diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 000000000..e69de29bb diff --git a/COPYING b/COPYING new file mode 100644 index 000000000..a43ea2126 --- /dev/null +++ b/COPYING @@ -0,0 +1,339 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 000000000..e69de29bb diff --git a/INSTALL b/INSTALL new file mode 100644 index 000000000..cbd1c80d2 --- /dev/null +++ b/INSTALL @@ -0,0 +1 @@ +/usr/share/automake-1.11/INSTALL \ No newline at end of file diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 000000000..f26892443 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS = src + diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 000000000..d680f1741 --- /dev/null +++ b/Makefile.in @@ -0,0 +1,670 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = . +DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in $(top_srcdir)/configure AUTHORS COPYING \ + ChangeLog INSTALL NEWS compile config.guess config.sub depcomp \ + install-sh missing +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno config.status.lineno +mkinstalldirs = $(install_sh) -d +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir dist dist-all distcheck +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + { test ! -d "$(distdir)" \ + || { find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr "$(distdir)"; }; } +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +distuninstallcheck_listfiles = find . -type f -print +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +ALLEGRO_CONFIG = @ALLEGRO_CONFIG@ +AMTAR = @AMTAR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EXEEXT = @EXEEXT@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +OBJEXT = @OBJEXT@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +VERSION = @VERSION@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +allegro_CFLAGS = @allegro_CFLAGS@ +allegro_LIBS = @allegro_LIBS@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +SUBDIRS = src +all: all-recursive + +.SUFFIXES: +am--refresh: + @: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --gnu'; \ + $(am__cd) $(srcdir) && $(AUTOMAKE) --gnu \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: $(am__configure_deps) + $(am__cd) $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +$(am__aclocal_m4_deps): + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + $(am__remove_distdir) + test -d "$(distdir)" || mkdir "$(distdir)" + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done + -test -n "$(am__skip_mode_fix)" \ + || find "$(distdir)" -type d ! -perm -755 \ + -exec chmod u+rwx,go+rx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r "$(distdir)" +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 + $(am__remove_distdir) + +dist-lzma: distdir + tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma + $(am__remove_distdir) + +dist-xz: distdir + tardir=$(distdir) && $(am__tar) | xz -c >$(distdir).tar.xz + $(am__remove_distdir) + +dist-tarZ: distdir + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__remove_distdir) + +dist-shar: distdir + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__remove_distdir) + +dist dist-all: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.lzma*) \ + lzma -dc $(distdir).tar.lzma | $(am__untar) ;;\ + *.tar.xz*) \ + xz -dc $(distdir).tar.xz | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/_build + mkdir $(distdir)/_inst + chmod a-w $(distdir) + test -d $(distdir)/_build || exit 0; \ + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && am__cwd=`pwd` \ + && $(am__cd) $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \ + && cd "$$am__cwd" \ + || exit 1 + $(am__remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x' +distuninstallcheck: + @$(am__cd) '$(distuninstallcheck_dir)' \ + && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-recursive + +clean-am: clean-generic mostlyclean-am + +distclean: distclean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am am--refresh check check-am clean clean-generic \ + ctags ctags-recursive dist dist-all dist-bzip2 dist-gzip \ + dist-lzma dist-shar dist-tarZ dist-xz dist-zip distcheck \ + distclean distclean-generic distclean-tags distcleancheck \ + distdir distuninstallcheck dvi dvi-am html html-am info \ + info-am install install-am install-data install-data-am \ + install-dvi install-dvi-am install-exec install-exec-am \ + install-html install-html-am install-info install-info-am \ + install-man install-pdf install-pdf-am install-ps \ + install-ps-am install-strip installcheck installcheck-am \ + installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic pdf \ + pdf-am ps ps-am tags tags-recursive uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/NEWS b/NEWS new file mode 100644 index 000000000..e69de29bb diff --git a/README b/README new file mode 100644 index 000000000..e69de29bb diff --git a/Readme-LINUX.txt b/Readme-LINUX.txt new file mode 100644 index 000000000..c52f741c8 --- /dev/null +++ b/Readme-LINUX.txt @@ -0,0 +1,31 @@ +PCem v8.1 Linux supplement + + +You will need the following libraries : + +Allegro 4.x +OpenAL +ALut + +and their dependencies. + +Open a terminal window, navigate to the PCem directory then enter + +./configure +make + +then ./pcem to run. + + +The Linux port is currently entirely unpolished, and mainly exists as a starting point for +anyone who wants to make a better port. + +The menu is not available all the time. Press CTRL-ALT-PGDN to open it. + +The mouse does not work very well, at least on my machine. This is most likely an Allegro issue. + +Fullscreen mode is not present. + +Video acceleration is not used at all, so performance is inferior to the Windows version. + +CD-ROM support currently only accesses /dev/cdrom. It has not been heavily tested. diff --git a/aclocal.m4 b/aclocal.m4 new file mode 100644 index 000000000..0b87a57fe --- /dev/null +++ b/aclocal.m4 @@ -0,0 +1,1179 @@ +# generated automatically by aclocal 1.11.1 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc. +# This file 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. + +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.65],, +[m4_warning([this file was generated for autoconf 2.65. +You have another version of autoconf. It may work, but is not guaranteed to. +If you have problems, you may need to regenerate the build system entirely. +To do so, use the procedure documented by the package, typically `autoreconf'.])]) + +# Configure paths for Allegro +# Shamelessly stolen from libxml.a4 +# Jon Rafkind 2004-06-06 +# Adapted from: +# Configure paths for libXML +# Toshio Kuratomi 2001-04-21 +# Adapted from: +# Configure paths for GLIB +# Owen Taylor 97-11-3 + +dnl AM_PATH_allegro([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND]]]) +dnl Test for allegro, and define allegro_CFLAGS and allegro_LIBS +dnl +AC_DEFUN([AM_PATH_ALLEGRO],[ +AC_ARG_WITH(allegro-prefix, + [ --with-allegro-prefix=PFX Prefix where liballegro is installed (optional)], + ALLEGRO_CONFIG_prefix="$withval", ALLEGRO_CONFIG_prefix="") +AC_ARG_WITH(allegro-exec-prefix, + [ --with-allegro-exec-prefix=PFX Exec prefix where liballegro is installed (optional)], + ALLEGRO_CONFIG_exec_prefix="$withval", ALLEGRO_CONFIG_exec_prefix="") +AC_ARG_ENABLE(allegrotest, + [ --disable-allegrotest Do not try to compile and run a test LIBallegro program],, + enable_allegrotest=yes) + + if test x$ALLEGRO_CONFIG_exec_prefix != x ; then + ALLEGRO_CONFIG_args="$ALLEGRO_CONFIG_args --exec-prefix=$ALLEGRO_CONFIG_exec_prefix" + if test x${ALLEGRO_CONFIG+set} != xset ; then + ALLEGRO_CONFIG=$ALLEGRO_CONFIG_exec_prefix/bin/allegro-config + fi + fi + if test x$ALLEGRO_CONFIG_prefix != x ; then + ALLEGRO_CONFIG_args="$ALLEGRO_CONFIG_args --prefix=$ALLEGRO_CONFIG_prefix" + if test x${ALLEGRO_CONFIG+set} != xset ; then + ALLEGRO_CONFIG=$ALLEGRO_CONFIG_prefix/bin/allegro-config + fi + fi + + AC_PATH_PROG(ALLEGRO_CONFIG, allegro-config, no) + min_allegro_version=ifelse([$1], ,4.0.0,[$1]) + AC_MSG_CHECKING(for Allegro - version >= $min_allegro_version) + no_allegro="" + if test "$ALLEGRO_CONFIG" = "no" ; then + no_allegro=yes + else + allegro_CFLAGS=`$ALLEGRO_CONFIG $ALLEGRO_CONFIG_args --cflags` + allegro_LIBS=`$ALLEGRO_CONFIG $ALLEGRO_CONFIG_args --libs` + ALLEGRO_CONFIG_major_version=`$ALLEGRO_CONFIG $ALLEGRO_CONFIG_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` + ALLEGRO_CONFIG_minor_version=`$ALLEGRO_CONFIG $ALLEGRO_CONFIG_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` + ALLEGRO_CONFIG_micro_version=`$ALLEGRO_CONFIG $ALLEGRO_CONFIG_args --version | \ + sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` + if test "x$enable_allegrotest" = "xyes" ; then + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $allegro_CFLAGS" + LIBS="$allegro_LIBS $LIBS" +dnl +dnl Now check if the installed liballegro is sufficiently new. +dnl (Also sanity checks the results of allegro-config to some extent) +dnl + rm -f conf.allegrotest + AC_TRY_RUN([ +#include +#include +#include +#include + +int +main() +{ + int allegro_major_version, allegro_minor_version, allegro_micro_version; + int major, minor, micro; + char *tmp_version; + int tmp_int_version; + + system("touch conf.allegrotest"); + + /* Capture allegro-config output via autoconf/configure variables */ + /* HP/UX 9 (%@#!) writes to sscanf strings */ + tmp_version = (char *)strdup("$min_allegro_version"); + if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { + printf("%s, bad version string from allegro-config\n", "$min_allegro_version"); + free(tmp_version); + exit(1); + } + free(tmp_version); + + /* Capture the version information from the header files */ + allegro_major_version = ALLEGRO_VERSION; + allegro_minor_version = ALLEGRO_SUB_VERSION; + allegro_micro_version = ALLEGRO_WIP_VERSION; + + /* Compare allegro-config output to the Allegro headers */ + if ((allegro_major_version != $ALLEGRO_CONFIG_major_version) || + (allegro_minor_version != $ALLEGRO_CONFIG_minor_version)) + + { + printf("*** Allegro header files (version %d.%d.%d) do not match\n", + allegro_major_version, allegro_minor_version, allegro_micro_version); + printf("*** allegro-config (version %d.%d.%d)\n", + $ALLEGRO_CONFIG_major_version, $ALLEGRO_CONFIG_minor_version, $ALLEGRO_CONFIG_micro_version); + return 1; + } +/* Compare the headers to the library to make sure we match */ + /* Less than ideal -- doesn't provide us with return value feedback, + * only exits if there's a serious mismatch between header and library. + */ + /* TODO: + * This doesnt work! + */ + /* ALLEGRO_TEST_VERSION; */ + + /* Test that the library is greater than our minimum version */ + if (($ALLEGRO_CONFIG_major_version > major) || + (($ALLEGRO_CONFIG_major_version == major) && ($ALLEGRO_CONFIG_minor_version > minor)) || + (($ALLEGRO_CONFIG_major_version == major) && ($ALLEGRO_CONFIG_minor_version == minor) && + ($ALLEGRO_CONFIG_micro_version >= micro))) + { + return 0; + } + else + { + printf("\n*** An old version of Allegro (%d.%d.%d) was found.\n", + allegro_major_version, allegro_minor_version, allegro_micro_version); + printf("*** You need a version of Allegro newer than %d.%d.%d. The latest version of\n", + major, minor, micro); + printf("*** Allegro is always available from http://alleg.sf.net.\n"); + printf("***\n"); + printf("*** If you have already installed a sufficiently new version, this error\n"); + printf("*** probably means that the wrong copy of the allegro-config shell script is\n"); + printf("*** being found. The easiest way to fix this is to remove the old version\n"); + printf("*** of Allegro, but you can also set the ALLEGRO_CONFIG environment to point to the\n"); + printf("*** correct copy of allegro-config. (In this case, you will have to\n"); + printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); + printf("*** so that the correct libraries are found at run-time))\n"); + } + return 1; +} END_OF_MAIN() +],, no_allegro=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + + if test "x$no_allegro" = x ; then + AC_MSG_RESULT(yes (version $ALLEGRO_CONFIG_major_version.$ALLEGRO_CONFIG_minor_version.$ALLEGRO_CONFIG_micro_version)) + ifelse([$2], , :, [$2]) + else + AC_MSG_RESULT(no) + if test "$ALLEGRO_CONFIG" = "no" ; then + echo "*** The allegro-config script installed by Allegro could not be found" + echo "*** If Allegro was installed in PREFIX, make sure PREFIX/bin is in" + echo "*** your path, or set the ALLEGRO_CONFIG environment variable to the" + echo "*** full path to allegro-config." + else + if test -f conf.allegrotest ; then + : + else + echo "*** Could not run Allegro test program, checking why..." + CFLAGS="$CFLAGS $allegro_CFLAGS" + LIBS="$LIBS $allegro_LIBS" + AC_TRY_LINK([ +#include +#include +], [ ALLEGRO_TEST_VERSION; return 0;], + [ echo "*** The test program compiled, but did not run. This usually means" + echo "*** that the run-time linker is not finding Allegro or finding the wrong" + echo "*** version of Allegro. If it is not finding Allegro, you'll need to set your" + echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" + echo "*** to the installed location Also, make sure you have run ldconfig if that" + echo "*** is required on your system" + echo "***" + echo "*** If you have an old version installed, it is best to remove it, although" + echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" ], + [ echo "*** The test program failed to compile or link. See the file config.log for the" + echo "*** exact error that occured. This usually means Allegro was incorrectly installed" + echo "*** or that you have moved Allegro since it was installed. In the latter case, you" + echo "*** may want to edit the allegro-config script: $ALLEGRO_CONFIG" ]) + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + + allegro_CFLAGS="" + allegro_LIBS="" + ifelse([$3], , :, [$3]) + fi + AC_SUBST(allegro_CFLAGS) + AC_SUBST(allegro_LIBS) + rm -f conf.allegrotest +]) + +# Copyright (C) 2002, 2003, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. +# +# This file 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. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +# (This private macro should not be called outside this file.) +AC_DEFUN([AM_AUTOMAKE_VERSION], +[am__api_version='1.11' +dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to +dnl require some minimum version. Point them to the right macro. +m4_if([$1], [1.11.1], [], + [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl +]) + +# _AM_AUTOCONF_VERSION(VERSION) +# ----------------------------- +# aclocal traces this macro to find the Autoconf version. +# This is a private macro too. Using m4_define simplifies +# the logic in aclocal, which can simply ignore this definition. +m4_define([_AM_AUTOCONF_VERSION], []) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced. +# This function is AC_REQUIREd by AM_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], +[AM_AUTOMAKE_VERSION([1.11.1])dnl +m4_ifndef([AC_AUTOCONF_VERSION], + [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl +_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file 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. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005, 2006, 2008 +# Free Software Foundation, Inc. +# +# This file 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. + +# serial 9 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE])dnl +AC_SUBST([$1_FALSE])dnl +_AM_SUBST_NOTMAKE([$1_TRUE])dnl +_AM_SUBST_NOTMAKE([$1_FALSE])dnl +m4_define([_AM_COND_VALUE_$1], [$2])dnl +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2009 +# Free Software Foundation, Inc. +# +# This file 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. + +# serial 10 + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], UPC, [depcc="$UPC" am_compiler_list=], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + am__universal=false + m4_case([$1], [CC], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac], + [CXX], + [case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac]) + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH])dnl +_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file 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. + +#serial 5 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[{ + # Autoconf 2.62 quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005, 2006, 2008, 2009 Free Software Foundation, Inc. +# +# This file 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. + +# serial 16 + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.62])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl +dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT. +m4_if(m4_ifdef([AC_PACKAGE_NAME], 1)m4_ifdef([AC_PACKAGE_VERSION], 1), 11,, + [m4_fatal([AC_INIT should be called with package and version arguments])])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_OBJC], + [_AM_DEPENDENCIES(OBJC)], + [define([AC_PROG_OBJC], + defn([AC_PROG_OBJC])[_AM_DEPENDENCIES(OBJC)])])dnl +]) +_AM_IF_OPTION([silent-rules], [AC_REQUIRE([AM_SILENT_RULES])])dnl +dnl The `parallel-tests' driver may need to know about EXEEXT, so add the +dnl `am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This macro +dnl is hooked onto _AC_COMPILER_EXEEXT early, see below. +AC_CONFIG_COMMANDS_PRE(dnl +[m4_provide_if([_AM_COMPILER_EXEEXT], + [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl +]) + +dnl Hook into `_AC_COMPILER_EXEEXT' early to learn its expansion. Do not +dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further +dnl mangled by Autoconf and run in a shell conditional statement. +m4_define([_AC_COMPILER_EXEEXT], +m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_arg=$1 +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $_am_arg | $_am_arg:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001, 2003, 2005, 2008 Free Software Foundation, Inc. +# +# This file 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. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi +AC_SUBST(install_sh)]) + +# Copyright (C) 2003, 2005 Free Software Foundation, Inc. +# +# This file 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. + +# serial 2 + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005, 2009 Free Software Foundation, Inc. +# +# This file 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. + +# serial 4 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from `make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Copyright (C) 1999, 2000, 2001, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file 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. + +# serial 6 + +# AM_PROG_CC_C_O +# -------------- +# Like AC_PROG_CC_C_O, but changed for automake. +AC_DEFUN([AM_PROG_CC_C_O], +[AC_REQUIRE([AC_PROG_CC_C_O])dnl +AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([compile])dnl +# FIXME: we rely on the cache variable name because +# there is no other way. +set dummy $CC +am_cc=`echo $[2] | sed ['s/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/']` +eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o +if test "$am_t" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi +dnl Make sure AC_PROG_CC is never called again, or it will override our +dnl setting of CC. +m4_define([AC_PROG_CC], + [m4_fatal([AC_PROG_CC cannot be called after AM_PROG_CC_C_O])]) +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2004, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file 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. + +# serial 6 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +AC_REQUIRE_AUX_FILE([missing])dnl +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# Copyright (C) 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# +# This file 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. + +# AM_PROG_MKDIR_P +# --------------- +# Check for `mkdir -p'. +AC_DEFUN([AM_PROG_MKDIR_P], +[AC_PREREQ([2.60])dnl +AC_REQUIRE([AC_PROG_MKDIR_P])dnl +dnl Automake 1.8 to 1.9.6 used to define mkdir_p. We now use MKDIR_P, +dnl while keeping a definition of mkdir_p for backward compatibility. +dnl @MKDIR_P@ is magic: AC_OUTPUT adjusts its value for each Makefile. +dnl However we cannot define mkdir_p as $(MKDIR_P) for the sake of +dnl Makefile.ins that do not define MKDIR_P, so we do our own +dnl adjustment using top_builddir (which is defined more often than +dnl MKDIR_P). +AC_SUBST([mkdir_p], ["$MKDIR_P"])dnl +case $mkdir_p in + [[\\/$]]* | ?:[[\\/]]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac +]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005, 2008 Free Software Foundation, Inc. +# +# This file 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. + +# serial 4 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008 +# Free Software Foundation, Inc. +# +# This file 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. + +# serial 5 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[[\\\"\#\$\&\'\`$am_lf]]*) + AC_MSG_ERROR([unsafe absolute working directory name]);; +esac +case $srcdir in + *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*) + AC_MSG_ERROR([unsafe srcdir value: `$srcdir']);; +esac + +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file 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. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Copyright (C) 2006, 2008 Free Software Foundation, Inc. +# +# This file 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. + +# serial 2 + +# _AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in. +# This macro is traced by Automake. +AC_DEFUN([_AM_SUBST_NOTMAKE]) + +# AM_SUBST_NOTMAKE(VARIABLE) +# --------------------------- +# Public sister of _AM_SUBST_NOTMAKE. +AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004, 2005 Free Software Foundation, Inc. +# +# This file 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. + +# serial 2 + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of `v7', `ustar', or `pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. +AM_MISSING_PROG([AMTAR], [tar]) +m4_if([$1], [v7], + [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) +AC_MSG_RESULT([$am_cv_prog_tar_$1])]) +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + diff --git a/compile b/compile new file mode 100644 index 000000000..cf0edba28 --- /dev/null +++ b/compile @@ -0,0 +1 @@ +/usr/share/automake-1.11/compile \ No newline at end of file diff --git a/config.guess b/config.guess new file mode 100644 index 000000000..e3a2116a7 --- /dev/null +++ b/config.guess @@ -0,0 +1,1533 @@ +#! /bin/sh +# Attempt to guess a canonical system name. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 +# Free Software Foundation, Inc. + +timestamp='2009-06-10' + +# This file is free software; you can redistribute it and/or modify it +# under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Originally written by Per Bothner . +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# This script attempts to guess a canonical system name similar to +# config.sub. If it succeeds, it prints the system name on stdout, and +# exits with 0. Otherwise, it exits with 1. +# +# The plan is that this can be called by configure scripts if you +# don't specify an explicit build system type. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] + +Output the configuration name of the system \`$me' is run on. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.guess ($timestamp) + +Originally written by Per Bothner. +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" >&2 + exit 1 ;; + * ) + break ;; + esac +done + +if test $# != 0; then + echo "$me: too many arguments$help" >&2 + exit 1 +fi + +trap 'exit 1' 1 2 15 + +# CC_FOR_BUILD -- compiler used by this script. Note that the use of a +# compiler to aid in system detection is discouraged as it requires +# temporary files to be created and, as you can see below, it is a +# headache to deal with in a portable fashion. + +# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still +# use `HOST_CC' if defined, but it is deprecated. + +# Portable tmp directory creation inspired by the Autoconf team. + +set_cc_for_build=' +trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; +trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; +: ${TMPDIR=/tmp} ; + { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || + { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || + { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || + { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; +dummy=$tmp/dummy ; +tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; +case $CC_FOR_BUILD,$HOST_CC,$CC in + ,,) echo "int x;" > $dummy.c ; + for c in cc gcc c89 c99 ; do + if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then + CC_FOR_BUILD="$c"; break ; + fi ; + done ; + if test x"$CC_FOR_BUILD" = x ; then + CC_FOR_BUILD=no_compiler_found ; + fi + ;; + ,,*) CC_FOR_BUILD=$CC ;; + ,*,*) CC_FOR_BUILD=$HOST_CC ;; +esac ; set_cc_for_build= ;' + +# This is needed to find uname on a Pyramid OSx when run in the BSD universe. +# (ghazi@noc.rutgers.edu 1994-08-24) +if (test -f /.attbin/uname) >/dev/null 2>&1 ; then + PATH=$PATH:/.attbin ; export PATH +fi + +UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown +UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown +UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown +UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown + +# Note: order is significant - the case branches are not exclusive. + +case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in + *:NetBSD:*:*) + # NetBSD (nbsd) targets should (where applicable) match one or + # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, + # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently + # switched to ELF, *-*-netbsd* would select the old + # object file format. This provides both forward + # compatibility and a consistent mechanism for selecting the + # object file format. + # + # Note: NetBSD doesn't particularly care about the vendor + # portion of the name. We always set it to "unknown". + sysctl="sysctl -n hw.machine_arch" + UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ + /usr/sbin/$sysctl 2>/dev/null || echo unknown)` + case "${UNAME_MACHINE_ARCH}" in + armeb) machine=armeb-unknown ;; + arm*) machine=arm-unknown ;; + sh3el) machine=shl-unknown ;; + sh3eb) machine=sh-unknown ;; + sh5el) machine=sh5le-unknown ;; + *) machine=${UNAME_MACHINE_ARCH}-unknown ;; + esac + # The Operating System including object format, if it has switched + # to ELF recently, or will in the future. + case "${UNAME_MACHINE_ARCH}" in + arm*|i386|m68k|ns32k|sh3*|sparc|vax) + eval $set_cc_for_build + if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ELF__ + then + # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). + # Return netbsd for either. FIX? + os=netbsd + else + os=netbsdelf + fi + ;; + *) + os=netbsd + ;; + esac + # The OS release + # Debian GNU/NetBSD machines have a different userland, and + # thus, need a distinct triplet. However, they do not need + # kernel version information, so it can be replaced with a + # suitable tag, in the style of linux-gnu. + case "${UNAME_VERSION}" in + Debian*) + release='-gnu' + ;; + *) + release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` + ;; + esac + # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: + # contains redundant information, the shorter form: + # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. + echo "${machine}-${os}${release}" + exit ;; + *:OpenBSD:*:*) + UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` + echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} + exit ;; + *:ekkoBSD:*:*) + echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} + exit ;; + *:SolidBSD:*:*) + echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} + exit ;; + macppc:MirBSD:*:*) + echo powerpc-unknown-mirbsd${UNAME_RELEASE} + exit ;; + *:MirBSD:*:*) + echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} + exit ;; + alpha:OSF1:*:*) + case $UNAME_RELEASE in + *4.0) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` + ;; + *5.*) + UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` + ;; + esac + # According to Compaq, /usr/sbin/psrinfo has been available on + # OSF/1 and Tru64 systems produced since 1995. I hope that + # covers most systems running today. This code pipes the CPU + # types through head -n 1, so we only detect the type of CPU 0. + ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` + case "$ALPHA_CPU_TYPE" in + "EV4 (21064)") + UNAME_MACHINE="alpha" ;; + "EV4.5 (21064)") + UNAME_MACHINE="alpha" ;; + "LCA4 (21066/21068)") + UNAME_MACHINE="alpha" ;; + "EV5 (21164)") + UNAME_MACHINE="alphaev5" ;; + "EV5.6 (21164A)") + UNAME_MACHINE="alphaev56" ;; + "EV5.6 (21164PC)") + UNAME_MACHINE="alphapca56" ;; + "EV5.7 (21164PC)") + UNAME_MACHINE="alphapca57" ;; + "EV6 (21264)") + UNAME_MACHINE="alphaev6" ;; + "EV6.7 (21264A)") + UNAME_MACHINE="alphaev67" ;; + "EV6.8CB (21264C)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8AL (21264B)") + UNAME_MACHINE="alphaev68" ;; + "EV6.8CX (21264D)") + UNAME_MACHINE="alphaev68" ;; + "EV6.9A (21264/EV69A)") + UNAME_MACHINE="alphaev69" ;; + "EV7 (21364)") + UNAME_MACHINE="alphaev7" ;; + "EV7.9 (21364A)") + UNAME_MACHINE="alphaev79" ;; + esac + # A Pn.n version is a patched version. + # A Vn.n version is a released version. + # A Tn.n version is a released field test version. + # A Xn.n version is an unreleased experimental baselevel. + # 1.2 uses "1.2" for uname -r. + echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + exit ;; + Alpha\ *:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # Should we change UNAME_MACHINE based on the output of uname instead + # of the specific Alpha model? + echo alpha-pc-interix + exit ;; + 21064:Windows_NT:50:3) + echo alpha-dec-winnt3.5 + exit ;; + Amiga*:UNIX_System_V:4.0:*) + echo m68k-unknown-sysv4 + exit ;; + *:[Aa]miga[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-amigaos + exit ;; + *:[Mm]orph[Oo][Ss]:*:*) + echo ${UNAME_MACHINE}-unknown-morphos + exit ;; + *:OS/390:*:*) + echo i370-ibm-openedition + exit ;; + *:z/VM:*:*) + echo s390-ibm-zvmoe + exit ;; + *:OS400:*:*) + echo powerpc-ibm-os400 + exit ;; + arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) + echo arm-acorn-riscix${UNAME_RELEASE} + exit ;; + arm:riscos:*:*|arm:RISCOS:*:*) + echo arm-unknown-riscos + exit ;; + SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) + echo hppa1.1-hitachi-hiuxmpp + exit ;; + Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) + # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. + if test "`(/bin/universe) 2>/dev/null`" = att ; then + echo pyramid-pyramid-sysv3 + else + echo pyramid-pyramid-bsd + fi + exit ;; + NILE*:*:*:dcosx) + echo pyramid-pyramid-svr4 + exit ;; + DRS?6000:unix:4.0:6*) + echo sparc-icl-nx6 + exit ;; + DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) + case `/usr/bin/uname -p` in + sparc) echo sparc-icl-nx7; exit ;; + esac ;; + s390x:SunOS:*:*) + echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4H:SunOS:5.*:*) + echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) + echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*) + eval $set_cc_for_build + SUN_ARCH="i386" + # If there is a compiler, see if it is configured for 64-bit objects. + # Note that the Sun cc does not turn __LP64__ into 1 like gcc does. + # This test works for both compilers. + if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then + if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \ + (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \ + grep IS_64BIT_ARCH >/dev/null + then + SUN_ARCH="x86_64" + fi + fi + echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:6*:*) + # According to config.sub, this is the proper way to canonicalize + # SunOS6. Hard to guess exactly what SunOS6 will be like, but + # it's likely to be more like Solaris than SunOS4. + echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + sun4*:SunOS:*:*) + case "`/usr/bin/arch -k`" in + Series*|S4*) + UNAME_RELEASE=`uname -v` + ;; + esac + # Japanese Language versions have a version number like `4.1.3-JL'. + echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'` + exit ;; + sun3*:SunOS:*:*) + echo m68k-sun-sunos${UNAME_RELEASE} + exit ;; + sun*:*:4.2BSD:*) + UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` + test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 + case "`/bin/arch`" in + sun3) + echo m68k-sun-sunos${UNAME_RELEASE} + ;; + sun4) + echo sparc-sun-sunos${UNAME_RELEASE} + ;; + esac + exit ;; + aushp:SunOS:*:*) + echo sparc-auspex-sunos${UNAME_RELEASE} + exit ;; + # The situation for MiNT is a little confusing. The machine name + # can be virtually everything (everything which is not + # "atarist" or "atariste" at least should have a processor + # > m68000). The system name ranges from "MiNT" over "FreeMiNT" + # to the lowercase version "mint" (or "freemint"). Finally + # the system name "TOS" denotes a system which is actually not + # MiNT. But MiNT is downward compatible to TOS, so this should + # be no problem. + atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) + echo m68k-atari-mint${UNAME_RELEASE} + exit ;; + milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) + echo m68k-milan-mint${UNAME_RELEASE} + exit ;; + hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) + echo m68k-hades-mint${UNAME_RELEASE} + exit ;; + *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) + echo m68k-unknown-mint${UNAME_RELEASE} + exit ;; + m68k:machten:*:*) + echo m68k-apple-machten${UNAME_RELEASE} + exit ;; + powerpc:machten:*:*) + echo powerpc-apple-machten${UNAME_RELEASE} + exit ;; + RISC*:Mach:*:*) + echo mips-dec-mach_bsd4.3 + exit ;; + RISC*:ULTRIX:*:*) + echo mips-dec-ultrix${UNAME_RELEASE} + exit ;; + VAX*:ULTRIX*:*:*) + echo vax-dec-ultrix${UNAME_RELEASE} + exit ;; + 2020:CLIX:*:* | 2430:CLIX:*:*) + echo clipper-intergraph-clix${UNAME_RELEASE} + exit ;; + mips:*:*:UMIPS | mips:*:*:RISCos) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c +#ifdef __cplusplus +#include /* for printf() prototype */ + int main (int argc, char *argv[]) { +#else + int main (argc, argv) int argc; char *argv[]; { +#endif + #if defined (host_mips) && defined (MIPSEB) + #if defined (SYSTYPE_SYSV) + printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_SVR4) + printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); + #endif + #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) + printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); + #endif + #endif + exit (-1); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && + dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && + SYSTEM_NAME=`$dummy $dummyarg` && + { echo "$SYSTEM_NAME"; exit; } + echo mips-mips-riscos${UNAME_RELEASE} + exit ;; + Motorola:PowerMAX_OS:*:*) + echo powerpc-motorola-powermax + exit ;; + Motorola:*:4.3:PL8-*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) + echo powerpc-harris-powermax + exit ;; + Night_Hawk:Power_UNIX:*:*) + echo powerpc-harris-powerunix + exit ;; + m88k:CX/UX:7*:*) + echo m88k-harris-cxux7 + exit ;; + m88k:*:4*:R4*) + echo m88k-motorola-sysv4 + exit ;; + m88k:*:3*:R3*) + echo m88k-motorola-sysv3 + exit ;; + AViiON:dgux:*:*) + # DG/UX returns AViiON for all architectures + UNAME_PROCESSOR=`/usr/bin/uname -p` + if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] + then + if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ + [ ${TARGET_BINARY_INTERFACE}x = x ] + then + echo m88k-dg-dgux${UNAME_RELEASE} + else + echo m88k-dg-dguxbcs${UNAME_RELEASE} + fi + else + echo i586-dg-dgux${UNAME_RELEASE} + fi + exit ;; + M88*:DolphinOS:*:*) # DolphinOS (SVR3) + echo m88k-dolphin-sysv3 + exit ;; + M88*:*:R3*:*) + # Delta 88k system running SVR3 + echo m88k-motorola-sysv3 + exit ;; + XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) + echo m88k-tektronix-sysv3 + exit ;; + Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) + echo m68k-tektronix-bsd + exit ;; + *:IRIX*:*:*) + echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` + exit ;; + ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX. + echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id + exit ;; # Note that: echo "'`uname -s`'" gives 'AIX ' + i*86:AIX:*:*) + echo i386-ibm-aix + exit ;; + ia64:AIX:*:*) + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} + exit ;; + *:AIX:2:3) + if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + + main() + { + if (!__power_pc()) + exit(1); + puts("powerpc-ibm-aix3.2.5"); + exit(0); + } +EOF + if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` + then + echo "$SYSTEM_NAME" + else + echo rs6000-ibm-aix3.2.5 + fi + elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then + echo rs6000-ibm-aix3.2.4 + else + echo rs6000-ibm-aix3.2 + fi + exit ;; + *:AIX:*:[456]) + IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` + if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then + IBM_ARCH=rs6000 + else + IBM_ARCH=powerpc + fi + if [ -x /usr/bin/oslevel ] ; then + IBM_REV=`/usr/bin/oslevel` + else + IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} + fi + echo ${IBM_ARCH}-ibm-aix${IBM_REV} + exit ;; + *:AIX:*:*) + echo rs6000-ibm-aix + exit ;; + ibmrt:4.4BSD:*|romp-ibm:BSD:*) + echo romp-ibm-bsd4.4 + exit ;; + ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and + echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to + exit ;; # report: romp-ibm BSD 4.3 + *:BOSX:*:*) + echo rs6000-bull-bosx + exit ;; + DPX/2?00:B.O.S.:*:*) + echo m68k-bull-sysv3 + exit ;; + 9000/[34]??:4.3bsd:1.*:*) + echo m68k-hp-bsd + exit ;; + hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) + echo m68k-hp-bsd4.4 + exit ;; + 9000/[34678]??:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + case "${UNAME_MACHINE}" in + 9000/31? ) HP_ARCH=m68000 ;; + 9000/[34]?? ) HP_ARCH=m68k ;; + 9000/[678][0-9][0-9]) + if [ -x /usr/bin/getconf ]; then + sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` + sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` + case "${sc_cpu_version}" in + 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 + 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 + 532) # CPU_PA_RISC2_0 + case "${sc_kernel_bits}" in + 32) HP_ARCH="hppa2.0n" ;; + 64) HP_ARCH="hppa2.0w" ;; + '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 + esac ;; + esac + fi + if [ "${HP_ARCH}" = "" ]; then + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + + #define _HPUX_SOURCE + #include + #include + + int main () + { + #if defined(_SC_KERNEL_BITS) + long bits = sysconf(_SC_KERNEL_BITS); + #endif + long cpu = sysconf (_SC_CPU_VERSION); + + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1"); break; + case CPU_PA_RISC2_0: + #if defined(_SC_KERNEL_BITS) + switch (bits) + { + case 64: puts ("hppa2.0w"); break; + case 32: puts ("hppa2.0n"); break; + default: puts ("hppa2.0"); break; + } break; + #else /* !defined(_SC_KERNEL_BITS) */ + puts ("hppa2.0"); break; + #endif + default: puts ("hppa1.0"); break; + } + exit (0); + } +EOF + (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` + test -z "$HP_ARCH" && HP_ARCH=hppa + fi ;; + esac + if [ ${HP_ARCH} = "hppa2.0w" ] + then + eval $set_cc_for_build + + # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating + # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler + # generating 64-bit code. GNU and HP use different nomenclature: + # + # $ CC_FOR_BUILD=cc ./config.guess + # => hppa2.0w-hp-hpux11.23 + # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess + # => hppa64-hp-hpux11.23 + + if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | + grep -q __LP64__ + then + HP_ARCH="hppa2.0w" + else + HP_ARCH="hppa64" + fi + fi + echo ${HP_ARCH}-hp-hpux${HPUX_REV} + exit ;; + ia64:HP-UX:*:*) + HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` + echo ia64-hp-hpux${HPUX_REV} + exit ;; + 3050*:HI-UX:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + int + main () + { + long cpu = sysconf (_SC_CPU_VERSION); + /* The order matters, because CPU_IS_HP_MC68K erroneously returns + true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct + results, however. */ + if (CPU_IS_PA_RISC (cpu)) + { + switch (cpu) + { + case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break; + case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break; + case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break; + default: puts ("hppa-hitachi-hiuxwe2"); break; + } + } + else if (CPU_IS_HP_MC68K (cpu)) + puts ("m68k-hitachi-hiuxwe2"); + else puts ("unknown-hitachi-hiuxwe2"); + exit (0); + } +EOF + $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + echo unknown-hitachi-hiuxwe2 + exit ;; + 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) + echo hppa1.1-hp-bsd + exit ;; + 9000/8??:4.3bsd:*:*) + echo hppa1.0-hp-bsd + exit ;; + *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) + echo hppa1.0-hp-mpeix + exit ;; + hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) + echo hppa1.1-hp-osf + exit ;; + hp8??:OSF1:*:*) + echo hppa1.0-hp-osf + exit ;; + i*86:OSF1:*:*) + if [ -x /usr/sbin/sysversion ] ; then + echo ${UNAME_MACHINE}-unknown-osf1mk + else + echo ${UNAME_MACHINE}-unknown-osf1 + fi + exit ;; + parisc*:Lites*:*:*) + echo hppa1.1-hp-lites + exit ;; + C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) + echo c1-convex-bsd + exit ;; + C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) + echo c34-convex-bsd + exit ;; + C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) + echo c38-convex-bsd + exit ;; + C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) + echo c4-convex-bsd + exit ;; + CRAY*Y-MP:*:*:*) + echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*[A-Z]90:*:*:*) + echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ + | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ + -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ + -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*TS:*:*:*) + echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*T3E:*:*:*) + echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + CRAY*SV1:*:*:*) + echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + *:UNICOS/mp:*:*) + echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' + exit ;; + F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) + FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` + echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + 5000:UNIX_System_V:4.*:*) + FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` + FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` + echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" + exit ;; + i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) + echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} + exit ;; + sparc*:BSD/OS:*:*) + echo sparc-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:BSD/OS:*:*) + echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} + exit ;; + *:FreeBSD:*:*) + case ${UNAME_MACHINE} in + pc98) + echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + amd64) + echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + *) + echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; + esac + exit ;; + i*:CYGWIN*:*) + echo ${UNAME_MACHINE}-pc-cygwin + exit ;; + *:MINGW*:*) + echo ${UNAME_MACHINE}-pc-mingw32 + exit ;; + i*:windows32*:*) + # uname -m includes "-pc" on this system. + echo ${UNAME_MACHINE}-mingw32 + exit ;; + i*:PW*:*) + echo ${UNAME_MACHINE}-pc-pw32 + exit ;; + *:Interix*:[3456]*) + case ${UNAME_MACHINE} in + x86) + echo i586-pc-interix${UNAME_RELEASE} + exit ;; + EM64T | authenticamd | genuineintel) + echo x86_64-unknown-interix${UNAME_RELEASE} + exit ;; + IA64) + echo ia64-unknown-interix${UNAME_RELEASE} + exit ;; + esac ;; + [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) + echo i${UNAME_MACHINE}-pc-mks + exit ;; + 8664:Windows_NT:*) + echo x86_64-pc-mks + exit ;; + i*:Windows_NT*:* | Pentium*:Windows_NT*:*) + # How do we know it's Interix rather than the generic POSIX subsystem? + # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we + # UNAME_MACHINE based on the output of uname instead of i386? + echo i586-pc-interix + exit ;; + i*:UWIN*:*) + echo ${UNAME_MACHINE}-pc-uwin + exit ;; + amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) + echo x86_64-unknown-cygwin + exit ;; + p*:CYGWIN*:*) + echo powerpcle-unknown-cygwin + exit ;; + prep*:SunOS:5.*:*) + echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` + exit ;; + *:GNU:*:*) + # the GNU system + echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` + exit ;; + *:GNU/*:*:*) + # other systems with GNU libc and userland + echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu + exit ;; + i*86:Minix:*:*) + echo ${UNAME_MACHINE}-pc-minix + exit ;; + arm*:Linux:*:*) + eval $set_cc_for_build + if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \ + | grep -q __ARM_EABI__ + then + echo ${UNAME_MACHINE}-unknown-linux-gnu + else + echo ${UNAME_MACHINE}-unknown-linux-gnueabi + fi + exit ;; + avr32*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + cris:Linux:*:*) + echo cris-axis-linux-gnu + exit ;; + crisv32:Linux:*:*) + echo crisv32-axis-linux-gnu + exit ;; + frv:Linux:*:*) + echo frv-unknown-linux-gnu + exit ;; + ia64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m32r*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + m68*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + mips:Linux:*:* | mips64:Linux:*:*) + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #undef CPU + #undef ${UNAME_MACHINE} + #undef ${UNAME_MACHINE}el + #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) + CPU=${UNAME_MACHINE}el + #else + #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) + CPU=${UNAME_MACHINE} + #else + CPU= + #endif + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^CPU/{ + s: ::g + p + }'`" + test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } + ;; + or32:Linux:*:*) + echo or32-unknown-linux-gnu + exit ;; + ppc:Linux:*:*) + echo powerpc-unknown-linux-gnu + exit ;; + ppc64:Linux:*:*) + echo powerpc64-unknown-linux-gnu + exit ;; + alpha:Linux:*:*) + case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in + EV5) UNAME_MACHINE=alphaev5 ;; + EV56) UNAME_MACHINE=alphaev56 ;; + PCA56) UNAME_MACHINE=alphapca56 ;; + PCA57) UNAME_MACHINE=alphapca56 ;; + EV6) UNAME_MACHINE=alphaev6 ;; + EV67) UNAME_MACHINE=alphaev67 ;; + EV68*) UNAME_MACHINE=alphaev68 ;; + esac + objdump --private-headers /bin/sh | grep -q ld.so.1 + if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi + echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} + exit ;; + padre:Linux:*:*) + echo sparc-unknown-linux-gnu + exit ;; + parisc:Linux:*:* | hppa:Linux:*:*) + # Look for CPU level + case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in + PA7*) echo hppa1.1-unknown-linux-gnu ;; + PA8*) echo hppa2.0-unknown-linux-gnu ;; + *) echo hppa-unknown-linux-gnu ;; + esac + exit ;; + parisc64:Linux:*:* | hppa64:Linux:*:*) + echo hppa64-unknown-linux-gnu + exit ;; + s390:Linux:*:* | s390x:Linux:*:*) + echo ${UNAME_MACHINE}-ibm-linux + exit ;; + sh64*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sh*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + sparc:Linux:*:* | sparc64:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + vax:Linux:*:*) + echo ${UNAME_MACHINE}-dec-linux-gnu + exit ;; + x86_64:Linux:*:*) + echo x86_64-unknown-linux-gnu + exit ;; + xtensa*:Linux:*:*) + echo ${UNAME_MACHINE}-unknown-linux-gnu + exit ;; + i*86:Linux:*:*) + # The BFD linker knows what the default object file format is, so + # first see if it will tell us. cd to the root directory to prevent + # problems with other programs or directories called `ld' in the path. + # Set LC_ALL=C to ensure ld outputs messages in English. + ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ + | sed -ne '/supported targets:/!d + s/[ ][ ]*/ /g + s/.*supported targets: *// + s/ .*// + p'` + case "$ld_supported_targets" in + elf32-i386) + TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" + ;; + esac + # Determine whether the default compiler is a.out or elf + eval $set_cc_for_build + sed 's/^ //' << EOF >$dummy.c + #include + #ifdef __ELF__ + # ifdef __GLIBC__ + # if __GLIBC__ >= 2 + LIBC=gnu + # else + LIBC=gnulibc1 + # endif + # else + LIBC=gnulibc1 + # endif + #else + #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) + LIBC=gnu + #else + LIBC=gnuaout + #endif + #endif + #ifdef __dietlibc__ + LIBC=dietlibc + #endif +EOF + eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' + /^LIBC/{ + s: ::g + p + }'`" + test x"${LIBC}" != x && { + echo "${UNAME_MACHINE}-pc-linux-${LIBC}" + exit + } + test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } + ;; + i*86:DYNIX/ptx:4*:*) + # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. + # earlier versions are messed up and put the nodename in both + # sysname and nodename. + echo i386-sequent-sysv4 + exit ;; + i*86:UNIX_SV:4.2MP:2.*) + # Unixware is an offshoot of SVR4, but it has its own version + # number series starting with 2... + # I am not positive that other SVR4 systems won't match this, + # I just have to hope. -- rms. + # Use sysv4.2uw... so that sysv4* matches it. + echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} + exit ;; + i*86:OS/2:*:*) + # If we were able to find `uname', then EMX Unix compatibility + # is probably installed. + echo ${UNAME_MACHINE}-pc-os2-emx + exit ;; + i*86:XTS-300:*:STOP) + echo ${UNAME_MACHINE}-unknown-stop + exit ;; + i*86:atheos:*:*) + echo ${UNAME_MACHINE}-unknown-atheos + exit ;; + i*86:syllable:*:*) + echo ${UNAME_MACHINE}-pc-syllable + exit ;; + i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*) + echo i386-unknown-lynxos${UNAME_RELEASE} + exit ;; + i*86:*DOS:*:*) + echo ${UNAME_MACHINE}-pc-msdosdjgpp + exit ;; + i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) + UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` + if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then + echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} + else + echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} + fi + exit ;; + i*86:*:5:[678]*) + # UnixWare 7.x, OpenUNIX and OpenServer 6. + case `/bin/uname -X | grep "^Machine"` in + *486*) UNAME_MACHINE=i486 ;; + *Pentium) UNAME_MACHINE=i586 ;; + *Pent*|*Celeron) UNAME_MACHINE=i686 ;; + esac + echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} + exit ;; + i*86:*:3.2:*) + if test -f /usr/options/cb.name; then + UNAME_REL=`sed -n 's/.*Version //p' /dev/null >/dev/null ; then + UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')` + (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 + (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ + && UNAME_MACHINE=i586 + (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ + && UNAME_MACHINE=i686 + (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ + && UNAME_MACHINE=i686 + echo ${UNAME_MACHINE}-pc-sco$UNAME_REL + else + echo ${UNAME_MACHINE}-pc-sysv32 + fi + exit ;; + pc:*:*:*) + # Left here for compatibility: + # uname -m prints for DJGPP always 'pc', but it prints nothing about + # the processor, so we play safe by assuming i586. + # Note: whatever this is, it MUST be the same as what config.sub + # prints for the "djgpp" host, or else GDB configury will decide that + # this is a cross-build. + echo i586-pc-msdosdjgpp + exit ;; + Intel:Mach:3*:*) + echo i386-pc-mach3 + exit ;; + paragon:*:*:*) + echo i860-intel-osf1 + exit ;; + i860:*:4.*:*) # i860-SVR4 + if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then + echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4 + else # Add other i860-SVR4 vendors below as they are discovered. + echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4 + fi + exit ;; + mini*:CTIX:SYS*5:*) + # "miniframe" + echo m68010-convergent-sysv + exit ;; + mc68k:UNIX:SYSTEM5:3.51m) + echo m68k-convergent-sysv + exit ;; + M680?0:D-NIX:5.3:*) + echo m68k-diab-dnix + exit ;; + M68*:*:R3V[5678]*:*) + test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; + 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) + OS_REL='' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4; exit; } ;; + NCR*:*:4.2:* | MPRAS*:*:4.2:*) + OS_REL='.3' + test -r /etc/.relid \ + && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` + /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ + && { echo i486-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } + /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \ + && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; + m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) + echo m68k-unknown-lynxos${UNAME_RELEASE} + exit ;; + mc68030:UNIX_System_V:4.*:*) + echo m68k-atari-sysv4 + exit ;; + TSUNAMI:LynxOS:2.*:*) + echo sparc-unknown-lynxos${UNAME_RELEASE} + exit ;; + rs6000:LynxOS:2.*:*) + echo rs6000-unknown-lynxos${UNAME_RELEASE} + exit ;; + PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*) + echo powerpc-unknown-lynxos${UNAME_RELEASE} + exit ;; + SM[BE]S:UNIX_SV:*:*) + echo mips-dde-sysv${UNAME_RELEASE} + exit ;; + RM*:ReliantUNIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + RM*:SINIX-*:*:*) + echo mips-sni-sysv4 + exit ;; + *:SINIX-*:*:*) + if uname -p 2>/dev/null >/dev/null ; then + UNAME_MACHINE=`(uname -p) 2>/dev/null` + echo ${UNAME_MACHINE}-sni-sysv4 + else + echo ns32k-sni-sysv + fi + exit ;; + PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort + # says + echo i586-unisys-sysv4 + exit ;; + *:UNIX_System_V:4*:FTX*) + # From Gerald Hewes . + # How about differentiating between stratus architectures? -djm + echo hppa1.1-stratus-sysv4 + exit ;; + *:*:*:FTX*) + # From seanf@swdc.stratus.com. + echo i860-stratus-sysv4 + exit ;; + i*86:VOS:*:*) + # From Paul.Green@stratus.com. + echo ${UNAME_MACHINE}-stratus-vos + exit ;; + *:VOS:*:*) + # From Paul.Green@stratus.com. + echo hppa1.1-stratus-vos + exit ;; + mc68*:A/UX:*:*) + echo m68k-apple-aux${UNAME_RELEASE} + exit ;; + news*:NEWS-OS:6*:*) + echo mips-sony-newsos6 + exit ;; + R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) + if [ -d /usr/nec ]; then + echo mips-nec-sysv${UNAME_RELEASE} + else + echo mips-unknown-sysv${UNAME_RELEASE} + fi + exit ;; + BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. + echo powerpc-be-beos + exit ;; + BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. + echo powerpc-apple-beos + exit ;; + BePC:BeOS:*:*) # BeOS running on Intel PC compatible. + echo i586-pc-beos + exit ;; + BePC:Haiku:*:*) # Haiku running on Intel PC compatible. + echo i586-pc-haiku + exit ;; + SX-4:SUPER-UX:*:*) + echo sx4-nec-superux${UNAME_RELEASE} + exit ;; + SX-5:SUPER-UX:*:*) + echo sx5-nec-superux${UNAME_RELEASE} + exit ;; + SX-6:SUPER-UX:*:*) + echo sx6-nec-superux${UNAME_RELEASE} + exit ;; + SX-7:SUPER-UX:*:*) + echo sx7-nec-superux${UNAME_RELEASE} + exit ;; + SX-8:SUPER-UX:*:*) + echo sx8-nec-superux${UNAME_RELEASE} + exit ;; + SX-8R:SUPER-UX:*:*) + echo sx8r-nec-superux${UNAME_RELEASE} + exit ;; + Power*:Rhapsody:*:*) + echo powerpc-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Rhapsody:*:*) + echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} + exit ;; + *:Darwin:*:*) + UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown + case $UNAME_PROCESSOR in + unknown) UNAME_PROCESSOR=powerpc ;; + esac + echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} + exit ;; + *:procnto*:*:* | *:QNX:[0123456789]*:*) + UNAME_PROCESSOR=`uname -p` + if test "$UNAME_PROCESSOR" = "x86"; then + UNAME_PROCESSOR=i386 + UNAME_MACHINE=pc + fi + echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} + exit ;; + *:QNX:*:4*) + echo i386-pc-qnx + exit ;; + NSE-?:NONSTOP_KERNEL:*:*) + echo nse-tandem-nsk${UNAME_RELEASE} + exit ;; + NSR-?:NONSTOP_KERNEL:*:*) + echo nsr-tandem-nsk${UNAME_RELEASE} + exit ;; + *:NonStop-UX:*:*) + echo mips-compaq-nonstopux + exit ;; + BS2000:POSIX*:*:*) + echo bs2000-siemens-sysv + exit ;; + DS/*:UNIX_System_V:*:*) + echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} + exit ;; + *:Plan9:*:*) + # "uname -m" is not consistent, so use $cputype instead. 386 + # is converted to i386 for consistency with other x86 + # operating systems. + if test "$cputype" = "386"; then + UNAME_MACHINE=i386 + else + UNAME_MACHINE="$cputype" + fi + echo ${UNAME_MACHINE}-unknown-plan9 + exit ;; + *:TOPS-10:*:*) + echo pdp10-unknown-tops10 + exit ;; + *:TENEX:*:*) + echo pdp10-unknown-tenex + exit ;; + KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) + echo pdp10-dec-tops20 + exit ;; + XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) + echo pdp10-xkl-tops20 + exit ;; + *:TOPS-20:*:*) + echo pdp10-unknown-tops20 + exit ;; + *:ITS:*:*) + echo pdp10-unknown-its + exit ;; + SEI:*:*:SEIUX) + echo mips-sei-seiux${UNAME_RELEASE} + exit ;; + *:DragonFly:*:*) + echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` + exit ;; + *:*VMS:*:*) + UNAME_MACHINE=`(uname -p) 2>/dev/null` + case "${UNAME_MACHINE}" in + A*) echo alpha-dec-vms ; exit ;; + I*) echo ia64-dec-vms ; exit ;; + V*) echo vax-dec-vms ; exit ;; + esac ;; + *:XENIX:*:SysV) + echo i386-pc-xenix + exit ;; + i*86:skyos:*:*) + echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' + exit ;; + i*86:rdos:*:*) + echo ${UNAME_MACHINE}-pc-rdos + exit ;; + i*86:AROS:*:*) + echo ${UNAME_MACHINE}-pc-aros + exit ;; +esac + +#echo '(No uname command or uname output not recognized.)' 1>&2 +#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 + +eval $set_cc_for_build +cat >$dummy.c < +# include +#endif +main () +{ +#if defined (sony) +#if defined (MIPSEB) + /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed, + I don't know.... */ + printf ("mips-sony-bsd\n"); exit (0); +#else +#include + printf ("m68k-sony-newsos%s\n", +#ifdef NEWSOS4 + "4" +#else + "" +#endif + ); exit (0); +#endif +#endif + +#if defined (__arm) && defined (__acorn) && defined (__unix) + printf ("arm-acorn-riscix\n"); exit (0); +#endif + +#if defined (hp300) && !defined (hpux) + printf ("m68k-hp-bsd\n"); exit (0); +#endif + +#if defined (NeXT) +#if !defined (__ARCHITECTURE__) +#define __ARCHITECTURE__ "m68k" +#endif + int version; + version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`; + if (version < 4) + printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); + else + printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); + exit (0); +#endif + +#if defined (MULTIMAX) || defined (n16) +#if defined (UMAXV) + printf ("ns32k-encore-sysv\n"); exit (0); +#else +#if defined (CMU) + printf ("ns32k-encore-mach\n"); exit (0); +#else + printf ("ns32k-encore-bsd\n"); exit (0); +#endif +#endif +#endif + +#if defined (__386BSD__) + printf ("i386-pc-bsd\n"); exit (0); +#endif + +#if defined (sequent) +#if defined (i386) + printf ("i386-sequent-dynix\n"); exit (0); +#endif +#if defined (ns32000) + printf ("ns32k-sequent-dynix\n"); exit (0); +#endif +#endif + +#if defined (_SEQUENT_) + struct utsname un; + + uname(&un); + + if (strncmp(un.version, "V2", 2) == 0) { + printf ("i386-sequent-ptx2\n"); exit (0); + } + if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */ + printf ("i386-sequent-ptx1\n"); exit (0); + } + printf ("i386-sequent-ptx\n"); exit (0); + +#endif + +#if defined (vax) +# if !defined (ultrix) +# include +# if defined (BSD) +# if BSD == 43 + printf ("vax-dec-bsd4.3\n"); exit (0); +# else +# if BSD == 199006 + printf ("vax-dec-bsd4.3reno\n"); exit (0); +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# endif +# else + printf ("vax-dec-bsd\n"); exit (0); +# endif +# else + printf ("vax-dec-ultrix\n"); exit (0); +# endif +#endif + +#if defined (alliant) && defined (i860) + printf ("i860-alliant-bsd\n"); exit (0); +#endif + + exit (1); +} +EOF + +$CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && + { echo "$SYSTEM_NAME"; exit; } + +# Apollos put the system type in the environment. + +test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } + +# Convex versions that predate uname can use getsysinfo(1) + +if [ -x /usr/convex/getsysinfo ] +then + case `getsysinfo -f cpu_type` in + c1*) + echo c1-convex-bsd + exit ;; + c2*) + if getsysinfo -f scalar_acc + then echo c32-convex-bsd + else echo c2-convex-bsd + fi + exit ;; + c34*) + echo c34-convex-bsd + exit ;; + c38*) + echo c38-convex-bsd + exit ;; + c4*) + echo c4-convex-bsd + exit ;; + esac +fi + +cat >&2 < in order to provide the needed +information to handle your system. + +config.guess timestamp = $timestamp + +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null` + +hostinfo = `(hostinfo) 2>/dev/null` +/bin/universe = `(/bin/universe) 2>/dev/null` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` +/bin/arch = `(/bin/arch) 2>/dev/null` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` + +UNAME_MACHINE = ${UNAME_MACHINE} +UNAME_RELEASE = ${UNAME_RELEASE} +UNAME_SYSTEM = ${UNAME_SYSTEM} +UNAME_VERSION = ${UNAME_VERSION} +EOF + +exit 1 + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/config.sub b/config.sub new file mode 100644 index 000000000..eb0389a69 --- /dev/null +++ b/config.sub @@ -0,0 +1,1693 @@ +#! /bin/sh +# Configuration validation subroutine script. +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, +# 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 +# Free Software Foundation, Inc. + +timestamp='2009-06-11' + +# This file is (in principle) common to ALL GNU software. +# The presence of a machine in this file suggests that SOME GNU software +# can handle that machine. It does not imply ALL GNU software can. +# +# This file is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA +# 02110-1301, USA. +# +# As a special exception to the GNU General Public License, if you +# distribute this file as part of a program that contains a +# configuration script generated by Autoconf, you may include it under +# the same distribution terms that you use for the rest of that program. + + +# Please send patches to . Submit a context +# diff and a properly formatted ChangeLog entry. +# +# Configuration subroutine to validate and canonicalize a configuration type. +# Supply the specified configuration type as an argument. +# If it is invalid, we print an error message on stderr and exit with code 1. +# Otherwise, we print the canonical config type on stdout and succeed. + +# This file is supposed to be the same for all GNU packages +# and recognize all the CPU types, system types and aliases +# that are meaningful with *any* GNU software. +# Each package is responsible for reporting which valid configurations +# it does not support. The user should be able to distinguish +# a failure to support a valid configuration from a meaningless +# configuration. + +# The goal of this file is to map all the various variations of a given +# machine specification into a single specification in the form: +# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM +# or in some cases, the newer four-part form: +# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM +# It is wrong to echo any other type of specification. + +me=`echo "$0" | sed -e 's,.*/,,'` + +usage="\ +Usage: $0 [OPTION] CPU-MFR-OPSYS + $0 [OPTION] ALIAS + +Canonicalize a configuration name. + +Operation modes: + -h, --help print this help, then exit + -t, --time-stamp print date of last modification, then exit + -v, --version print version number, then exit + +Report bugs and patches to ." + +version="\ +GNU config.sub ($timestamp) + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc. + +This is free software; see the source for copying conditions. There is NO +warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." + +help=" +Try \`$me --help' for more information." + +# Parse command line +while test $# -gt 0 ; do + case $1 in + --time-stamp | --time* | -t ) + echo "$timestamp" ; exit ;; + --version | -v ) + echo "$version" ; exit ;; + --help | --h* | -h ) + echo "$usage"; exit ;; + -- ) # Stop option processing + shift; break ;; + - ) # Use stdin as input. + break ;; + -* ) + echo "$me: invalid option $1$help" + exit 1 ;; + + *local*) + # First pass through any local machine types. + echo $1 + exit ;; + + * ) + break ;; + esac +done + +case $# in + 0) echo "$me: missing argument$help" >&2 + exit 1;; + 1) ;; + *) echo "$me: too many arguments$help" >&2 + exit 1;; +esac + +# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). +# Here we must recognize all the valid KERNEL-OS combinations. +maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` +case $maybe_os in + nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ + uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ + kopensolaris*-gnu* | \ + storm-chaos* | os2-emx* | rtmk-nova*) + os=-$maybe_os + basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` + ;; + *) + basic_machine=`echo $1 | sed 's/-[^-]*$//'` + if [ $basic_machine != $1 ] + then os=`echo $1 | sed 's/.*-/-/'` + else os=; fi + ;; +esac + +### Let's recognize common machines as not being operating systems so +### that things like config.sub decstation-3100 work. We also +### recognize some manufacturers as not being operating systems, so we +### can provide default operating systems below. +case $os in + -sun*os*) + # Prevent following clause from handling this invalid input. + ;; + -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \ + -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \ + -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \ + -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\ + -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \ + -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \ + -apple | -axis | -knuth | -cray) + os= + basic_machine=$1 + ;; + -bluegene*) + os=-cnk + ;; + -sim | -cisco | -oki | -wec | -winbond) + os= + basic_machine=$1 + ;; + -scout) + ;; + -wrs) + os=-vxworks + basic_machine=$1 + ;; + -chorusos*) + os=-chorusos + basic_machine=$1 + ;; + -chorusrdb) + os=-chorusrdb + basic_machine=$1 + ;; + -hiux*) + os=-hiuxwe2 + ;; + -sco6) + os=-sco5v6 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5) + os=-sco3.2v5 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco4) + os=-sco3.2v4 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2.[4-9]*) + os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco3.2v[4-9]*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco5v6*) + # Don't forget version if it is 3.2v4 or newer. + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -sco*) + os=-sco3.2v2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -udk*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -isc) + os=-isc2.2 + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -clix*) + basic_machine=clipper-intergraph + ;; + -isc*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` + ;; + -lynx*) + os=-lynxos + ;; + -ptx*) + basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` + ;; + -windowsnt*) + os=`echo $os | sed -e 's/windowsnt/winnt/'` + ;; + -psos*) + os=-psos + ;; + -mint | -mint[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; +esac + +# Decode aliases for certain CPU-COMPANY combinations. +case $basic_machine in + # Recognize the basic CPU types without company name. + # Some are omitted here because they have special meanings below. + 1750a | 580 \ + | a29k \ + | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ + | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ + | am33_2.0 \ + | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ + | bfin \ + | c4x | clipper \ + | d10v | d30v | dlx | dsp16xx \ + | fido | fr30 | frv \ + | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ + | i370 | i860 | i960 | ia64 \ + | ip2k | iq2000 \ + | lm32 \ + | m32c | m32r | m32rle | m68000 | m68k | m88k \ + | maxq | mb | microblaze | mcore | mep | metag \ + | mips | mipsbe | mipseb | mipsel | mipsle \ + | mips16 \ + | mips64 | mips64el \ + | mips64octeon | mips64octeonel \ + | mips64orion | mips64orionel \ + | mips64r5900 | mips64r5900el \ + | mips64vr | mips64vrel \ + | mips64vr4100 | mips64vr4100el \ + | mips64vr4300 | mips64vr4300el \ + | mips64vr5000 | mips64vr5000el \ + | mips64vr5900 | mips64vr5900el \ + | mipsisa32 | mipsisa32el \ + | mipsisa32r2 | mipsisa32r2el \ + | mipsisa64 | mipsisa64el \ + | mipsisa64r2 | mipsisa64r2el \ + | mipsisa64sb1 | mipsisa64sb1el \ + | mipsisa64sr71k | mipsisa64sr71kel \ + | mipstx39 | mipstx39el \ + | mn10200 | mn10300 \ + | moxie \ + | mt \ + | msp430 \ + | nios | nios2 \ + | ns16k | ns32k \ + | or32 \ + | pdp10 | pdp11 | pj | pjl \ + | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ + | pyramid \ + | score \ + | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ + | sh64 | sh64le \ + | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ + | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ + | spu | strongarm \ + | tahoe | thumb | tic4x | tic80 | tron \ + | v850 | v850e \ + | we32k \ + | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ + | z8k | z80) + basic_machine=$basic_machine-unknown + ;; + m6811 | m68hc11 | m6812 | m68hc12) + # Motorola 68HC11/12. + basic_machine=$basic_machine-unknown + os=-none + ;; + m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) + ;; + ms1) + basic_machine=mt-unknown + ;; + + # We use `pc' rather than `unknown' + # because (1) that's what they normally are, and + # (2) the word "unknown" tends to confuse beginning users. + i*86 | x86_64) + basic_machine=$basic_machine-pc + ;; + # Object if more than one company name word. + *-*-*) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; + # Recognize the basic CPU types with company name. + 580-* \ + | a29k-* \ + | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ + | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ + | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ + | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ + | avr-* | avr32-* \ + | bfin-* | bs2000-* \ + | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ + | clipper-* | craynv-* | cydra-* \ + | d10v-* | d30v-* | dlx-* \ + | elxsi-* \ + | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ + | h8300-* | h8500-* \ + | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ + | i*86-* | i860-* | i960-* | ia64-* \ + | ip2k-* | iq2000-* \ + | lm32-* \ + | m32c-* | m32r-* | m32rle-* \ + | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ + | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \ + | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ + | mips16-* \ + | mips64-* | mips64el-* \ + | mips64octeon-* | mips64octeonel-* \ + | mips64orion-* | mips64orionel-* \ + | mips64r5900-* | mips64r5900el-* \ + | mips64vr-* | mips64vrel-* \ + | mips64vr4100-* | mips64vr4100el-* \ + | mips64vr4300-* | mips64vr4300el-* \ + | mips64vr5000-* | mips64vr5000el-* \ + | mips64vr5900-* | mips64vr5900el-* \ + | mipsisa32-* | mipsisa32el-* \ + | mipsisa32r2-* | mipsisa32r2el-* \ + | mipsisa64-* | mipsisa64el-* \ + | mipsisa64r2-* | mipsisa64r2el-* \ + | mipsisa64sb1-* | mipsisa64sb1el-* \ + | mipsisa64sr71k-* | mipsisa64sr71kel-* \ + | mipstx39-* | mipstx39el-* \ + | mmix-* \ + | mt-* \ + | msp430-* \ + | nios-* | nios2-* \ + | none-* | np1-* | ns16k-* | ns32k-* \ + | orion-* \ + | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ + | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ + | pyramid-* \ + | romp-* | rs6000-* \ + | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ + | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ + | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ + | sparclite-* \ + | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ + | tahoe-* | thumb-* \ + | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* | tile-* \ + | tron-* \ + | v850-* | v850e-* | vax-* \ + | we32k-* \ + | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ + | xstormy16-* | xtensa*-* \ + | ymp-* \ + | z8k-* | z80-*) + ;; + # Recognize the basic CPU types without company name, with glob match. + xtensa*) + basic_machine=$basic_machine-unknown + ;; + # Recognize the various machine names and aliases which stand + # for a CPU type and a company and sometimes even an OS. + 386bsd) + basic_machine=i386-unknown + os=-bsd + ;; + 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) + basic_machine=m68000-att + ;; + 3b*) + basic_machine=we32k-att + ;; + a29khif) + basic_machine=a29k-amd + os=-udi + ;; + abacus) + basic_machine=abacus-unknown + ;; + adobe68k) + basic_machine=m68010-adobe + os=-scout + ;; + alliant | fx80) + basic_machine=fx80-alliant + ;; + altos | altos3068) + basic_machine=m68k-altos + ;; + am29k) + basic_machine=a29k-none + os=-bsd + ;; + amd64) + basic_machine=x86_64-pc + ;; + amd64-*) + basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + amdahl) + basic_machine=580-amdahl + os=-sysv + ;; + amiga | amiga-*) + basic_machine=m68k-unknown + ;; + amigaos | amigados) + basic_machine=m68k-unknown + os=-amigaos + ;; + amigaunix | amix) + basic_machine=m68k-unknown + os=-sysv4 + ;; + apollo68) + basic_machine=m68k-apollo + os=-sysv + ;; + apollo68bsd) + basic_machine=m68k-apollo + os=-bsd + ;; + aros) + basic_machine=i386-pc + os=-aros + ;; + aux) + basic_machine=m68k-apple + os=-aux + ;; + balance) + basic_machine=ns32k-sequent + os=-dynix + ;; + blackfin) + basic_machine=bfin-unknown + os=-linux + ;; + blackfin-*) + basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + bluegene*) + basic_machine=powerpc-ibm + os=-cnk + ;; + c90) + basic_machine=c90-cray + os=-unicos + ;; + cegcc) + basic_machine=arm-unknown + os=-cegcc + ;; + convex-c1) + basic_machine=c1-convex + os=-bsd + ;; + convex-c2) + basic_machine=c2-convex + os=-bsd + ;; + convex-c32) + basic_machine=c32-convex + os=-bsd + ;; + convex-c34) + basic_machine=c34-convex + os=-bsd + ;; + convex-c38) + basic_machine=c38-convex + os=-bsd + ;; + cray | j90) + basic_machine=j90-cray + os=-unicos + ;; + craynv) + basic_machine=craynv-cray + os=-unicosmp + ;; + cr16) + basic_machine=cr16-unknown + os=-elf + ;; + crds | unos) + basic_machine=m68k-crds + ;; + crisv32 | crisv32-* | etraxfs*) + basic_machine=crisv32-axis + ;; + cris | cris-* | etrax*) + basic_machine=cris-axis + ;; + crx) + basic_machine=crx-unknown + os=-elf + ;; + da30 | da30-*) + basic_machine=m68k-da30 + ;; + decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) + basic_machine=mips-dec + ;; + decsystem10* | dec10*) + basic_machine=pdp10-dec + os=-tops10 + ;; + decsystem20* | dec20*) + basic_machine=pdp10-dec + os=-tops20 + ;; + delta | 3300 | motorola-3300 | motorola-delta \ + | 3300-motorola | delta-motorola) + basic_machine=m68k-motorola + ;; + delta88) + basic_machine=m88k-motorola + os=-sysv3 + ;; + dicos) + basic_machine=i686-pc + os=-dicos + ;; + djgpp) + basic_machine=i586-pc + os=-msdosdjgpp + ;; + dpx20 | dpx20-*) + basic_machine=rs6000-bull + os=-bosx + ;; + dpx2* | dpx2*-bull) + basic_machine=m68k-bull + os=-sysv3 + ;; + ebmon29k) + basic_machine=a29k-amd + os=-ebmon + ;; + elxsi) + basic_machine=elxsi-elxsi + os=-bsd + ;; + encore | umax | mmax) + basic_machine=ns32k-encore + ;; + es1800 | OSE68k | ose68k | ose | OSE) + basic_machine=m68k-ericsson + os=-ose + ;; + fx2800) + basic_machine=i860-alliant + ;; + genix) + basic_machine=ns32k-ns + ;; + gmicro) + basic_machine=tron-gmicro + os=-sysv + ;; + go32) + basic_machine=i386-pc + os=-go32 + ;; + h3050r* | hiux*) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + h8300hms) + basic_machine=h8300-hitachi + os=-hms + ;; + h8300xray) + basic_machine=h8300-hitachi + os=-xray + ;; + h8500hms) + basic_machine=h8500-hitachi + os=-hms + ;; + harris) + basic_machine=m88k-harris + os=-sysv3 + ;; + hp300-*) + basic_machine=m68k-hp + ;; + hp300bsd) + basic_machine=m68k-hp + os=-bsd + ;; + hp300hpux) + basic_machine=m68k-hp + os=-hpux + ;; + hp3k9[0-9][0-9] | hp9[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k2[0-9][0-9] | hp9k31[0-9]) + basic_machine=m68000-hp + ;; + hp9k3[2-9][0-9]) + basic_machine=m68k-hp + ;; + hp9k6[0-9][0-9] | hp6[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hp9k7[0-79][0-9] | hp7[0-79][0-9]) + basic_machine=hppa1.1-hp + ;; + hp9k78[0-9] | hp78[0-9]) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) + # FIXME: really hppa2.0-hp + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][13679] | hp8[0-9][13679]) + basic_machine=hppa1.1-hp + ;; + hp9k8[0-9][0-9] | hp8[0-9][0-9]) + basic_machine=hppa1.0-hp + ;; + hppa-next) + os=-nextstep3 + ;; + hppaosf) + basic_machine=hppa1.1-hp + os=-osf + ;; + hppro) + basic_machine=hppa1.1-hp + os=-proelf + ;; + i370-ibm* | ibm*) + basic_machine=i370-ibm + ;; +# I'm not sure what "Sysv32" means. Should this be sysv3.2? + i*86v32) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv32 + ;; + i*86v4*) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv4 + ;; + i*86v) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-sysv + ;; + i*86sol2) + basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` + os=-solaris2 + ;; + i386mach) + basic_machine=i386-mach + os=-mach + ;; + i386-vsta | vsta) + basic_machine=i386-unknown + os=-vsta + ;; + iris | iris4d) + basic_machine=mips-sgi + case $os in + -irix*) + ;; + *) + os=-irix4 + ;; + esac + ;; + isi68 | isi) + basic_machine=m68k-isi + os=-sysv + ;; + m68knommu) + basic_machine=m68k-unknown + os=-linux + ;; + m68knommu-*) + basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + m88k-omron*) + basic_machine=m88k-omron + ;; + magnum | m3230) + basic_machine=mips-mips + os=-sysv + ;; + merlin) + basic_machine=ns32k-utek + os=-sysv + ;; + mingw32) + basic_machine=i386-pc + os=-mingw32 + ;; + mingw32ce) + basic_machine=arm-unknown + os=-mingw32ce + ;; + miniframe) + basic_machine=m68000-convergent + ;; + *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) + basic_machine=m68k-atari + os=-mint + ;; + mips3*-*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` + ;; + mips3*) + basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown + ;; + monitor) + basic_machine=m68k-rom68k + os=-coff + ;; + morphos) + basic_machine=powerpc-unknown + os=-morphos + ;; + msdos) + basic_machine=i386-pc + os=-msdos + ;; + ms1-*) + basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` + ;; + mvs) + basic_machine=i370-ibm + os=-mvs + ;; + ncr3000) + basic_machine=i486-ncr + os=-sysv4 + ;; + netbsd386) + basic_machine=i386-unknown + os=-netbsd + ;; + netwinder) + basic_machine=armv4l-rebel + os=-linux + ;; + news | news700 | news800 | news900) + basic_machine=m68k-sony + os=-newsos + ;; + news1000) + basic_machine=m68030-sony + os=-newsos + ;; + news-3600 | risc-news) + basic_machine=mips-sony + os=-newsos + ;; + necv70) + basic_machine=v70-nec + os=-sysv + ;; + next | m*-next ) + basic_machine=m68k-next + case $os in + -nextstep* ) + ;; + -ns2*) + os=-nextstep2 + ;; + *) + os=-nextstep3 + ;; + esac + ;; + nh3000) + basic_machine=m68k-harris + os=-cxux + ;; + nh[45]000) + basic_machine=m88k-harris + os=-cxux + ;; + nindy960) + basic_machine=i960-intel + os=-nindy + ;; + mon960) + basic_machine=i960-intel + os=-mon960 + ;; + nonstopux) + basic_machine=mips-compaq + os=-nonstopux + ;; + np1) + basic_machine=np1-gould + ;; + nsr-tandem) + basic_machine=nsr-tandem + ;; + op50n-* | op60c-*) + basic_machine=hppa1.1-oki + os=-proelf + ;; + openrisc | openrisc-*) + basic_machine=or32-unknown + ;; + os400) + basic_machine=powerpc-ibm + os=-os400 + ;; + OSE68000 | ose68000) + basic_machine=m68000-ericsson + os=-ose + ;; + os68k) + basic_machine=m68k-none + os=-os68k + ;; + pa-hitachi) + basic_machine=hppa1.1-hitachi + os=-hiuxwe2 + ;; + paragon) + basic_machine=i860-intel + os=-osf + ;; + parisc) + basic_machine=hppa-unknown + os=-linux + ;; + parisc-*) + basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'` + os=-linux + ;; + pbd) + basic_machine=sparc-tti + ;; + pbb) + basic_machine=m68k-tti + ;; + pc532 | pc532-*) + basic_machine=ns32k-pc532 + ;; + pc98) + basic_machine=i386-pc + ;; + pc98-*) + basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium | p5 | k5 | k6 | nexgen | viac3) + basic_machine=i586-pc + ;; + pentiumpro | p6 | 6x86 | athlon | athlon_*) + basic_machine=i686-pc + ;; + pentiumii | pentium2 | pentiumiii | pentium3) + basic_machine=i686-pc + ;; + pentium4) + basic_machine=i786-pc + ;; + pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) + basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumpro-* | p6-* | 6x86-* | athlon-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) + basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pentium4-*) + basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + pn) + basic_machine=pn-gould + ;; + power) basic_machine=power-ibm + ;; + ppc) basic_machine=powerpc-unknown + ;; + ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppcle | powerpclittle | ppc-le | powerpc-little) + basic_machine=powerpcle-unknown + ;; + ppcle-* | powerpclittle-*) + basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64) basic_machine=powerpc64-unknown + ;; + ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ppc64le | powerpc64little | ppc64-le | powerpc64-little) + basic_machine=powerpc64le-unknown + ;; + ppc64le-* | powerpc64little-*) + basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` + ;; + ps2) + basic_machine=i386-ibm + ;; + pw32) + basic_machine=i586-unknown + os=-pw32 + ;; + rdos) + basic_machine=i386-pc + os=-rdos + ;; + rom68k) + basic_machine=m68k-rom68k + os=-coff + ;; + rm[46]00) + basic_machine=mips-siemens + ;; + rtpc | rtpc-*) + basic_machine=romp-ibm + ;; + s390 | s390-*) + basic_machine=s390-ibm + ;; + s390x | s390x-*) + basic_machine=s390x-ibm + ;; + sa29200) + basic_machine=a29k-amd + os=-udi + ;; + sb1) + basic_machine=mipsisa64sb1-unknown + ;; + sb1el) + basic_machine=mipsisa64sb1el-unknown + ;; + sde) + basic_machine=mipsisa32-sde + os=-elf + ;; + sei) + basic_machine=mips-sei + os=-seiux + ;; + sequent) + basic_machine=i386-sequent + ;; + sh) + basic_machine=sh-hitachi + os=-hms + ;; + sh5el) + basic_machine=sh5le-unknown + ;; + sh64) + basic_machine=sh64-unknown + ;; + sparclite-wrs | simso-wrs) + basic_machine=sparclite-wrs + os=-vxworks + ;; + sps7) + basic_machine=m68k-bull + os=-sysv2 + ;; + spur) + basic_machine=spur-unknown + ;; + st2000) + basic_machine=m68k-tandem + ;; + stratus) + basic_machine=i860-stratus + os=-sysv4 + ;; + sun2) + basic_machine=m68000-sun + ;; + sun2os3) + basic_machine=m68000-sun + os=-sunos3 + ;; + sun2os4) + basic_machine=m68000-sun + os=-sunos4 + ;; + sun3os3) + basic_machine=m68k-sun + os=-sunos3 + ;; + sun3os4) + basic_machine=m68k-sun + os=-sunos4 + ;; + sun4os3) + basic_machine=sparc-sun + os=-sunos3 + ;; + sun4os4) + basic_machine=sparc-sun + os=-sunos4 + ;; + sun4sol2) + basic_machine=sparc-sun + os=-solaris2 + ;; + sun3 | sun3-*) + basic_machine=m68k-sun + ;; + sun4) + basic_machine=sparc-sun + ;; + sun386 | sun386i | roadrunner) + basic_machine=i386-sun + ;; + sv1) + basic_machine=sv1-cray + os=-unicos + ;; + symmetry) + basic_machine=i386-sequent + os=-dynix + ;; + t3e) + basic_machine=alphaev5-cray + os=-unicos + ;; + t90) + basic_machine=t90-cray + os=-unicos + ;; + tic54x | c54x*) + basic_machine=tic54x-unknown + os=-coff + ;; + tic55x | c55x*) + basic_machine=tic55x-unknown + os=-coff + ;; + tic6x | c6x*) + basic_machine=tic6x-unknown + os=-coff + ;; + tile*) + basic_machine=tile-unknown + os=-linux-gnu + ;; + tx39) + basic_machine=mipstx39-unknown + ;; + tx39el) + basic_machine=mipstx39el-unknown + ;; + toad1) + basic_machine=pdp10-xkl + os=-tops20 + ;; + tower | tower-32) + basic_machine=m68k-ncr + ;; + tpf) + basic_machine=s390x-ibm + os=-tpf + ;; + udi29k) + basic_machine=a29k-amd + os=-udi + ;; + ultra3) + basic_machine=a29k-nyu + os=-sym1 + ;; + v810 | necv810) + basic_machine=v810-nec + os=-none + ;; + vaxv) + basic_machine=vax-dec + os=-sysv + ;; + vms) + basic_machine=vax-dec + os=-vms + ;; + vpp*|vx|vx-*) + basic_machine=f301-fujitsu + ;; + vxworks960) + basic_machine=i960-wrs + os=-vxworks + ;; + vxworks68) + basic_machine=m68k-wrs + os=-vxworks + ;; + vxworks29k) + basic_machine=a29k-wrs + os=-vxworks + ;; + w65*) + basic_machine=w65-wdc + os=-none + ;; + w89k-*) + basic_machine=hppa1.1-winbond + os=-proelf + ;; + xbox) + basic_machine=i686-pc + os=-mingw32 + ;; + xps | xps100) + basic_machine=xps100-honeywell + ;; + ymp) + basic_machine=ymp-cray + os=-unicos + ;; + z8k-*-coff) + basic_machine=z8k-unknown + os=-sim + ;; + z80-*-coff) + basic_machine=z80-unknown + os=-sim + ;; + none) + basic_machine=none-none + os=-none + ;; + +# Here we handle the default manufacturer of certain CPU types. It is in +# some cases the only manufacturer, in others, it is the most popular. + w89k) + basic_machine=hppa1.1-winbond + ;; + op50n) + basic_machine=hppa1.1-oki + ;; + op60c) + basic_machine=hppa1.1-oki + ;; + romp) + basic_machine=romp-ibm + ;; + mmix) + basic_machine=mmix-knuth + ;; + rs6000) + basic_machine=rs6000-ibm + ;; + vax) + basic_machine=vax-dec + ;; + pdp10) + # there are many clones, so DEC is not a safe bet + basic_machine=pdp10-unknown + ;; + pdp11) + basic_machine=pdp11-dec + ;; + we32k) + basic_machine=we32k-att + ;; + sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele) + basic_machine=sh-unknown + ;; + sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) + basic_machine=sparc-sun + ;; + cydra) + basic_machine=cydra-cydrome + ;; + orion) + basic_machine=orion-highlevel + ;; + orion105) + basic_machine=clipper-highlevel + ;; + mac | mpw | mac-mpw) + basic_machine=m68k-apple + ;; + pmac | pmac-mpw) + basic_machine=powerpc-apple + ;; + *-unknown) + # Make sure to match an already-canonicalized machine name. + ;; + *) + echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2 + exit 1 + ;; +esac + +# Here we canonicalize certain aliases for manufacturers. +case $basic_machine in + *-digital*) + basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'` + ;; + *-commodore*) + basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'` + ;; + *) + ;; +esac + +# Decode manufacturer-specific aliases for certain operating systems. + +if [ x"$os" != x"" ] +then +case $os in + # First match some system type aliases + # that might get confused with valid system types. + # -solaris* is a basic system type, with this one exception. + -solaris1 | -solaris1.*) + os=`echo $os | sed -e 's|solaris1|sunos4|'` + ;; + -solaris) + os=-solaris2 + ;; + -svr4*) + os=-sysv4 + ;; + -unixware*) + os=-sysv4.2uw + ;; + -gnu/linux*) + os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` + ;; + # First accept the basic system types. + # The portable systems comes first. + # Each alternative MUST END IN A *, to match a version number. + # -sysv* is not here because it comes later, after sysvr4. + -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \ + | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\ + | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ + | -kopensolaris* \ + | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ + | -aos* | -aros* \ + | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ + | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ + | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ + | -openbsd* | -solidbsd* \ + | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ + | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ + | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ + | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ + | -chorusos* | -chorusrdb* | -cegcc* \ + | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ + | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ + | -uxpv* | -beos* | -mpeix* | -udk* \ + | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ + | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ + | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ + | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ + | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ + | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ + | -skyos* | -haiku* | -rdos* | -toppers* | -drops*) + # Remember, each alternative MUST END IN *, to match a version number. + ;; + -qnx*) + case $basic_machine in + x86-* | i*86-*) + ;; + *) + os=-nto$os + ;; + esac + ;; + -nto-qnx*) + ;; + -nto*) + os=`echo $os | sed -e 's|nto|nto-qnx|'` + ;; + -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ + | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ + | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) + ;; + -mac*) + os=`echo $os | sed -e 's|mac|macos|'` + ;; + -linux-dietlibc) + os=-linux-dietlibc + ;; + -linux*) + os=`echo $os | sed -e 's|linux|linux-gnu|'` + ;; + -sunos5*) + os=`echo $os | sed -e 's|sunos5|solaris2|'` + ;; + -sunos6*) + os=`echo $os | sed -e 's|sunos6|solaris3|'` + ;; + -opened*) + os=-openedition + ;; + -os400*) + os=-os400 + ;; + -wince*) + os=-wince + ;; + -osfrose*) + os=-osfrose + ;; + -osf*) + os=-osf + ;; + -utek*) + os=-bsd + ;; + -dynix*) + os=-bsd + ;; + -acis*) + os=-aos + ;; + -atheos*) + os=-atheos + ;; + -syllable*) + os=-syllable + ;; + -386bsd) + os=-bsd + ;; + -ctix* | -uts*) + os=-sysv + ;; + -nova*) + os=-rtmk-nova + ;; + -ns2 ) + os=-nextstep2 + ;; + -nsk*) + os=-nsk + ;; + # Preserve the version number of sinix5. + -sinix5.*) + os=`echo $os | sed -e 's|sinix|sysv|'` + ;; + -sinix*) + os=-sysv4 + ;; + -tpf*) + os=-tpf + ;; + -triton*) + os=-sysv3 + ;; + -oss*) + os=-sysv3 + ;; + -svr4) + os=-sysv4 + ;; + -svr3) + os=-sysv3 + ;; + -sysvr4) + os=-sysv4 + ;; + # This must come after -sysvr4. + -sysv*) + ;; + -ose*) + os=-ose + ;; + -es1800*) + os=-ose + ;; + -xenix) + os=-xenix + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + os=-mint + ;; + -aros*) + os=-aros + ;; + -kaos*) + os=-kaos + ;; + -zvmoe) + os=-zvmoe + ;; + -dicos*) + os=-dicos + ;; + -none) + ;; + *) + # Get rid of the `-' at the beginning of $os. + os=`echo $os | sed 's/[^-]*-//'` + echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2 + exit 1 + ;; +esac +else + +# Here we handle the default operating systems that come with various machines. +# The value should be what the vendor currently ships out the door with their +# machine or put another way, the most popular os provided with the machine. + +# Note that if you're going to try to match "-MANUFACTURER" here (say, +# "-sun"), then you have to tell the case statement up towards the top +# that MANUFACTURER isn't an operating system. Otherwise, code above +# will signal an error saying that MANUFACTURER isn't an operating +# system, and we'll never get to this point. + +case $basic_machine in + score-*) + os=-elf + ;; + spu-*) + os=-elf + ;; + *-acorn) + os=-riscix1.2 + ;; + arm*-rebel) + os=-linux + ;; + arm*-semi) + os=-aout + ;; + c4x-* | tic4x-*) + os=-coff + ;; + # This must come before the *-dec entry. + pdp10-*) + os=-tops20 + ;; + pdp11-*) + os=-none + ;; + *-dec | vax-*) + os=-ultrix4.2 + ;; + m68*-apollo) + os=-domain + ;; + i386-sun) + os=-sunos4.0.2 + ;; + m68000-sun) + os=-sunos3 + # This also exists in the configure program, but was not the + # default. + # os=-sunos4 + ;; + m68*-cisco) + os=-aout + ;; + mep-*) + os=-elf + ;; + mips*-cisco) + os=-elf + ;; + mips*-*) + os=-elf + ;; + or32-*) + os=-coff + ;; + *-tti) # must be before sparc entry or we get the wrong os. + os=-sysv3 + ;; + sparc-* | *-sun) + os=-sunos4.1.1 + ;; + *-be) + os=-beos + ;; + *-haiku) + os=-haiku + ;; + *-ibm) + os=-aix + ;; + *-knuth) + os=-mmixware + ;; + *-wec) + os=-proelf + ;; + *-winbond) + os=-proelf + ;; + *-oki) + os=-proelf + ;; + *-hp) + os=-hpux + ;; + *-hitachi) + os=-hiux + ;; + i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) + os=-sysv + ;; + *-cbm) + os=-amigaos + ;; + *-dg) + os=-dgux + ;; + *-dolphin) + os=-sysv3 + ;; + m68k-ccur) + os=-rtu + ;; + m88k-omron*) + os=-luna + ;; + *-next ) + os=-nextstep + ;; + *-sequent) + os=-ptx + ;; + *-crds) + os=-unos + ;; + *-ns) + os=-genix + ;; + i370-*) + os=-mvs + ;; + *-next) + os=-nextstep3 + ;; + *-gould) + os=-sysv + ;; + *-highlevel) + os=-bsd + ;; + *-encore) + os=-bsd + ;; + *-sgi) + os=-irix + ;; + *-siemens) + os=-sysv4 + ;; + *-masscomp) + os=-rtu + ;; + f30[01]-fujitsu | f700-fujitsu) + os=-uxpv + ;; + *-rom68k) + os=-coff + ;; + *-*bug) + os=-coff + ;; + *-apple) + os=-macos + ;; + *-atari*) + os=-mint + ;; + *) + os=-none + ;; +esac +fi + +# Here we handle the case where we know the os, and the CPU type, but not the +# manufacturer. We pick the logical manufacturer. +vendor=unknown +case $basic_machine in + *-unknown) + case $os in + -riscix*) + vendor=acorn + ;; + -sunos*) + vendor=sun + ;; + -cnk*|-aix*) + vendor=ibm + ;; + -beos*) + vendor=be + ;; + -hpux*) + vendor=hp + ;; + -mpeix*) + vendor=hp + ;; + -hiux*) + vendor=hitachi + ;; + -unos*) + vendor=crds + ;; + -dgux*) + vendor=dg + ;; + -luna*) + vendor=omron + ;; + -genix*) + vendor=ns + ;; + -mvs* | -opened*) + vendor=ibm + ;; + -os400*) + vendor=ibm + ;; + -ptx*) + vendor=sequent + ;; + -tpf*) + vendor=ibm + ;; + -vxsim* | -vxworks* | -windiss*) + vendor=wrs + ;; + -aux*) + vendor=apple + ;; + -hms*) + vendor=hitachi + ;; + -mpw* | -macos*) + vendor=apple + ;; + -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) + vendor=atari + ;; + -vos*) + vendor=stratus + ;; + esac + basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` + ;; +esac + +echo $basic_machine$os +exit + +# Local variables: +# eval: (add-hook 'write-file-hooks 'time-stamp) +# time-stamp-start: "timestamp='" +# time-stamp-format: "%:y-%02m-%02d" +# time-stamp-end: "'" +# End: diff --git a/configure b/configure new file mode 100644 index 000000000..abbd3d632 --- /dev/null +++ b/configure @@ -0,0 +1,5776 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.65 for PCem v10.1. +# +# Report bugs to >. +# +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# +# +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + +if test "x$CONFIG_SHELL" = x; then + as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which + # is contrary to our usage. Disable this feature. + alias -g '\${1+\"\$@\"}'='\"\$@\"' + setopt NO_GLOB_SUBST +else + case \`(set -o) 2>/dev/null\` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi +" + as_required="as_fn_return () { (exit \$1); } +as_fn_success () { as_fn_return 0; } +as_fn_failure () { as_fn_return 1; } +as_fn_ret_success () { return 0; } +as_fn_ret_failure () { return 1; } + +exitcode=0 +as_fn_success || { exitcode=1; echo as_fn_success failed.; } +as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; } +as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; } +as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; } +if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then : + +else + exitcode=1; echo positional parameters were not saved. +fi +test x\$exitcode = x0 || exit 1" + as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO + as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO + eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" && + test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1" + if (eval "$as_required") 2>/dev/null; then : + as_have_required=yes +else + as_have_required=no +fi + if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then : + +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +as_found=false +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + as_found=: + case $as_dir in #( + /*) + for as_base in sh bash ksh sh5; do + # Try only shells that exist, to save several forks. + as_shell=$as_dir/$as_base + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then : + CONFIG_SHELL=$as_shell as_have_required=yes + if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then : + break 2 +fi +fi + done;; + esac + as_found=false +done +$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } && + { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then : + CONFIG_SHELL=$SHELL as_have_required=yes +fi; } +IFS=$as_save_IFS + + + if test "x$CONFIG_SHELL" != x; then : + # We cannot yet assume a decent shell, so we have to provide a + # neutralization value for shells without unset; and this also + # works around shells that cannot unset nonexistent variables. + BASH_ENV=/dev/null + ENV=/dev/null + (unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +fi + + if test x$as_have_required = xno; then : + $as_echo "$0: This script requires a shell more modern than all" + $as_echo "$0: the shells that I found on your system." + if test x${ZSH_VERSION+set} = xset ; then + $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should" + $as_echo "$0: be upgraded to zsh 4.3.4 or later." + else + $as_echo "$0: Please tell bug-autoconf@gnu.org and Tom Walker +$0: about your system, +$0: including any error possibly output before this +$0: message. Then install a modern shell, or manually run +$0: the script under such a shell if you do have one." + fi + exit 1 +fi +fi +fi +SHELL=${CONFIG_SHELL-/bin/sh} +export SHELL +# Unset more variables known to interfere with behavior of common tools. +CLICOLOR_FORCE= GREP_OPTIONS= +unset CLICOLOR_FORCE GREP_OPTIONS + +## --------------------- ## +## M4sh Shell Functions. ## +## --------------------- ## +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +# as_fn_error ERROR [LINENO LOG_FD] +# --------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with status $?, using 1 if that was 0. +as_fn_error () +{ + as_status=$?; test $as_status -eq 0 && as_status=1 + if test "$3"; then + as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 + fi + $as_echo "$as_me: error: $1" >&2 + as_fn_exit $as_status +} # as_fn_error + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + + + as_lineno_1=$LINENO as_lineno_1a=$LINENO + as_lineno_2=$LINENO as_lineno_2a=$LINENO + eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" && + test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || { + # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +test -n "$DJDIR" || exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= + +# Identity of this package. +PACKAGE_NAME='PCem' +PACKAGE_TARNAME='pcem' +PACKAGE_VERSION='v10.1' +PACKAGE_STRING='PCem v10.1' +PACKAGE_BUGREPORT='Tom Walker ' +PACKAGE_URL='' + +ac_subst_vars='am__EXEEXT_FALSE +am__EXEEXT_TRUE +LTLIBOBJS +LIBOBJS +allegro_LIBS +allegro_CFLAGS +ALLEGRO_CONFIG +OS_LINUX_FALSE +OS_LINUX_TRUE +OS_WIN_FALSE +OS_WIN_TRUE +CPU_X86_64_FALSE +CPU_X86_64_TRUE +CPU_I386_FALSE +CPU_I386_TRUE +am__fastdepCXX_FALSE +am__fastdepCXX_TRUE +CXXDEPMODE +ac_ct_CXX +CXXFLAGS +CXX +am__fastdepCC_FALSE +am__fastdepCC_TRUE +CCDEPMODE +AMDEPBACKSLASH +AMDEP_FALSE +AMDEP_TRUE +am__quote +am__include +DEPDIR +OBJEXT +EXEEXT +ac_ct_CC +CPPFLAGS +LDFLAGS +CFLAGS +CC +am__untar +am__tar +AMTAR +am__leading_dot +SET_MAKE +AWK +mkdir_p +MKDIR_P +INSTALL_STRIP_PROGRAM +STRIP +install_sh +MAKEINFO +AUTOHEADER +AUTOMAKE +AUTOCONF +ACLOCAL +VERSION +PACKAGE +CYGPATH_W +am__isrc +INSTALL_DATA +INSTALL_SCRIPT +INSTALL_PROGRAM +host_os +host_vendor +host_cpu +host +build_os +build_vendor +build_cpu +build +target_alias +host_alias +build_alias +LIBS +ECHO_T +ECHO_N +ECHO_C +DEFS +mandir +localedir +libdir +psdir +pdfdir +dvidir +htmldir +infodir +docdir +oldincludedir +includedir +localstatedir +sharedstatedir +sysconfdir +datadir +datarootdir +libexecdir +sbindir +bindir +program_transform_name +prefix +exec_prefix +PACKAGE_URL +PACKAGE_BUGREPORT +PACKAGE_STRING +PACKAGE_VERSION +PACKAGE_TARNAME +PACKAGE_NAME +PATH_SEPARATOR +SHELL' +ac_subst_files='' +ac_user_opts=' +enable_option_checking +enable_dependency_tracking +enable_debug +with_allegro_prefix +with_allegro_exec_prefix +enable_allegrotest +' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CXX +CXXFLAGS +CCC' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +ac_unrecognized_opts= +ac_unrecognized_sep= +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid feature name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"enable_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval enable_$ac_useropt=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=\$ac_optarg ;; + + -without-* | --without-*) + ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null && + as_fn_error "invalid package name: $ac_useropt" + ac_useropt_orig=$ac_useropt + ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'` + case $ac_user_opts in + *" +"with_$ac_useropt" +"*) ;; + *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig" + ac_unrecognized_sep=', ';; + esac + eval with_$ac_useropt=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) as_fn_error "unrecognized option: \`$ac_option' +Try \`$0 --help' for more information." + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + case $ac_envvar in #( + '' | [0-9]* | *[!_$as_cr_alnum]* ) + as_fn_error "invalid variable name: \`$ac_envvar'" ;; + esac + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + as_fn_error "missing argument to $ac_option" +fi + +if test -n "$ac_unrecognized_opts"; then + case $enable_option_checking in + no) ;; + fatal) as_fn_error "unrecognized options: $ac_unrecognized_opts" ;; + *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;; + esac +fi + +# Check all directory arguments for consistency. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + # Remove trailing slashes. + case $ac_val in + */ ) + ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'` + eval $ac_var=\$ac_val;; + esac + # Be sure to have absolute directory names. + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + as_fn_error "expected an absolute directory name for --$ac_var: $ac_val" +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + $as_echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + as_fn_error "working directory cannot be determined" +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + as_fn_error "pwd does not report name of working directory" + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$as_myself" || +$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_myself" : 'X\(//\)[^/]' \| \ + X"$as_myself" : 'X\(//\)$' \| \ + X"$as_myself" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_myself" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + as_fn_error "cannot find sources ($ac_unique_file) in $srcdir" +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error "$ac_msg" + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures PCem v10.1 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/pcem] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names + +System types: + --build=BUILD configure for building on BUILD [guessed] + --host=HOST cross-compile to build programs to run on HOST [BUILD] +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of PCem v10.1:";; + esac + cat <<\_ACEOF + +Optional Features: + --disable-option-checking ignore unrecognized --enable/--with options + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors + --enable-debug build debug executable + --disable-allegrotest Do not try to compile and run a test LIBallegro program + +Optional Packages: + --with-PACKAGE[=ARG] use PACKAGE [ARG=yes] + --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no) + --with-allegro-prefix=PFX Prefix where liballegro is installed (optional) + --with-allegro-exec-prefix=PFX Exec prefix where liballegro is installed (optional) + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CXX C++ compiler command + CXXFLAGS C++ compiler flags + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to >. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || + { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } || + continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +PCem configure v10.1 +generated by GNU Autoconf 2.65 + +Copyright (C) 2009 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi + +## ------------------------ ## +## Autoconf initialization. ## +## ------------------------ ## + +# ac_fn_c_try_compile LINENO +# -------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_c_try_compile + +# ac_fn_cxx_try_compile LINENO +# ---------------------------- +# Try to compile conftest.$ac_ext, and return whether this succeeded. +ac_fn_cxx_try_compile () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext + if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_cxx_try_compile + +# ac_fn_c_try_run LINENO +# ---------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes +# that executables *can* be run. +ac_fn_c_try_run () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { ac_try='./conftest$ac_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then : + ac_retval=0 +else + $as_echo "$as_me: program exited with status $ac_status" >&5 + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=$ac_status +fi + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_c_try_run + +# ac_fn_c_try_link LINENO +# ----------------------- +# Try to link conftest.$ac_ext, and return whether this succeeded. +ac_fn_c_try_link () +{ + as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + rm -f conftest.$ac_objext conftest$ac_exeext + if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + grep -v '^ *+' conftest.err >conftest.er1 + cat conftest.er1 >&5 + mv -f conftest.er1 conftest.err + fi + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && { + test "$cross_compiling" = yes || + $as_test_x conftest$ac_exeext + }; then : + ac_retval=0 +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_retval=1 +fi + # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information + # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would + # interfere with the next link command; also delete a directory that is + # left behind by Apple's compiler. We do this before executing the actions. + rm -rf conftest.dSYM conftest_ipa8_conftest.oo + eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;} + as_fn_set_status $ac_retval + +} # ac_fn_c_try_link +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by PCem $as_me v10.1, which was +generated by GNU Autoconf 2.65. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + $as_echo "PATH: $as_dir" + done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;; + 2) + as_fn_append ac_configure_args1 " '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + as_fn_append ac_configure_args " '$ac_arg'" + ;; + esac + done +done +{ ac_configure_args0=; unset ac_configure_args0;} +{ ac_configure_args1=; unset ac_configure_args1;} + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------------- ## +## File substitutions. ## +## ------------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + $as_echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + $as_echo "$as_me: caught signal $ac_signal" + $as_echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +$as_echo "/* confdefs.h */" > confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_URL "$PACKAGE_URL" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer an explicitly selected file to automatically selected ones. +ac_site_file1=NONE +ac_site_file2=NONE +if test -n "$CONFIG_SITE"; then + ac_site_file1=$CONFIG_SITE +elif test "x$prefix" != xNONE; then + ac_site_file1=$prefix/share/config.site + ac_site_file2=$prefix/etc/config.site +else + ac_site_file1=$ac_default_prefix/share/config.site + ac_site_file2=$ac_default_prefix/etc/config.site +fi +for ac_site_file in "$ac_site_file1" "$ac_site_file2" +do + test "x$ac_site_file" = xNONE && continue + if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5 +$as_echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special files + # actually), so we avoid doing that. DJGPP emulates it as a regular file. + if test /dev/null != "$cache_file" && test -f "$cache_file"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5 +$as_echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5 +$as_echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5 +$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + # differences in whitespace do not lead to failure. + ac_old_val_w=`echo x $ac_old_val` + ac_new_val_w=`echo x $ac_new_val` + if test "$ac_old_val_w" != "$ac_new_val_w"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5 +$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + ac_cache_corrupted=: + else + { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5 +$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;} + eval $ac_var=\$ac_old_val + fi + { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5 +$as_echo "$as_me: former value: \`$ac_old_val'" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5 +$as_echo "$as_me: current value: \`$ac_new_val'" >&2;} + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) as_fn_append ac_configure_args " '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} + { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5 +$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;} + as_fn_error "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5 +fi +## -------------------- ## +## Main body of script. ## +## -------------------- ## + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + for ac_t in install-sh install.sh shtool; do + if test -f "$ac_dir/$ac_t"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/$ac_t -c" + break 2 + fi + done +done +if test -z "$ac_aux_dir"; then + as_fn_error "cannot find install-sh, install.sh, or shtool in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" "$LINENO" 5 +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Make sure we can run config.sub. +$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 || + as_fn_error "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5 + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5 +$as_echo_n "checking build system type... " >&6; } +if test "${ac_cv_build+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_build_alias=$build_alias +test "x$ac_build_alias" = x && + ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"` +test "x$ac_build_alias" = x && + as_fn_error "cannot guess build type; you must specify one" "$LINENO" 5 +ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` || + as_fn_error "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5 + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5 +$as_echo "$ac_cv_build" >&6; } +case $ac_cv_build in +*-*-*) ;; +*) as_fn_error "invalid value of canonical build" "$LINENO" 5;; +esac +build=$ac_cv_build +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_build +shift +build_cpu=$1 +build_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +build_os=$* +IFS=$ac_save_IFS +case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5 +$as_echo_n "checking host system type... " >&6; } +if test "${ac_cv_host+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test "x$host_alias" = x; then + ac_cv_host=$ac_cv_build +else + ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` || + as_fn_error "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5 +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5 +$as_echo "$ac_cv_host" >&6; } +case $ac_cv_host in +*-*-*) ;; +*) as_fn_error "invalid value of canonical host" "$LINENO" 5;; +esac +host=$ac_cv_host +ac_save_IFS=$IFS; IFS='-' +set x $ac_cv_host +shift +host_cpu=$1 +host_vendor=$2 +shift; shift +# Remember, the first character of IFS is used to create $*, +# except with old shells: +host_os=$* +IFS=$ac_save_IFS +case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac + + + +am__api_version='1.11' + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +# Reject install programs that cannot install multiple files. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5 +$as_echo_n "checking for a BSD-compatible install... " >&6; } +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in #(( + ./ | .// | /[cC]/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + rm -rf conftest.one conftest.two conftest.dir + echo one > conftest.one + echo two > conftest.two + mkdir conftest.dir + if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" && + test -s conftest.one && test -s conftest.two && + test -s conftest.dir/conftest.one && + test -s conftest.dir/conftest.two + then + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + fi + done + done + ;; +esac + + done +IFS=$as_save_IFS + +rm -rf conftest.one conftest.two conftest.dir + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5 +$as_echo "$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5 +$as_echo_n "checking whether build environment is sane... " >&6; } +# Just in case +sleep 1 +echo timestamp > conftest.file +# Reject unsafe characters in $srcdir or the absolute working directory +# name. Accept space and tab only in the latter. +am_lf=' +' +case `pwd` in + *[\\\"\#\$\&\'\`$am_lf]*) + as_fn_error "unsafe absolute working directory name" "$LINENO" 5;; +esac +case $srcdir in + *[\\\"\#\$\&\'\`$am_lf\ \ ]*) + as_fn_error "unsafe srcdir value: \`$srcdir'" "$LINENO" 5;; +esac + +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t "$srcdir/configure" conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + as_fn_error "ls -t appears to fail. Make sure there is not a broken +alias in your environment" "$LINENO" 5 + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + as_fn_error "newly created file is older than distributed files! +Check your system clock" "$LINENO" 5 +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. +# By default was `s,x,x', remove it if useless. +ac_script='s/[\\$]/&&/g;s/;s,x,x,$//' +program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"` + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +if test x"${MISSING+set}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;; + *) + MISSING="\${SHELL} $am_aux_dir/missing" ;; + esac +fi +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`missing' script is too old or missing" >&5 +$as_echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +if test x"${install_sh}" != xset; then + case $am_aux_dir in + *\ * | *\ *) + install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;; + *) + install_sh="\${SHELL} $am_aux_dir/install-sh" + esac +fi + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_STRIP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5 +$as_echo "$STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5 +$as_echo "$ac_ct_STRIP" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s" + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5 +$as_echo_n "checking for a thread-safe mkdir -p... " >&6; } +if test -z "$MKDIR_P"; then + if test "${ac_cv_path_mkdir+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in mkdir gmkdir; do + for ac_exec_ext in '' $ac_executable_extensions; do + { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; } || continue + case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #( + 'mkdir (GNU coreutils) '* | \ + 'mkdir (coreutils) '* | \ + 'mkdir (fileutils) '4.1*) + ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext + break 3;; + esac + done + done + done +IFS=$as_save_IFS + +fi + + test -d ./--version && rmdir ./--version + if test "${ac_cv_path_mkdir+set}" = set; then + MKDIR_P="$ac_cv_path_mkdir -p" + else + # As a last resort, use the slow shell script. Don't cache a + # value for MKDIR_P within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + MKDIR_P="$ac_install_sh -d" + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5 +$as_echo "$MKDIR_P" >&6; } + +mkdir_p="$MKDIR_P" +case $mkdir_p in + [\\/$]* | ?:[\\/]*) ;; + */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;; +esac + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_AWK+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AWK="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5 +$as_echo "$AWK" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; } +set x ${MAKE-make} +ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + SET_MAKE= +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +if test "`cd $srcdir && pwd`" != "`pwd`"; then + # Use -I$(srcdir) only when $(srcdir) != ., so that make's output + # is not polluted with repeated "-I." + am__isrc=' -I$(srcdir)' + # test to see if srcdir already configured + if test -f $srcdir/config.status; then + as_fn_error "source directory already configured; run \"make distclean\" there first" "$LINENO" 5 + fi +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE='pcem' + VERSION='v10.1' + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +# Always define AMTAR for backward compatibility. + +AMTAR=${AMTAR-"${am_missing_run}tar"} + +am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' + + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5 +$as_echo "$CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5 +$as_echo "$ac_ct_CC" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "no acceptable C compiler found in \$PATH +See \`config.log' for more details." "$LINENO" 5; } + +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5 +$as_echo_n "checking whether the C compiler works... " >&6; } +ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` + +# The possible output files: +ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*" + +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { { ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi +if test -z "$ac_file"; then : + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +$as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +{ as_fn_set_status 77 +as_fn_error "C compiler cannot create executables +See \`config.log' for more details." "$LINENO" 5; }; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5 +$as_echo_n "checking for C compiler default output file name... " >&6; } +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5 +$as_echo "$ac_file" >&6; } +ac_exeext=$ac_cv_exeext + +rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5 +$as_echo_n "checking for suffix of executables... " >&6; } +if { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." "$LINENO" 5; } +fi +rm -f conftest conftest$ac_cv_exeext +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5 +$as_echo "$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +int +main () +{ +FILE *f = fopen ("conftest.out", "w"); + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +ac_clean_files="$ac_clean_files conftest.out" +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5 +$as_echo_n "checking whether we are cross compiling... " >&6; } +if test "$cross_compiling" != yes; then + { { ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } + if { ac_try='./conftest$ac_cv_exeext' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." "$LINENO" 5; } + fi + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5 +$as_echo "$cross_compiling" >&6; } + +rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out +ac_clean_files=$ac_clean_files_save +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5 +$as_echo_n "checking for suffix of object files... " >&6; } +if test "${ac_cv_objext+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { { ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; then : + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + $as_echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5 +$as_echo "$as_me: error: in \`$ac_pwd':" >&2;} +as_fn_error "cannot compute suffix of object files: cannot compile +See \`config.log' for more details." "$LINENO" 5; } +fi +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5 +$as_echo "$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5 +$as_echo_n "checking whether we are using the GNU C compiler... " >&6; } +if test "${ac_cv_c_compiler_gnu+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5 +$as_echo "$ac_cv_c_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GCC=yes +else + GCC= +fi +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5 +$as_echo_n "checking whether $CC accepts -g... " >&6; } +if test "${ac_cv_prog_cc_g+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +else + CFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + +else + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5 +$as_echo "$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5 +$as_echo_n "checking for $CC option to accept ISO C89... " >&6; } +if test "${ac_cv_prog_cc_c89+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + if ac_fn_c_try_compile "$LINENO"; then : + ac_cv_prog_cc_c89=$ac_arg +fi +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5 +$as_echo "none needed" >&6; } ;; + xno) + { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5 +$as_echo "unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5 +$as_echo "$ac_cv_prog_cc_c89" >&6; } ;; +esac +if test "x$ac_cv_prog_cc_c89" != xno; then : + +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +DEPDIR="${am__leading_dot}deps" + +ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo this is the am__doit target +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5 +$as_echo_n "checking for style of include used by $am_make... " >&6; } +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# Ignore all kinds of additional output from `make'. +case `$am_make -s -f confmf 2> /dev/null` in #( +*the\ am__doit\ target*) + am__include=include + am__quote= + _am_result=GNU + ;; +esac +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + case `$am_make -s -f confmf 2> /dev/null` in #( + *the\ am__doit\ target*) + am__include=.include + am__quote="\"" + _am_result=BSD + ;; + esac +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5 +$as_echo "$_am_result" >&6; } +rm -f confinc confmf + +# Check whether --enable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then : + enableval=$enable_dependency_tracking; +fi + +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi + if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + +depcc="$CC" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if test "${am_cv_CC_dependencies_compiler_type+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CC_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CC_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CC_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; } +CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then + am__fastdepCC_TRUE= + am__fastdepCC_FALSE='#' +else + am__fastdepCC_TRUE='#' + am__fastdepCC_FALSE= +fi + + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_CXX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5 +$as_echo "$CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5 +$as_echo "$ac_ct_CXX" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5 +$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5 +set X $ac_compile +ac_compiler=$2 +for ac_option in --version -v -V -qversion; do + { { ac_try="$ac_compiler $ac_option >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_compiler $ac_option >&5") 2>conftest.err + ac_status=$? + if test -s conftest.err; then + sed '10a\ +... rest of stderr output deleted ... + 10q' conftest.err >conftest.er1 + cat conftest.er1 >&5 + fi + rm -f conftest.er1 conftest.err + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } +done + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5 +$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; } +if test "${ac_cv_cxx_compiler_gnu+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_compiler_gnu=yes +else + ac_compiler_gnu=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5 +$as_echo "$ac_cv_cxx_compiler_gnu" >&6; } +if test $ac_compiler_gnu = yes; then + GXX=yes +else + GXX= +fi +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5 +$as_echo_n "checking whether $CXX accepts -g... " >&6; } +if test "${ac_cv_prog_cxx_g+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +else + CXXFLAGS="" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + +else + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_cxx_try_compile "$LINENO"; then : + ac_cv_prog_cxx_g=yes +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5 +$as_echo "$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +depcc="$CXX" am_compiler_list= + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5 +$as_echo_n "checking dependency style of $depcc... " >&6; } +if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CXX_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + am__universal=false + case " $depcc " in #( + *\ -arch\ *\ -arch\ *) am__universal=true ;; + esac + + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. Also, some Intel + # versions had trouble with output in subdirs + am__obj=sub/conftest.${OBJEXT-o} + am__minus_obj="-o $am__obj" + case $depmode in + gcc) + # This depmode causes a compiler race in universal mode. + test "$am__universal" = false || continue + ;; + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + msvisualcpp | msvcmsys) + # This compiler won't grok `-c -o', but also, the minuso test has + # not run yet. These depmodes are late enough in the game, and + # so weak that their functioning should not be impacted. + am__obj=conftest.${OBJEXT-o} + am__minus_obj= + ;; + none) break ;; + esac + if depmode=$depmode \ + source=sub/conftest.c object=$am__obj \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep $am__obj sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CXX_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CXX_dependencies_compiler_type=none +fi + +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5 +$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; } +CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type + + if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then + am__fastdepCXX_TRUE= + am__fastdepCXX_FALSE='#' +else + am__fastdepCXX_TRUE='#' + am__fastdepCXX_FALSE= +fi + + +if test "x$CC" != xcc; then + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC and cc understand -c and -o together" >&5 +$as_echo_n "checking whether $CC and cc understand -c and -o together... " >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether cc understands -c and -o together" >&5 +$as_echo_n "checking whether cc understands -c and -o together... " >&6; } +fi +set dummy $CC; ac_cc=`$as_echo "$2" | + sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'` +if { as_var=ac_cv_prog_cc_${ac_cc}_c_o; eval "test \"\${$as_var+set}\" = set"; }; then : + $as_echo_n "(cached) " >&6 +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +# Make sure it works both with $CC and with simple cc. +# We do the test twice because some compilers refuse to overwrite an +# existing .o file with -o, though they will create one. +ac_try='$CC -c conftest.$ac_ext -o conftest2.$ac_objext >&5' +rm -f conftest2.* +if { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && + test -f conftest2.$ac_objext && { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; +then + eval ac_cv_prog_cc_${ac_cc}_c_o=yes + if test "x$CC" != xcc; then + # Test first that cc exists at all. + if { ac_try='cc -c conftest.$ac_ext >&5' + { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; }; then + ac_try='cc -c conftest.$ac_ext -o conftest2.$ac_objext >&5' + rm -f conftest2.* + if { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; } && + test -f conftest2.$ac_objext && { { case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\"" +$as_echo "$ac_try_echo"; } >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5 + test $ac_status = 0; }; + then + # cc works too. + : + else + # cc exists but doesn't like -o. + eval ac_cv_prog_cc_${ac_cc}_c_o=no + fi + fi + fi +else + eval ac_cv_prog_cc_${ac_cc}_c_o=no +fi +rm -f core conftest* + +fi +if eval test \$ac_cv_prog_cc_${ac_cc}_c_o = yes; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + +$as_echo "#define NO_MINUS_C_MINUS_O 1" >>confdefs.h + +fi + +# FIXME: we rely on the cache variable name because +# there is no other way. +set dummy $CC +am_cc=`echo $2 | sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'` +eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o +if test "$am_t" != yes; then + # Losing compiler, so override with the script. + # FIXME: It is wrong to rewrite CC. + # But if we don't then we get into trouble of one sort or another. + # A longer-term fix would be to have automake use am__CC in this case, + # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)" + CC="$am_aux_dir/compile $CC" +fi + + + + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable debugging" >&5 +$as_echo_n "checking whether to enable debugging... " >&6; } +# Check whether --enable-debug was given. +if test "${enable_debug+set}" = set; then : + enableval=$enable_debug; +fi + +if test "$enable_debug" = "yes"; then + CFLAGS="-Wall -O0 -g -D_DEBUG" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } +else + CFLAGS="-O3" + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for cpu" >&5 +$as_echo_n "checking for cpu... " >&6; } +case "${host_cpu}" in + i?86) + CPU=i386 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${host_cpu}" >&5 +$as_echo "${host_cpu}" >&6; } + ;; + x86_64) + CPU=x86_64 + { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${host_cpu}" >&5 +$as_echo "${host_cpu}" >&6; } + ;; + *) + as_fn_error "Unsupported CPU." "$LINENO" 5 + ;; +esac + + if test "$CPU" = "i386"; then + CPU_I386_TRUE= + CPU_I386_FALSE='#' +else + CPU_I386_TRUE='#' + CPU_I386_FALSE= +fi + + if test "$CPU" = "x86_64"; then + CPU_X86_64_TRUE= + CPU_X86_64_FALSE='#' +else + CPU_X86_64_TRUE='#' + CPU_X86_64_FALSE= +fi + + +#AC_MSG_CHECKING([for libz]) +#AX_CHECK_ZLIB + + if test "$OS" = "win"; then + OS_WIN_TRUE= + OS_WIN_FALSE='#' +else + OS_WIN_TRUE='#' + OS_WIN_FALSE= +fi + + if test "$OS" = "linux"; then + OS_LINUX_TRUE= + OS_LINUX_FALSE='#' +else + OS_LINUX_TRUE='#' + OS_LINUX_FALSE= +fi + + +# Do not run test for Allegro with Win32/MinGW version, as binary builds have +# `allegro-config' missing. +# NOTE: For the following Autoconf macro to be supported, you need to extract +# allegro.m4 from the DOS/Windows Allegro sources (the file is contained +# in `misc') and copy it to this directory or MSYS's `/share/aclocal'. +if test "$OS" != "win"; then + + + +# Check whether --with-allegro-prefix was given. +if test "${with_allegro_prefix+set}" = set; then : + withval=$with_allegro_prefix; ALLEGRO_CONFIG_prefix="$withval" +else + ALLEGRO_CONFIG_prefix="" +fi + + +# Check whether --with-allegro-exec-prefix was given. +if test "${with_allegro_exec_prefix+set}" = set; then : + withval=$with_allegro_exec_prefix; ALLEGRO_CONFIG_exec_prefix="$withval" +else + ALLEGRO_CONFIG_exec_prefix="" +fi + +# Check whether --enable-allegrotest was given. +if test "${enable_allegrotest+set}" = set; then : + enableval=$enable_allegrotest; +else + enable_allegrotest=yes +fi + + + if test x$ALLEGRO_CONFIG_exec_prefix != x ; then + ALLEGRO_CONFIG_args="$ALLEGRO_CONFIG_args --exec-prefix=$ALLEGRO_CONFIG_exec_prefix" + if test x${ALLEGRO_CONFIG+set} != xset ; then + ALLEGRO_CONFIG=$ALLEGRO_CONFIG_exec_prefix/bin/allegro-config + fi + fi + if test x$ALLEGRO_CONFIG_prefix != x ; then + ALLEGRO_CONFIG_args="$ALLEGRO_CONFIG_args --prefix=$ALLEGRO_CONFIG_prefix" + if test x${ALLEGRO_CONFIG+set} != xset ; then + ALLEGRO_CONFIG=$ALLEGRO_CONFIG_prefix/bin/allegro-config + fi + fi + + # Extract the first word of "allegro-config", so it can be a program name with args. +set dummy allegro-config; ac_word=$2 +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5 +$as_echo_n "checking for $ac_word... " >&6; } +if test "${ac_cv_path_ALLEGRO_CONFIG+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + case $ALLEGRO_CONFIG in + [\\/]* | ?:[\\/]*) + ac_cv_path_ALLEGRO_CONFIG="$ALLEGRO_CONFIG" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_ALLEGRO_CONFIG="$as_dir/$ac_word$ac_exec_ext" + $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done + done +IFS=$as_save_IFS + + test -z "$ac_cv_path_ALLEGRO_CONFIG" && ac_cv_path_ALLEGRO_CONFIG="no" + ;; +esac +fi +ALLEGRO_CONFIG=$ac_cv_path_ALLEGRO_CONFIG +if test -n "$ALLEGRO_CONFIG"; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ALLEGRO_CONFIG" >&5 +$as_echo "$ALLEGRO_CONFIG" >&6; } +else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } +fi + + + min_allegro_version=4.0.0 + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Allegro - version >= $min_allegro_version" >&5 +$as_echo_n "checking for Allegro - version >= $min_allegro_version... " >&6; } + no_allegro="" + if test "$ALLEGRO_CONFIG" = "no" ; then + no_allegro=yes + else + allegro_CFLAGS=`$ALLEGRO_CONFIG $ALLEGRO_CONFIG_args --cflags` + allegro_LIBS=`$ALLEGRO_CONFIG $ALLEGRO_CONFIG_args --libs` + ALLEGRO_CONFIG_major_version=`$ALLEGRO_CONFIG $ALLEGRO_CONFIG_args --version | \ + sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\1/'` + ALLEGRO_CONFIG_minor_version=`$ALLEGRO_CONFIG $ALLEGRO_CONFIG_args --version | \ + sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\2/'` + ALLEGRO_CONFIG_micro_version=`$ALLEGRO_CONFIG $ALLEGRO_CONFIG_args --version | \ + sed 's/\([0-9]*\).\([0-9]*\).\([0-9]*\)/\3/'` + if test "x$enable_allegrotest" = "xyes" ; then + ac_save_CFLAGS="$CFLAGS" + ac_save_LIBS="$LIBS" + CFLAGS="$CFLAGS $allegro_CFLAGS" + LIBS="$allegro_LIBS $LIBS" + rm -f conf.allegrotest + if test "$cross_compiling" = yes; then : + echo $ac_n "cross compiling; assumed OK... $ac_c" +else + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include +#include +#include + +int +main() +{ + int allegro_major_version, allegro_minor_version, allegro_micro_version; + int major, minor, micro; + char *tmp_version; + int tmp_int_version; + + system("touch conf.allegrotest"); + + /* Capture allegro-config output via autoconf/configure variables */ + /* HP/UX 9 (%@#!) writes to sscanf strings */ + tmp_version = (char *)strdup("$min_allegro_version"); + if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { + printf("%s, bad version string from allegro-config\n", "$min_allegro_version"); + free(tmp_version); + exit(1); + } + free(tmp_version); + + /* Capture the version information from the header files */ + allegro_major_version = ALLEGRO_VERSION; + allegro_minor_version = ALLEGRO_SUB_VERSION; + allegro_micro_version = ALLEGRO_WIP_VERSION; + + /* Compare allegro-config output to the Allegro headers */ + if ((allegro_major_version != $ALLEGRO_CONFIG_major_version) || + (allegro_minor_version != $ALLEGRO_CONFIG_minor_version)) + + { + printf("*** Allegro header files (version %d.%d.%d) do not match\n", + allegro_major_version, allegro_minor_version, allegro_micro_version); + printf("*** allegro-config (version %d.%d.%d)\n", + $ALLEGRO_CONFIG_major_version, $ALLEGRO_CONFIG_minor_version, $ALLEGRO_CONFIG_micro_version); + return 1; + } +/* Compare the headers to the library to make sure we match */ + /* Less than ideal -- doesn't provide us with return value feedback, + * only exits if there's a serious mismatch between header and library. + */ + /* TODO: + * This doesnt work! + */ + /* ALLEGRO_TEST_VERSION; */ + + /* Test that the library is greater than our minimum version */ + if (($ALLEGRO_CONFIG_major_version > major) || + (($ALLEGRO_CONFIG_major_version == major) && ($ALLEGRO_CONFIG_minor_version > minor)) || + (($ALLEGRO_CONFIG_major_version == major) && ($ALLEGRO_CONFIG_minor_version == minor) && + ($ALLEGRO_CONFIG_micro_version >= micro))) + { + return 0; + } + else + { + printf("\n*** An old version of Allegro (%d.%d.%d) was found.\n", + allegro_major_version, allegro_minor_version, allegro_micro_version); + printf("*** You need a version of Allegro newer than %d.%d.%d. The latest version of\n", + major, minor, micro); + printf("*** Allegro is always available from http://alleg.sf.net.\n"); + printf("***\n"); + printf("*** If you have already installed a sufficiently new version, this error\n"); + printf("*** probably means that the wrong copy of the allegro-config shell script is\n"); + printf("*** being found. The easiest way to fix this is to remove the old version\n"); + printf("*** of Allegro, but you can also set the ALLEGRO_CONFIG environment to point to the\n"); + printf("*** correct copy of allegro-config. (In this case, you will have to\n"); + printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); + printf("*** so that the correct libraries are found at run-time))\n"); + } + return 1; +} END_OF_MAIN() + +_ACEOF +if ac_fn_c_try_run "$LINENO"; then : + +else + no_allegro=yes +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \ + conftest.$ac_objext conftest.beam conftest.$ac_ext +fi + + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + + if test "x$no_allegro" = x ; then + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes (version $ALLEGRO_CONFIG_major_version.$ALLEGRO_CONFIG_minor_version.$ALLEGRO_CONFIG_micro_version)" >&5 +$as_echo "yes (version $ALLEGRO_CONFIG_major_version.$ALLEGRO_CONFIG_minor_version.$ALLEGRO_CONFIG_micro_version)" >&6; } + : + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; } + if test "$ALLEGRO_CONFIG" = "no" ; then + echo "*** The allegro-config script installed by Allegro could not be found" + echo "*** If Allegro was installed in PREFIX, make sure PREFIX/bin is in" + echo "*** your path, or set the ALLEGRO_CONFIG environment variable to the" + echo "*** full path to allegro-config." + else + if test -f conf.allegrotest ; then + : + else + echo "*** Could not run Allegro test program, checking why..." + CFLAGS="$CFLAGS $allegro_CFLAGS" + LIBS="$LIBS $allegro_LIBS" + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +#include +#include + +int +main () +{ + ALLEGRO_TEST_VERSION; return 0; + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + echo "*** The test program compiled, but did not run. This usually means" + echo "*** that the run-time linker is not finding Allegro or finding the wrong" + echo "*** version of Allegro. If it is not finding Allegro, you'll need to set your" + echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" + echo "*** to the installed location Also, make sure you have run ldconfig if that" + echo "*** is required on your system" + echo "***" + echo "*** If you have an old version installed, it is best to remove it, although" + echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" +else + echo "*** The test program failed to compile or link. See the file config.log for the" + echo "*** exact error that occured. This usually means Allegro was incorrectly installed" + echo "*** or that you have moved Allegro since it was installed. In the latter case, you" + echo "*** may want to edit the allegro-config script: $ALLEGRO_CONFIG" +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext + CFLAGS="$ac_save_CFLAGS" + LIBS="$ac_save_LIBS" + fi + fi + + allegro_CFLAGS="" + allegro_LIBS="" + as_fn_error "building PCem requires Allegro to be installed" "$LINENO" 5 + fi + + + rm -f conf.allegrotest + +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for alGetError in -lopenal" >&5 +$as_echo_n "checking for alGetError in -lopenal... " >&6; } +if test "${ac_cv_lib_openal_alGetError+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lopenal $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char alGetError (); +int +main () +{ +return alGetError (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_openal_alGetError=yes +else + ac_cv_lib_openal_alGetError=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_openal_alGetError" >&5 +$as_echo "$ac_cv_lib_openal_alGetError" >&6; } +if test "x$ac_cv_lib_openal_alGetError" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBOPENAL 1 +_ACEOF + + LIBS="-lopenal $LIBS" + +else + \ + echo "You need to install the OpenAL library." + exit -1 +fi + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for alutInit in -lalut" >&5 +$as_echo_n "checking for alutInit in -lalut... " >&6; } +if test "${ac_cv_lib_alut_alutInit+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lalut $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char alutInit (); +int +main () +{ +return alutInit (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_alut_alutInit=yes +else + ac_cv_lib_alut_alutInit=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_alut_alutInit" >&5 +$as_echo "$ac_cv_lib_alut_alutInit" >&6; } +if test "x$ac_cv_lib_alut_alutInit" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBALUT 1 +_ACEOF + + LIBS="-lalut $LIBS" + +else + \ + echo "You need to install the ALUT library." + exit -1 +fi + + +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5 +$as_echo_n "checking for pthread_create in -lpthread... " >&6; } +if test "${ac_cv_lib_pthread_pthread_create+set}" = set; then : + $as_echo_n "(cached) " >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lpthread $LIBS" +cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char pthread_create (); +int +main () +{ +return pthread_create (); + ; + return 0; +} +_ACEOF +if ac_fn_c_try_link "$LINENO"; then : + ac_cv_lib_pthread_pthread_create=yes +else + ac_cv_lib_pthread_pthread_create=no +fi +rm -f core conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5 +$as_echo "$ac_cv_lib_pthread_pthread_create" >&6; } +if test "x$ac_cv_lib_pthread_pthread_create" = x""yes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBPTHREAD 1 +_ACEOF + + LIBS="-lpthread $LIBS" + +fi + + +ac_config_files="$ac_config_files Makefile src/Makefile" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5 +$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #( + *) { eval $ac_var=; unset $ac_var;} ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes: double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \. + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + test "x$cache_file" != "x/dev/null" && + { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5 +$as_echo "$as_me: updating cache $cache_file" >&6;} + cat confcache >$cache_file + else + { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5 +$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +ac_script=' +:mline +/\\$/{ + N + s,\\\n,, + b mline +} +t clear +:clear +s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g +t quote +s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g +t quote +b any +:quote +s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g +s/\[/\\&/g +s/\]/\\&/g +s/\$/$$/g +H +:any +${ + g + s/^\n// + s/\n/ /g + p +} +' +DEFS=`sed -n "$ac_script" confdefs.h` + + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`$as_echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext" + as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + if test -n "$EXEEXT"; then + am__EXEEXT_TRUE= + am__EXEEXT_FALSE='#' +else + am__EXEEXT_TRUE='#' + am__EXEEXT_FALSE= +fi + +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + as_fn_error "conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then + as_fn_error "conditional \"am__fastdepCC\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + as_fn_error "conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${CPU_I386_TRUE}" && test -z "${CPU_I386_FALSE}"; then + as_fn_error "conditional \"CPU_I386\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${CPU_X86_64_TRUE}" && test -z "${CPU_X86_64_FALSE}"; then + as_fn_error "conditional \"CPU_X86_64\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${OS_WIN_TRUE}" && test -z "${OS_WIN_FALSE}"; then + as_fn_error "conditional \"OS_WIN\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi +if test -z "${OS_LINUX_TRUE}" && test -z "${OS_LINUX_FALSE}"; then + as_fn_error "conditional \"OS_LINUX\" was never defined. +Usually this means the macro was only invoked conditionally." "$LINENO" 5 +fi + +: ${CONFIG_STATUS=./config.status} +ac_write_fail=0 +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5 +$as_echo "$as_me: creating $CONFIG_STATUS" >&6;} +as_write_fail=0 +cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1 +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false + +SHELL=\${CONFIG_SHELL-$SHELL} +export SHELL +_ASEOF +cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1 +## -------------------- ## +## M4sh Initialization. ## +## -------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then : + emulate sh + NULLCMD=: + # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in #( + *posix*) : + set -o posix ;; #( + *) : + ;; +esac +fi + + +as_nl=' +' +export as_nl +# Printing a long string crashes Solaris 7 /usr/bin/printf. +as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\' +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo +as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo +# Prefer a ksh shell builtin over an external printf program on Solaris, +# but without wasting forks for bash or zsh. +if test -z "$BASH_VERSION$ZSH_VERSION" \ + && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='print -r --' + as_echo_n='print -rn --' +elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then + as_echo='printf %s\n' + as_echo_n='printf %s' +else + if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then + as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"' + as_echo_n='/usr/ucb/echo -n' + else + as_echo_body='eval expr "X$1" : "X\\(.*\\)"' + as_echo_n_body='eval + arg=$1; + case $arg in #( + *"$as_nl"*) + expr "X$arg" : "X\\(.*\\)$as_nl"; + arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;; + esac; + expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl" + ' + export as_echo_n_body + as_echo_n='sh -c $as_echo_n_body as_echo' + fi + export as_echo_body + as_echo='sh -c $as_echo_body as_echo' +fi + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + PATH_SEPARATOR=: + (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && { + (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 || + PATH_SEPARATOR=';' + } +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in #(( + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break + done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + exit 1 +fi + +# Unset variables that we do not need and which cause bugs (e.g. in +# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1" +# suppresses any "Segmentation fault" message there. '((' could +# trigger a bug in pdksh 5.2.14. +for as_var in BASH_ENV ENV MAIL MAILPATH +do eval test x\${$as_var+set} = xset \ + && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || : +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +LC_ALL=C +export LC_ALL +LANGUAGE=C +export LANGUAGE + +# CDPATH. +(unset CDPATH) >/dev/null 2>&1 && unset CDPATH + + +# as_fn_error ERROR [LINENO LOG_FD] +# --------------------------------- +# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are +# provided, also output the error to LOG_FD, referencing LINENO. Then exit the +# script with status $?, using 1 if that was 0. +as_fn_error () +{ + as_status=$?; test $as_status -eq 0 && as_status=1 + if test "$3"; then + as_lineno=${as_lineno-"$2"} as_lineno_stack=as_lineno_stack=$as_lineno_stack + $as_echo "$as_me:${as_lineno-$LINENO}: error: $1" >&$3 + fi + $as_echo "$as_me: error: $1" >&2 + as_fn_exit $as_status +} # as_fn_error + + +# as_fn_set_status STATUS +# ----------------------- +# Set $? to STATUS, without forking. +as_fn_set_status () +{ + return $1 +} # as_fn_set_status + +# as_fn_exit STATUS +# ----------------- +# Exit the shell with STATUS, even in a "trap 0" or "set -e" context. +as_fn_exit () +{ + set +e + as_fn_set_status $1 + exit $1 +} # as_fn_exit + +# as_fn_unset VAR +# --------------- +# Portably unset VAR. +as_fn_unset () +{ + { eval $1=; unset $1;} +} +as_unset=as_fn_unset +# as_fn_append VAR VALUE +# ---------------------- +# Append the text in VALUE to the end of the definition contained in VAR. Take +# advantage of any shell optimizations that allow amortized linear growth over +# repeated appends, instead of the typical quadratic growth present in naive +# implementations. +if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then : + eval 'as_fn_append () + { + eval $1+=\$2 + }' +else + as_fn_append () + { + eval $1=\$$1\$2 + } +fi # as_fn_append + +# as_fn_arith ARG... +# ------------------ +# Perform arithmetic evaluation on the ARGs, and store the result in the +# global $as_val. Take advantage of shells that can avoid forks. The arguments +# must be portable across $(()) and expr. +if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then : + eval 'as_fn_arith () + { + as_val=$(( $* )) + }' +else + as_fn_arith () + { + as_val=`expr "$@" || test $? -eq 1` + } +fi # as_fn_arith + + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in #((((( +-n*) + case `echo 'xy\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + xy) ECHO_C='\c';; + *) echo `echo ksh88 bug on AIX 6.1` > /dev/null + ECHO_T=' ';; + esac;; +*) + ECHO_N='-n';; +esac + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir 2>/dev/null +fi +if (echo >conf$$.file) 2>/dev/null; then + if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' + elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln + else + as_ln_s='cp -p' + fi +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + + +# as_fn_mkdir_p +# ------------- +# Create "$as_dir" as a directory, including parents if necessary. +as_fn_mkdir_p () +{ + + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || eval $as_mkdir_p || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || as_fn_error "cannot create directory $as_dir" + + +} # as_fn_mkdir_p +if mkdir -p . 2>/dev/null; then + as_mkdir_p='mkdir -p "$as_dir"' +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in #( + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in #(( + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 +## ----------------------------------- ## +## Main body of $CONFIG_STATUS script. ## +## ----------------------------------- ## +_ASEOF +test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1 + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# Save the log message, to keep $0 and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by PCem $as_me v10.1, which was +generated by GNU Autoconf 2.65. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +case $ac_config_files in *" +"*) set x $ac_config_files; shift; ac_config_files=$*;; +esac + + + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# Files that config.status was made for. +config_files="$ac_config_files" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +ac_cs_usage="\ +\`$as_me' instantiates files and other configuration actions +from templates according to the current configuration. Unless the files +and actions are specified as TAGs, all are instantiated by default. + +Usage: $0 [OPTION]... [TAG]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + --config print configuration, then exit + -q, --quiet, --silent + do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + +Configuration files: +$config_files + +Configuration commands: +$config_commands + +Report bugs to >." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" +ac_cs_version="\\ +PCem config.status v10.1 +configured by $0, generated by GNU Autoconf 2.65, + with options \\"\$ac_cs_config\\" + +Copyright (C) 2009 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +MKDIR_P='$MKDIR_P' +AWK='$AWK' +test -n "\$AWK" || AWK=awk +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# The default lists apply if the user does not specify any file. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + $as_echo "$ac_cs_version"; exit ;; + --config | --confi | --conf | --con | --co | --c ) + $as_echo "$ac_cs_config"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + case $ac_optarg in + *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + as_fn_append CONFIG_FILES " '$ac_optarg'" + ac_need_defaults=false;; + --he | --h | --help | --hel | -h ) + $as_echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) as_fn_error "unrecognized option: \`$1' +Try \`$0 --help' for more information." ;; + + *) as_fn_append ac_config_targets " $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +if \$ac_cs_recheck; then + set X '$SHELL' '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion + shift + \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6 + CONFIG_SHELL='$SHELL' + export CONFIG_SHELL + exec "\$@" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + $as_echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +# +# INIT-COMMANDS +# +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "src/Makefile") CONFIG_FILES="$CONFIG_FILES src/Makefile" ;; + + *) as_fn_error "invalid argument: \`$ac_config_target'" "$LINENO" 5;; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +' 0 + trap 'as_fn_exit 1' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || as_fn_error "cannot create a temporary directory in ." "$LINENO" 5 + +# Set up the scripts for CONFIG_FILES section. +# No need to generate them if there are no CONFIG_FILES. +# This happens for instance with `./config.status config.h'. +if test -n "$CONFIG_FILES"; then + + +ac_cr=`echo X | tr X '\015'` +# On cygwin, bash can eat \r inside `` if the user requested igncr. +# But we know of no other shell where ac_cr would be empty at this +# point, so we can use a bashism as a fallback. +if test "x$ac_cr" = x; then + eval ac_cr=\$\'\\r\' +fi +ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' /dev/null` +if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then + ac_cs_awk_cr='\r' +else + ac_cs_awk_cr=$ac_cr +fi + +echo 'BEGIN {' >"$tmp/subs1.awk" && +_ACEOF + + +{ + echo "cat >conf$$subs.awk <<_ACEOF" && + echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' && + echo "_ACEOF" +} >conf$$subs.sh || + as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 +ac_delim_num=`echo "$ac_subst_vars" | grep -c '$'` +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + . ./conf$$subs.sh || + as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 + + ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X` + if test $ac_delim_n = $ac_delim_num; then + break + elif $ac_last_try; then + as_fn_error "could not make $CONFIG_STATUS" "$LINENO" 5 + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done +rm -f conf$$subs.sh + +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +cat >>"\$tmp/subs1.awk" <<\\_ACAWK && +_ACEOF +sed -n ' +h +s/^/S["/; s/!.*/"]=/ +p +g +s/^[^!]*!// +:repl +t repl +s/'"$ac_delim"'$// +t delim +:nl +h +s/\(.\{148\}\)..*/\1/ +t more1 +s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/ +p +n +b repl +:more1 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t nl +:delim +h +s/\(.\{148\}\)..*/\1/ +t more2 +s/["\\]/\\&/g; s/^/"/; s/$/"/ +p +b +:more2 +s/["\\]/\\&/g; s/^/"/; s/$/"\\/ +p +g +s/.\{148\}// +t delim +' >$CONFIG_STATUS || ac_write_fail=1 +rm -f conf$$subs.awk +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +_ACAWK +cat >>"\$tmp/subs1.awk" <<_ACAWK && + for (key in S) S_is_set[key] = 1 + FS = "" + +} +{ + line = $ 0 + nfields = split(line, field, "@") + substed = 0 + len = length(field[1]) + for (i = 2; i < nfields; i++) { + key = field[i] + keylen = length(key) + if (S_is_set[key]) { + value = S[key] + line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3) + len += length(value) + length(field[++i]) + substed = 1 + } else + len += 1 + keylen + } + + print line +} + +_ACAWK +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then + sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g" +else + cat +fi < "$tmp/subs1.awk" > "$tmp/subs.awk" \ + || as_fn_error "could not setup config files machinery" "$LINENO" 5 +_ACEOF + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/ +s/:*\${srcdir}:*/:/ +s/:*@srcdir@:*/:/ +s/^\([^=]*=[ ]*\):*/\1/ +s/:*$// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +fi # test -n "$CONFIG_FILES" + + +eval set X " :F $CONFIG_FILES :C $CONFIG_COMMANDS" +shift +for ac_tag +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) as_fn_error "invalid tag \`$ac_tag'" "$LINENO" 5;; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + as_fn_error "cannot find input file: \`$ac_f'" "$LINENO" 5;; + esac + case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac + as_fn_append ac_file_inputs " '$ac_f'" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input='Generated from '` + $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g' + `' by configure.' + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5 +$as_echo "$as_me: creating $ac_file" >&6;} + fi + # Neutralize special characters interpreted by sed in replacement strings. + case $configure_input in #( + *\&* | *\|* | *\\* ) + ac_sed_conf_input=`$as_echo "$configure_input" | + sed 's/[\\\\&|]/\\\\&/g'`;; #( + *) ac_sed_conf_input=$configure_input;; + esac + + case $ac_tag in + *:-:* | *:-) cat >"$tmp/stdin" \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 ;; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir="$ac_dir"; as_fn_mkdir_p + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac + ac_MKDIR_P=$MKDIR_P + case $MKDIR_P in + [\\/$]* | ?:[\\/]* ) ;; + */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= +ac_sed_dataroot=' +/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p' +case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 +ac_sed_extra="$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s|@configure_input@|$ac_sed_conf_input|;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@top_build_prefix@&$ac_top_build_prefix&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +s&@MKDIR_P@&$ac_MKDIR_P&;t t +$ac_datarootdir_hack +" +eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$tmp/subs.awk" >$tmp/out \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&5 +$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&2;} + + rm -f "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out" && rm -f "$tmp/out";; + *) rm -f "$ac_file" && mv "$tmp/out" "$ac_file";; + esac \ + || as_fn_error "could not create $ac_file" "$LINENO" 5 + ;; + + + :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5 +$as_echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || { + # Autoconf 2.62 quotes --file arguments for eval, but not when files + # are listed without --file. Let's play safe and only enable the eval + # if we detect the quoting. + case $CONFIG_FILES in + *\'*) eval set x "$CONFIG_FILES" ;; + *) set x $CONFIG_FILES ;; + esac + shift + for mf + do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # Grep'ing the whole file is not good either: AIX grep has a line + # limit of 2048, but all sed's we know have understand at least 4000. + if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then + dirpart=`$as_dirname -- "$mf" || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`$as_dirname -- "$file" || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| . 2>/dev/null || +$as_echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + as_dir=$dirpart/$fdir; as_fn_mkdir_p + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done + done +} + ;; + + esac +done # for ac_tag + + +as_fn_exit 0 +_ACEOF +ac_clean_files=$ac_clean_files_save + +test $ac_write_fail = 0 || + as_fn_error "write failure creating $CONFIG_STATUS" "$LINENO" 5 + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || as_fn_exit $? +fi +if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then + { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5 +$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;} +fi + diff --git a/configure.ac b/configure.ac new file mode 100644 index 000000000..388f3db76 --- /dev/null +++ b/configure.ac @@ -0,0 +1,69 @@ +# configure.ac for PCem +# + +AC_PREREQ([2.61]) +AC_INIT(PCem, v10.1, Tom Walker , pcem) + +AC_CANONICAL_HOST + +AM_INIT_AUTOMAKE +AC_PROG_CC +AC_PROG_CXX +AM_PROG_CC_C_O + + + +AC_MSG_CHECKING([whether to enable debugging]) +AC_ARG_ENABLE(debug, + AC_HELP_STRING([--enable-debug], [build debug executable])) +if test "$enable_debug" = "yes"; then + CFLAGS="-Wall -O0 -g -D_DEBUG" + AC_MSG_RESULT([yes]) +else + CFLAGS="-O3" + AC_MSG_RESULT([no]) +fi + +AC_MSG_CHECKING([for cpu]) +case "${host_cpu}" in + i?86) + CPU=i386 + AC_MSG_RESULT(${host_cpu}) + ;; + x86_64) + CPU=x86_64 + AC_MSG_RESULT(${host_cpu}) + ;; + *) + AC_MSG_ERROR([Unsupported CPU.]) + ;; +esac + +AM_CONDITIONAL(CPU_I386, test "$CPU" = "i386") +AM_CONDITIONAL(CPU_X86_64, test "$CPU" = "x86_64") + +#AC_MSG_CHECKING([for libz]) +#AX_CHECK_ZLIB + +AM_CONDITIONAL(OS_WIN, test "$OS" = "win") +AM_CONDITIONAL(OS_LINUX, test "$OS" = "linux") + +# Do not run test for Allegro with Win32/MinGW version, as binary builds have +# `allegro-config' missing. +# NOTE: For the following Autoconf macro to be supported, you need to extract +# allegro.m4 from the DOS/Windows Allegro sources (the file is contained +# in `misc') and copy it to this directory or MSYS's `/share/aclocal'. +if test "$OS" != "win"; then + AM_PATH_ALLEGRO(, , AC_MSG_ERROR(building PCem requires Allegro to be installed)) +fi + +AC_CHECK_LIB([openal], [alGetError], [], \ + [echo "You need to install the OpenAL library." + exit -1]) +AC_CHECK_LIB([alut], [alutInit], [], \ + [echo "You need to install the ALUT library." + exit -1]) + +AC_CHECK_LIB([pthread], [pthread_create]) + +AC_OUTPUT([Makefile src/Makefile]) diff --git a/depcomp b/depcomp new file mode 100644 index 000000000..b0ad20c05 --- /dev/null +++ b/depcomp @@ -0,0 +1 @@ +/usr/share/automake-1.11/depcomp \ No newline at end of file diff --git a/install-sh b/install-sh new file mode 100644 index 000000000..205f21c6b --- /dev/null +++ b/install-sh @@ -0,0 +1 @@ +/usr/share/automake-1.11/install-sh \ No newline at end of file diff --git a/missing b/missing new file mode 100644 index 000000000..20bc5b0ed --- /dev/null +++ b/missing @@ -0,0 +1 @@ +/usr/share/automake-1.11/missing \ No newline at end of file diff --git a/nvr/430vx.nvr b/nvr/430vx.nvr new file mode 100644 index 000000000..329a958f8 Binary files /dev/null and b/nvr/430vx.nvr differ diff --git a/nvr/440fx.nvr b/nvr/440fx.nvr new file mode 100644 index 000000000..3b82111ff Binary files /dev/null and b/nvr/440fx.nvr differ diff --git a/nvr/586mc1.nvr b/nvr/586mc1.nvr new file mode 100644 index 000000000..c2562cfa6 Binary files /dev/null and b/nvr/586mc1.nvr differ diff --git a/nvr/acer386.nvr b/nvr/acer386.nvr new file mode 100644 index 000000000..22bff6c1d Binary files /dev/null and b/nvr/acer386.nvr differ diff --git a/nvr/acerm3a.nvr b/nvr/acerm3a.nvr new file mode 100644 index 000000000..578c9f03f Binary files /dev/null and b/nvr/acerm3a.nvr differ diff --git a/nvr/acerv35n.nvr b/nvr/acerv35n.nvr new file mode 100644 index 000000000..a153ab477 Binary files /dev/null and b/nvr/acerv35n.nvr differ diff --git a/nvr/adgold.bin b/nvr/adgold.bin new file mode 100644 index 000000000..566bffc4a Binary files /dev/null and b/nvr/adgold.bin differ diff --git a/nvr/ami286.nvr b/nvr/ami286.nvr new file mode 100644 index 000000000..bfb993f2f Binary files /dev/null and b/nvr/ami286.nvr differ diff --git a/nvr/ami386.nvr b/nvr/ami386.nvr new file mode 100644 index 000000000..225630115 Binary files /dev/null and b/nvr/ami386.nvr differ diff --git a/nvr/ami486.nvr b/nvr/ami486.nvr new file mode 100644 index 000000000..705527986 Binary files /dev/null and b/nvr/ami486.nvr differ diff --git a/nvr/at.nvr b/nvr/at.nvr new file mode 100644 index 000000000..b5c94c19f Binary files /dev/null and b/nvr/at.nvr differ diff --git a/nvr/cmdpc30.nvr b/nvr/cmdpc30.nvr new file mode 100644 index 000000000..3e6551836 Binary files /dev/null and b/nvr/cmdpc30.nvr differ diff --git a/nvr/dell200.nvr b/nvr/dell200.nvr new file mode 100644 index 000000000..b16f18490 Binary files /dev/null and b/nvr/dell200.nvr differ diff --git a/nvr/deskpro386.nvr b/nvr/deskpro386.nvr new file mode 100644 index 000000000..95ab63b2d Binary files /dev/null and b/nvr/deskpro386.nvr differ diff --git a/nvr/dtk386.nvr b/nvr/dtk386.nvr new file mode 100644 index 000000000..c8450f5ab Binary files /dev/null and b/nvr/dtk386.nvr differ diff --git a/nvr/dtk486.nvr b/nvr/dtk486.nvr new file mode 100644 index 000000000..81762a976 Binary files /dev/null and b/nvr/dtk486.nvr differ diff --git a/nvr/endeavor.nvr b/nvr/endeavor.nvr new file mode 100644 index 000000000..a46ee6710 Binary files /dev/null and b/nvr/endeavor.nvr differ diff --git a/nvr/europc.nvr b/nvr/europc.nvr new file mode 100644 index 000000000..6757695ca Binary files /dev/null and b/nvr/europc.nvr differ diff --git a/nvr/hot-433.nvr b/nvr/hot-433.nvr new file mode 100644 index 000000000..104e7113c Binary files /dev/null and b/nvr/hot-433.nvr differ diff --git a/nvr/ibmps1_2011.nvr b/nvr/ibmps1_2011.nvr new file mode 100644 index 000000000..2029c7bf3 Binary files /dev/null and b/nvr/ibmps1_2011.nvr differ diff --git a/nvr/ibmps1_2121.nvr b/nvr/ibmps1_2121.nvr new file mode 100644 index 000000000..bea05137d Binary files /dev/null and b/nvr/ibmps1_2121.nvr differ diff --git a/nvr/kn97.nvr b/nvr/kn97.nvr new file mode 100644 index 000000000..bed158dc7 Binary files /dev/null and b/nvr/kn97.nvr differ diff --git a/nvr/mb500n.nvr b/nvr/mb500n.nvr new file mode 100644 index 000000000..7564c0cb9 Binary files /dev/null and b/nvr/mb500n.nvr differ diff --git a/nvr/megapc.nvr b/nvr/megapc.nvr new file mode 100644 index 000000000..389276174 Binary files /dev/null and b/nvr/megapc.nvr differ diff --git a/nvr/p54tp4xe.nvr b/nvr/p54tp4xe.nvr new file mode 100644 index 000000000..544bf8339 Binary files /dev/null and b/nvr/p54tp4xe.nvr differ diff --git a/nvr/p55t2p4.nvr b/nvr/p55t2p4.nvr new file mode 100644 index 000000000..2c9b27bff Binary files /dev/null and b/nvr/p55t2p4.nvr differ diff --git a/nvr/p55tp4n.nvr b/nvr/p55tp4n.nvr new file mode 100644 index 000000000..0c7ab65fc Binary files /dev/null and b/nvr/p55tp4n.nvr differ diff --git a/nvr/p55tp4xe.nvr b/nvr/p55tp4xe.nvr new file mode 100644 index 000000000..8f8a83106 Binary files /dev/null and b/nvr/p55tp4xe.nvr differ diff --git a/nvr/p55tvp4.nvr b/nvr/p55tvp4.nvr new file mode 100644 index 000000000..4e5b81d8f Binary files /dev/null and b/nvr/p55tvp4.nvr differ diff --git a/nvr/p55va.nvr b/nvr/p55va.nvr new file mode 100644 index 000000000..e3e32d6ab Binary files /dev/null and b/nvr/p55va.nvr differ diff --git a/nvr/p5sp4.nvr b/nvr/p5sp4.nvr new file mode 100644 index 000000000..e1d2c3a9b Binary files /dev/null and b/nvr/p5sp4.nvr differ diff --git a/nvr/pc1512.nvr b/nvr/pc1512.nvr new file mode 100644 index 000000000..b1f758b3e Binary files /dev/null and b/nvr/pc1512.nvr differ diff --git a/nvr/pc1640.nvr b/nvr/pc1640.nvr new file mode 100644 index 000000000..7171e74fc Binary files /dev/null and b/nvr/pc1640.nvr differ diff --git a/nvr/pc200.nvr b/nvr/pc200.nvr new file mode 100644 index 000000000..bca7ebe91 Binary files /dev/null and b/nvr/pc200.nvr differ diff --git a/nvr/pc2086.nvr b/nvr/pc2086.nvr new file mode 100644 index 000000000..40f563600 Binary files /dev/null and b/nvr/pc2086.nvr differ diff --git a/nvr/pc3086.nvr b/nvr/pc3086.nvr new file mode 100644 index 000000000..f340d66ae Binary files /dev/null and b/nvr/pc3086.nvr differ diff --git a/nvr/plato.nvr b/nvr/plato.nvr new file mode 100644 index 000000000..b8d5d8404 Binary files /dev/null and b/nvr/plato.nvr differ diff --git a/nvr/px386.nvr b/nvr/px386.nvr new file mode 100644 index 000000000..c33bb9714 Binary files /dev/null and b/nvr/px386.nvr differ diff --git a/nvr/r418.nvr b/nvr/r418.nvr new file mode 100644 index 000000000..9edb80612 Binary files /dev/null and b/nvr/r418.nvr differ diff --git a/nvr/revenge.nvr b/nvr/revenge.nvr new file mode 100644 index 000000000..2ee09d49d Binary files /dev/null and b/nvr/revenge.nvr differ diff --git a/nvr/sis496.nvr b/nvr/sis496.nvr new file mode 100644 index 000000000..56f19faaf Binary files /dev/null and b/nvr/sis496.nvr differ diff --git a/nvr/tandy1000hx.bin b/nvr/tandy1000hx.bin new file mode 100644 index 000000000..e69de4f70 Binary files /dev/null and b/nvr/tandy1000hx.bin differ diff --git a/nvr/tandy1000sl2.bin b/nvr/tandy1000sl2.bin new file mode 100644 index 000000000..e69de4f70 Binary files /dev/null and b/nvr/tandy1000sl2.bin differ diff --git a/nvr/vli486sv2g.nvr b/nvr/vli486sv2g.nvr new file mode 100644 index 000000000..36437f7c5 Binary files /dev/null and b/nvr/vli486sv2g.nvr differ diff --git a/nvr/win486.nvr b/nvr/win486.nvr new file mode 100644 index 000000000..97221385a Binary files /dev/null and b/nvr/win486.nvr differ diff --git a/readme.txt b/readme.txt new file mode 100644 index 000000000..30afba3fd --- /dev/null +++ b/readme.txt @@ -0,0 +1,775 @@ +PCem v10.1 + +PCem is licensed under the GPL, see COPYING for more details. + +Changes since v10: + +- Fixed buffer overruns in PIIX and ET4000/W32p emulation +- Add command line options to start in fullscreen and to specify config file +- Emulator doesn't die when the CPU jumps to an unexecutable address +- Removed Voodoo memory dump on exit + + +PCem emulates the following machines: + +IBM 5150 PC (1981) +The original PC. This shipped in 1981 with a 4.77mhz 8088, 64k of RAM, and a cassette port. +Disc drives quickly became standard, along with more memory. + +ROM files needed: + +ibmpc\pc102782.bin +ibmpc\basicc11.f6 +ibmpc\basicc11.f8 +ibmpc\basicc11.fa +ibmpc\basicc11.fc + + +IBM 5160 XT (1983) +From a hardware perspective, this is a minor tweak of the original PC. It originally shipped +with 128k of RAM and a 10mb hard disc, both of which could be easily fitted to the 1981 machine. +However, this was targetted as businesses and was more successful than the original. + +ROM files needed: + +ibmxt\5000027.u19 +ibmxt\1501512.u18 + + +IBM PCjr (1984) +A home machine, which had better graphics and sound than most XTs but was not hardware compatible +with the PC. + +ROM files needed: + +ibmpcjr\bios.rom + + +IBM AT (1984) +This was the 'next generation' PC, fully 16-bit with an 80286. The original model came with a 6mhz +286, which ran three times as fast as the XT. This model also introduced EGA. + +ROM files needed: + +ibmat\at111585.0 +ibmat\at111585.1 + + +Olivetti M24 (1984) +An enhanced XT clone, also known as the AT&T PC 6300. Has an 8086 CPU, and an unusual 'double-res' +CGA display. + +ROM files needed: + +olivetti_m24\olivetti_m24_version_1.43_low.bin +olivetti_m24\olivetti_m24_version_1.43_high.bin + + +Tandy 1000 (1985) +This is a clone of the unsuccessful IBM PCjr, which added better graphics and sound to the XT, +but removed much expandability plus some other hardware (such as the DMA controller). The Tandy +puts back the DMA controller and ISA slots, making it a much more useful machine. Many games +from the late 80s support the Tandy. + +ROM files needed: + +tandy\tandy1t1.020 + + +DTK Clone XT (1986) +A generic clone XT board. + +ROM files needed: + +dtk\DTK_ERSO_2.42_2764.bin + + +Amstrad PC1512 (1986) +This was Amstrad's first entry into the PC clone market (after the CPC and PCW machines), and +was the first cheap PC available in the UK, selling for only £500. It was a 'turbo' clone, +having an 8mhz 8086, as opposed to an 8088, and had 512k RAM as standard. It also had a +perculiar modification to its onboard CGA controller - the 640x200 mode had 16 colours instead +of the usual 2. This was put to good use by GEM, which shipped with the machine. + +Amstrad's CGA implementation has a few oddities, these are emulated as best as possible. This +mainly affects games defining unusual video modes, though 160x100x16 still works (as on the real +machine). + +ROM files needed: + +pc1512\40043.v1 +pc1512\40044.v2 +pc1512\40078.ic127 + + +Amstrad PC1640 (1987) +Amstrad's followup to the PC1512, the PC1640 had 640k of RAM and onboard EGA, but was otherwise +mostly the same. + +ROM files needed: + +pc1640\40043.v3 +pc1640\40044.v3 +pc1640\40100 + + +Sinclair PC200/Amstrad PC20 (1988) +This was Amstrad's entry to the 16-bit home computer market, intended to compete with the Atari +ST and Commodore Amiga. It's similar to the PC1512, but is based on Amstrad's portable PPC512 +system. With stock CGA and PC speaker, it couldn't compare with the ST or Amiga. + +ROM files needed: + +pc200\pc20v2.0 +pc200\pc20v2.1 +pc200\40109.bin + + +Schneider Euro PC (1988) +A German XT clone. An 'all-in-one' system like the Sinclair PC200. I don't know much about this +machine to be honest! This doesn't appear to work with the XTIDE BIOS, so therefore this is the +only model that does not support hard discs. + +ROM files needed: + +europc\50145 +europc\50146 + + +(c)Anonymous Generic Turbo XT BIOS (1988?) +This is a BIOS whose source code was made available on Usenet in 1988. It appears to be an +anonymous BIOS from an XT clone board. It was then heavily modified to fix bugs. The history of +this BIOS (and the source code) is at http://dizzie.narod.ru/bios.txt + +ROM files needed: + +genxt\pcxt.rom + + +AMI XT clone (1989) + +ROM files needed: + +amixt\AMI_8088_BIOS_31JAN89.BIN + + +DTK XT clone (1988) + +ROM files needed: + +dtk\DTK_ERSO_2.42_2764.bin + + +VTech Laser Turbo XT (1987) + +ROM files needed: + +ltxt\27C64.bin + + +VTech Laser XT3 (1989) + +ROM files needed: + +lxt3\27C64D.bin + + +Phoenix XT clone (1986) + +ROM files needed: + +pxxt\000p001.bin + + +Juko XT clone (1988) + +ROM files needed: + +jukopc\000o001.bin + + +Commodore PC30-III (1988) +A fairly generic 286 clone. + +ROM files needed: + +cmdpc30\commodore pc 30 iii even.bin +cmdpc30\commodore pc 30 iii odd.bin + + +Amstrad PC2086 (1989) +The PC2086 is essentially a PC1640 with VGA and 3.5" floppy drives. + +ROM files needed: + +pc2086\40179.ic129 +pc2086\40180.ic132 +pc2086\40186.ic171 + + +Amstrad PC3086 (1990) +The PC3086 is a version of the PC2086 with a more standard case. + +ROM files needed: + +pc3086\fc00.bin +pc3086\c000.bin + + +Dell System 200 (1990?) +This is a pretty generic 286 clone with a Phoenix BIOS. + +HIMEM.SYS doesn't appear to work on this one, for some reason. + +ROM files needed: + +dells200\dell0.bin +dells200\dell1.bin + + +AMI 286 clone (1990) +This is a generic 286 clone with an AMI BIOS. + +ROM files needed: + +ami286\amic206.bin + + +IBM PS/1 Model 2011 (1990) +This is a 286 with integrated VGA and a basic GUI and DOS 4.01 in ROM. + +ROM files needed: + +ibmps1\f80000.bin + + +Compaq Deskpro 386 (1989) +An early 386 system. I don't think this BIOS is from the original 1986 version +(the very first 386 system), but from a 1989 refresh. + +ROM files needed: + +deskpro386\109592-005.U11.bin +deskpro386\109591-005.U13.bin + + +Acermate 386SX/25N (1992?) +An integrated 386SX clone, with onboard Oak SVGA and IO. + +ROM files needed: +acer386\acer386.bin +acer386\oti067.bin + + +DTK 386SX clone (1990) + +ROM files needed: + +dtk386\3cto001.bin + + +Phoenix 386 clone (1989) + +ROM files needed: + +px386\3iip001l.bin +px386\3iip001h.bin + + +Amstrad MegaPC (1992) +A 386SX clone (otherwise known as the PC7386SX) with a built-in Sega Megadrive. Only the PC section +is emulated, obv. + +ROM files needed: +megapc\41651-bios lo.u18 +megapc\211253-bios hi.u19 + + +AMI 386 clone (1994) +This is a generic 386 clone with an AMI BIOS. The BIOS came from my 386DX/40, the motherboard is +dated June 1994. + +ROM files needed: + +ami386\ami386.bin + + +AMI 486 clone (1993) +This is a generic 486 clone with an AMI BIOS. The BIOS came from my 486SX/25, bought in December +1993. + +ROM files needed: + +ami486\ami486.bin + + +AMI WinBIOS 486 clone (1994) +A 486 clone with a newer AMI BIOS. + +ROM files needed: + +win486\ali1429g.amw + + +Award SiS 496/497 (1995) +A 486 clone using the SiS 496/497 chipset, with PCI bus and Award BIOS. + +ROM files needed: + +sis496\SIS496-1.AWA + + +Intel Premiere/PCI (Batman's Revenge) (1994) +A Socket 4 based board with 430LX chipset. + +Has an odd bug where on soft-reset, the memory count never ends. Hard-reset works okay. + +ROM files needed: + +revenge\1009AF2_.BI0 +revenge\1009AF2_.BI1 + + +Intel Advanced/EV (Endeavor) (1995) +A Socket 5/7 based board with 430FX chipset. The real board has a Sound Blaster Vibra 16 on board, +which is not emulated - use a discrete card instead. Some Advanced/EVs also had a Trio64 on board, +the emulated board does not have this either. + +Has essentially the same BIOS as the Premiere/PCI, and the same soft-reset bug. + +ROM files needed: + +endeavor\1006CB0_.BI0 +endeavor\1006CB0_.BI1 + + +Award 430VX PCI (1996) +A generic Socket 5/7 board with 430VX chipset. + +ROM files needed: + +430vx\55XWUQ0E.BIN + + + +PCem emulates the following graphics adapters : + +MDA +The original PC adapter. This displays 80x25 text in monochrome. + + +Hercules +A clone of MDA, with the addition of a high-resolution 720x348 graphics mode. + + +CGA +The most common of the original adapters, supporting 40x25 and 80x25 text, and +320x200 in 4 colours, 640x200 in 2 colours, and a composite mode giving 160x200 +in 16 colours. + + +IBM EGA +The original 1984 IBM EGA card, with 256k VRAM. + +ROM files needed: + +ibm_6277356_ega_card_u44_27128.bin + + +Trident 8900D SVGA +A low cost SVGA board circa 1992/1993. Not the greatest board in it's day, but +it has a reasonable VESA driver and (buggy) 15/16/24-bit colour modes. + +ROM files needed: + +trident.bin + + +Trident TGUI9440 +A later Trident board with GUI acceleration. Windows 9x doesn't include drivers +for this, so they have to be downloaded and installed separately. + +ROM files needed: + +9440.vbi + + +Tseng ET4000AX SVGA +A somewhat better SVGA board than the Trident, here you get better compatibility +and speed (on the real card, not the emulator) in exchange for being limited to +8-bit colour. + +ROM files needed: + +et4000.bin + + +Diamond Stealth 32 SVGA +An ET4000/W32p based board, has 15/16/24-bit colour modes, plus acceleration. + +ROM files needed: + +et4000w32.bin + + +Paradise Bahamas 64 +An S3 Vision864 based board. + +ROM files needed: + +bahamas64.bin + + +Number Nine 9FX +An S3 Trio64 based board. + +ROM files needed: + +s3_764.bin + + +ATI VGA Edge-16 +A basic SVGA clone. + +ROM files needed: + +vgaedge16.vbi + + +ATI VGA Charger +A basic SVGA clone, similar to the Edge-16. + +ROM files needed: + +bios.bin + + +ATI Graphics Pro Turbo +A Mach64GX based board. Probably the best of the emulated boards for use in +Windows. + +ROM files needed: + +mach64gx/bios.bin + + +OAK OTI-067 +A basic SVGA clone. + +ROM files needed: + +oti067/bios.bin + + +Diamond Stealth 3D 2000 +An S3 ViRGE/325 based board. + +PCem emulates the ViRGE S3D engine in software. This works with most games I tried, but +there may be some issues. The Direct3D drivers for the /325 are fairly poor (often showing +as missing triangles), so use of the /DX instead is recommended. + +The streams processor (video overlay) is also emulated, however many features are missing. + +ROM files needed: + +s3virge.bin + + +S3 ViRGE/DX +An S3 ViRGE/DX based board. The drivers that come with Windows are similar to those for the +/325, however better ones do exist (try the 8-21-1997 version). With the correct drivers, +many early Direct3D games work okay (if slowly). + +ROM files needed: + +86c375_1.bin + + +3DFX Voodoo Graphics +3D accelerator. Widely supported in late 90s games. + +PCem emulates this in software. The emulation isn't quite as fast as the real thing, but in +most games the emulated CPU is the bottleneck rather than the 3DFX, unless you insist on +running in 800x600. PCem can split rendering over two threads - this doesn't double performance, +but can give a noticeable improvement. + +PCem can emulate 6 and 8 MB configurations, but defaults to 4 MB for compatibility. It can also +emulate the screen filter present on the original card, though this does at present have a +noticeable performance hit. + +Almost everything I've tried works okay, with a very few exceptions - Screamer 2 and Rally have +serious issues, and Need For Speed II SE and III don't draw the map correctly. + + + +Some models have fixed graphics adapters : + +IBM PCjr +CGA with various new modes - 160x200x16, 320x200x16, 640x200x4. + +Olivetti M24 +CGA with double-res text modes and a 640x400 mode. I haven't seen a dump of the font +ROM for this yet, so if one is not provided the MDA font will be used - which looks slightly odd +as it is 14-line instead of 16-line. + +Tandy 1000 +Clone of PCjr video. Widely supported in 80s games. + +Amstrad PC1512 +CGA with a new mode (640x200x16). Only supported in GEM to my knowledge. + +Amstrad PC1640 +Paradise EGA. + +Amstrad PC2086/PC3086 +Paradise PVGA1. An early SVGA clone with 256kb VRAM. + +IBM PS/1 Model 2011 +Stock VGA with 256kb VRAM. + +Amstrad MegaPC +Paradise 90C11. A development of the PVGA1, with 512kb VRAM. + +Acer 386SX/25N +Oak OTI-067. Another 512kb SVGA clone. + + + +PCem emulates the following sound devices : + +PC speaker +The standard beeper on all PCs. Supports samples/RealSound. + +Tandy PSG +The Texas Instruments chip in the PCjr and Tandy 1000. Supports 3 voices plus +noise. I reused the emulator in B-em for this (slightly modified). + +Gameblaster +The Creative Labs Gameblaster/Creative Music System, Creative's first sound card +introduced in 1987. Has two Philips SAA1099, giving 12 voices of square waves plus 4 noise +voices. In stereo! + +Adlib +Has a Yamaha YM3812, giving 9 voices of 2 op FM, or 6 voices plus a rhythm section. PCem +uses the DOSBox dbopl emulator. + +Adlib Gold +OPL3 with YM318Z 12-bit digital section. Possibly some bugs (not a lot of software to test). + +Sound Blaster +Several Sound Blasters are emulated : + SB v1.0 - The original. Limited to 22khz, and no auto-init DMA (can cause crackles sometimes). + SB v1.5 - Adds auto-init DMA + SB v2.0 - Upped to 41khz + SB Pro v1.0 - Stereo, with twin OPL2 chips. + SB Pro v2.0 - Stereo, with OPL 3 chip + SB 16 - 16 bit stereo + SB AWE32 - SB 16 + wavetable MIDI. This requires a ROM dump from a real AWE32. +All are set to Address 220, IRQ 7 and DMA 1 (and High DMA 5). IRQ and DMA can be changed for the +SB16 & AWE32 in the drivers. +The relevant SET line for autoexec.bat is + SET BLASTER = A220 I7 D1 Tx - where Tx is T1 for SB v1.0, T3 for SB v2.0, T4 for SB Pro, + and T6 for SB16. + +AWE32 requires a ROM dump called awe32.raw. AWE-DUMP is a utility which can get a dump from a real +card. Most EMU8000 functionality should work, however filters are not correct and reverb/chorus +effects are not currently emulated. + +Gravis Ultrasound +32 voice sample playback. Port address is fixed to 240, IRQ and DMA can be changed from the drivers. +Emulation is improved significantly over previous versions. + +Windows Sound System +16-bit digital + OPL3. Note that this only emulates WSS itself, and should not be used with drivers +from compatible boards with additional components (eg Turtle Beach Monte Carlo) + +Innovation SSI-2001 +SID6581. Emulated using resid-fp. Board is fixed to port 280. + + +Other stuff emulated : + +Serial mouse +A Microsoft compatible serial mouse on COM1. Compatible drivers are all over the place for this. + +M24 mouse +I haven't seen a DOS mouse driver for this yet, but the regular scancode mode works, as does the +Windows 1.x driver. + +PC1512 mouse +The PC1512's perculiar quadrature mouse. You need Amstrad's actual driver for this one. + +PS/2 mouse +A PS/2 mouse is emulated on the MegaPC, 386SX/25N and Premiere/PCI models. As with serial, +compatible drivers are common. + +ATAPI CD-ROM +Works with OAKCDROM.SYS. It can only work with actual CD-ROM drives at the minute, so to use ISO images +you need a virtual CD drive. + + +XTIDE : + +The XTIDE board is emulated for machines that don't natively support IDE hard discs. + +You will need to download the XTIDE BIOS seperately. Of the various versions, ide_at.bin and ide_xt.bin +should be placed in the ROMS directory. ide_xt is used on all XT models, and ide_at is used on the IBM AT +and Commodore PC30-III machines. + +The BIOS is available at : + +http://code.google.com/p/xtideuniversalbios/ + +v2.0.0 beta 1 is the version I've mostly tested. v2.0.0 beta 3 is known to have some issues. + +For the PS/1, you will need v1.1.5. The PS/1 is a bit fussy with XTIDE, and I've found that it works best +when the XTIDE configuration has 'Full Operating Mode' disabled. This version must be called +ide_at_1_1_5.bin and should also be placed in the ROMS directory. + + +Notes : + +- The time on the PC1512 clock is wrong. The date is correct, though since the PC1512's bios isn't + Y2k compliant, it thinks it's 1988. + +- The envelope system on the Gameblaster isn't emulated. The noise may not be right either. + +- Some of the more unusual VGA features are not emulated. I haven't found anything that uses them yet. + +- On some versions of Windows the AWE32 is not set up correctly, claiming a resource conflict. To correct + this open the relevant item in Device Manager, choose 'Set Configuration Manually' and accept the + options presented. + + +Software tested: + +MS-DOS 3.3 +MS-DOS 6.22 + - Most of the supplied software seems to work, eg Drivespace, Defrag, Scandisk, QBASIC + etc + +Windows 1.03 +Windows 2.03 +Windows/286 2.1 +Windows/386 2.1 +Windows 3.0 +Windows 3.1 +Windows 3.11 for Workgroups +Windows NT 3.1 +Windows NT 3.51 +Windows NT 4 +Windows 95 +Windows 95 OSR 2 +Windows 98 +Windows 98 SE +Windows ME +Windows 2000 +Windows XP + +OS/2 1.0 - hard disk must be formatted beforehand +OS/2 1.21 - hard disk must be formatted beforehand +OS/2 1.3 +OS/2 2.0 +OS/2 Warp 3 +OS/2 Warp 4 + +BeOS 5 Personal Edition (only seems to work correctly on Award SiS 496/497) + +Mandrake Linux 7.1 +RedHat Linux 7.1 (Seawolf) +SUSE Linux 6.3 + +NetBSD 6.1.5 + +Office 97 +Word for Windows 2.0 +Works for Windows 3.0 + +Alien vs Predator +All New World of Lemmings +Alley Cat +Breakneck +Civilization (DOS and Windows versions) +Colin Mcrae Rally +Colonization +Command and Conquer : Red Alert (DOS and Windows versions) +Croc (demo, ViRGE and 3DFX) +Curse of Monkey Island +Dawn Patrol +Deus Ex (3DFX) (slow) +Discworld 2 +Doom +Duke Nukem 3D +Dune (floppy and CD versions) +Ecstatica +Epic Pinball +Expendable (3DFX) (slow) +Final Fantasy VII (3DFX) +Forsaken (3DFX) +G-Police (ViRGE and 3DFX) +Grand Theft Auto (3DFX) +Grand Theft Auto 2 (3DFX) +Grim Fandango (ViRGE and 3DFX) +Half-Life (3DFX) +Incoming (3DFX) +Interstate '76 +Jazz Jackrabbit +Jazz Jackrabbit 2 +Jedi Knight (3DFX) +Kings Quest (PC booter, PCjr and Tandy 1000) +Kings Quest II (booter) +Lemmings +Lemmings 2 : The Tribes +Lotus III +Mortal Kombat Trilogy (DOS and Windows versions) +Mystic Towers +Need for Speed II SE (3DFX) +Need for Speed III +Network Q RAC Rally +Oddworld : Abe's Oddysee +Overlord +Pinball Fantasies +Populous : The Beginning (3DFX) +Power Drive +Prince of Persia +Pro Pinball : Big Race USA +Pro Pinball : The Web +Psycho Pinball +Quake (3DFX) +Quake II (3DFX) +Rebel Assault +Return of Arcade +Rise of the Triad +Rollercoaster Tycoon +Screamer +Screamer Rally (not 3DFX) +Secret of Monkey Island +Sensible World of Soccer +Simcity 2000 (DOS, Windows 3.1, Windows 95 and OS/2 versions) +Simcity 3000 +SiN (3DFX) +Stargunner +System Shock +Terminal Velocity +The 7th Guest +The Humans +Theme Hospital (DOS and Windows versions) +Theme Park +Tomb Raider (ViRGE and 3DFX) +Tomb Raider II (3DFX) +Total Annihilation +Transport Tycoon +Turok (3DFX) +Tyrian +UFO : Enemy Unknown +Ultima Underworld II +Unreal +Unreal Tournament (3DFX) +Wacky Wheels +Wing Commander III +Wolfenstein 3D +Worms +X-Com : Apocalypse +X-Com : Terror From The Deep +X-Wing + diff --git a/roms/430vx/roms.txt b/roms/430vx/roms.txt new file mode 100644 index 000000000..4e9bbdc7d --- /dev/null +++ b/roms/430vx/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/acer386/roms.txt b/roms/acer386/roms.txt new file mode 100644 index 000000000..4e9bbdc7d --- /dev/null +++ b/roms/acer386/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/ami286/roms.txt b/roms/ami286/roms.txt new file mode 100644 index 000000000..4e9bbdc7d --- /dev/null +++ b/roms/ami286/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/ami386/roms.txt b/roms/ami386/roms.txt new file mode 100644 index 000000000..4e9bbdc7d --- /dev/null +++ b/roms/ami386/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/ami486/roms.txt b/roms/ami486/roms.txt new file mode 100644 index 000000000..4e9bbdc7d --- /dev/null +++ b/roms/ami486/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/cmdpc30/roms.txt b/roms/cmdpc30/roms.txt new file mode 100644 index 000000000..4e9bbdc7d --- /dev/null +++ b/roms/cmdpc30/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/dells200/roms.txt b/roms/dells200/roms.txt new file mode 100644 index 000000000..4e9bbdc7d --- /dev/null +++ b/roms/dells200/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/dtk/roms.txt b/roms/dtk/roms.txt new file mode 100644 index 000000000..4e9bbdc7d --- /dev/null +++ b/roms/dtk/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/endeavor/roms.txt b/roms/endeavor/roms.txt new file mode 100644 index 000000000..4e9bbdc7d --- /dev/null +++ b/roms/endeavor/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/europc/roms.txt b/roms/europc/roms.txt new file mode 100644 index 000000000..4e9bbdc7d --- /dev/null +++ b/roms/europc/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/genxt/roms.txt b/roms/genxt/roms.txt new file mode 100644 index 000000000..4e9bbdc7d --- /dev/null +++ b/roms/genxt/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/hot-433/roms.txt b/roms/hot-433/roms.txt new file mode 100644 index 000000000..4e9bbdc7d --- /dev/null +++ b/roms/hot-433/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/ibmat/roms.txt b/roms/ibmat/roms.txt new file mode 100644 index 000000000..4e9bbdc7d --- /dev/null +++ b/roms/ibmat/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/ibmpc/roms.txt b/roms/ibmpc/roms.txt new file mode 100644 index 000000000..4e9bbdc7d --- /dev/null +++ b/roms/ibmpc/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/ibmxt/roms.txt b/roms/ibmxt/roms.txt new file mode 100644 index 000000000..4e9bbdc7d --- /dev/null +++ b/roms/ibmxt/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/mach64gx/roms.txt b/roms/mach64gx/roms.txt new file mode 100644 index 000000000..4e9bbdc7d --- /dev/null +++ b/roms/mach64gx/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/mda.rom b/roms/mda.rom new file mode 100644 index 000000000..1b92f042a Binary files /dev/null and b/roms/mda.rom differ diff --git a/roms/megapc/roms.txt b/roms/megapc/roms.txt new file mode 100644 index 000000000..4e9bbdc7d --- /dev/null +++ b/roms/megapc/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/olivetti_m24/roms.txt b/roms/olivetti_m24/roms.txt new file mode 100644 index 000000000..4e9bbdc7d --- /dev/null +++ b/roms/olivetti_m24/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/oti067/roms.txt b/roms/oti067/roms.txt new file mode 100644 index 000000000..4e9bbdc7d --- /dev/null +++ b/roms/oti067/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/pc1512/roms.txt b/roms/pc1512/roms.txt new file mode 100644 index 000000000..4e9bbdc7d --- /dev/null +++ b/roms/pc1512/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/pc1640/roms.txt b/roms/pc1640/roms.txt new file mode 100644 index 000000000..4e9bbdc7d --- /dev/null +++ b/roms/pc1640/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/pc200/roms.txt b/roms/pc200/roms.txt new file mode 100644 index 000000000..4e9bbdc7d --- /dev/null +++ b/roms/pc200/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/pc2086/roms.txt b/roms/pc2086/roms.txt new file mode 100644 index 000000000..4e9bbdc7d --- /dev/null +++ b/roms/pc2086/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/pc3086/roms.txt b/roms/pc3086/roms.txt new file mode 100644 index 000000000..4e9bbdc7d --- /dev/null +++ b/roms/pc3086/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/revenge/roms.txt b/roms/revenge/roms.txt new file mode 100644 index 000000000..4e9bbdc7d --- /dev/null +++ b/roms/revenge/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/sis496/roms.txt b/roms/sis496/roms.txt new file mode 100644 index 000000000..4e9bbdc7d --- /dev/null +++ b/roms/sis496/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/tandy/roms.txt b/roms/tandy/roms.txt new file mode 100644 index 000000000..4e9bbdc7d --- /dev/null +++ b/roms/tandy/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/roms/win486/roms.txt b/roms/win486/roms.txt new file mode 100644 index 000000000..4e9bbdc7d --- /dev/null +++ b/roms/win486/roms.txt @@ -0,0 +1 @@ +This directory needs to contain some ROM files. \ No newline at end of file diff --git a/src/386.c b/src/386.c new file mode 100644 index 000000000..6dddc4088 --- /dev/null +++ b/src/386.c @@ -0,0 +1,380 @@ +#include +#include +#include +#include "ibm.h" +#include "x86.h" +#include "x87.h" +#include "mem.h" +#include "cpu.h" +#include "fdc.h" +#include "timer.h" + +#include "386_common.h" + +#define CPU_BLOCK_END() + +extern int codegen_flags_changed; + +x86seg *ea_seg; + +extern int nmi_enable; + +int inscounts[256]; +uint32_t oldpc2; + +int trap; + + + +extern int cpl_override; + +int has_fpu; +extern int fpucount; +int times; +uint16_t rds; +uint16_t ea_rseg; + +int is486; +int cgate32; + + + +uint8_t romext[32768]; +uint8_t *ram,*rom; +uint32_t biosmask; + +uint32_t rmdat32; +#define rmdat rmdat32 +#define fetchdat rmdat32 +uint32_t backupregs[16]; +extern int oddeven; +int inttype,abrt; + + +uint32_t oldcs2; +uint32_t oldecx; +uint32_t op32; + + +uint32_t *eal_r, *eal_w; + +uint16_t *mod1add[2][8]; +uint32_t *mod1seg[8]; + +static inline void fetch_ea_32_long(uint32_t rmdat) +{ + eal_r = eal_w = NULL; + easeg = ea_seg->base; + ea_rseg = ea_seg->seg; + if (rm == 4) + { + uint8_t sib = rmdat >> 8; + + switch (mod) + { + case 0: + eaaddr = cpu_state.regs[sib & 7].l; + cpu_state.pc++; + break; + case 1: + cpu_state.pc++; + eaaddr = ((uint32_t)(int8_t)getbyte()) + cpu_state.regs[sib & 7].l; +// pc++; + break; + case 2: + eaaddr = (fastreadl(cs + cpu_state.pc + 1)) + cpu_state.regs[sib & 7].l; + cpu_state.pc += 5; + break; + } + /*SIB byte present*/ + if ((sib & 7) == 5 && !mod) + eaaddr = getlong(); + else if ((sib & 6) == 4 && !ssegs) + { + easeg = ss; + ea_rseg = SS; + ea_seg = &_ss; + } + if (((sib >> 3) & 7) != 4) + eaaddr += cpu_state.regs[(sib >> 3) & 7].l << (sib >> 6); + } + else + { + eaaddr = cpu_state.regs[rm].l; + if (mod) + { + if (rm == 5 && !ssegs) + { + easeg = ss; + ea_rseg = SS; + ea_seg = &_ss; + } + if (mod == 1) + { + eaaddr += ((uint32_t)(int8_t)(rmdat >> 8)); + cpu_state.pc++; + } + else + { + eaaddr += getlong(); + } + } + else if (rm == 5) + { + eaaddr = getlong(); + } + } + if (easeg != 0xFFFFFFFF && ((easeg + eaaddr) & 0xFFF) <= 0xFFC) + { + uint32_t addr = easeg + eaaddr; + if ( readlookup2[addr >> 12] != -1) + eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); + if (writelookup2[addr >> 12] != -1) + eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); + } +} + +static inline void fetch_ea_16_long(uint32_t rmdat) +{ + eal_r = eal_w = NULL; + easeg = ea_seg->base; + ea_rseg = ea_seg->seg; + if (!mod && rm == 6) + { + eaaddr = getword(); + } + else + { + switch (mod) + { + case 0: + eaaddr = 0; + break; + case 1: + eaaddr = (uint16_t)(int8_t)(rmdat >> 8); cpu_state.pc++; + break; + case 2: + eaaddr = getword(); + break; + } + eaaddr += (*mod1add[0][rm]) + (*mod1add[1][rm]); + if (mod1seg[rm] == &ss && !ssegs) + { + easeg = ss; + ea_rseg = SS; + ea_seg = &_ss; + } + eaaddr &= 0xFFFF; + } + if (easeg != 0xFFFFFFFF && ((easeg + eaaddr) & 0xFFF) <= 0xFFC) + { + uint32_t addr = easeg + eaaddr; + if ( readlookup2[addr >> 12] != -1) + eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); + if (writelookup2[addr >> 12] != -1) + eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); + } +} + +#define fetch_ea_16(rmdat) cpu_state.pc++; mod=(rmdat >> 6) & 3; reg=(rmdat >> 3) & 7; rm = rmdat & 7; if (mod != 3) { fetch_ea_16_long(rmdat); if (abrt) return 0; } +#define fetch_ea_32(rmdat) cpu_state.pc++; mod=(rmdat >> 6) & 3; reg=(rmdat >> 3) & 7; rm = rmdat & 7; if (mod != 3) { fetch_ea_32_long(rmdat); } if (abrt) return 0 + +#include "x86_flags.h" + +#define getbytef() ((uint8_t)(fetchdat)); cpu_state.pc++ +#define getwordf() ((uint16_t)(fetchdat)); cpu_state.pc+=2 +#define getbyte2f() ((uint8_t)(fetchdat>>8)); cpu_state.pc++ +#define getword2f() ((uint16_t)(fetchdat>>8)); cpu_state.pc+=2 +extern int xout; + +int oldi; + +uint32_t testr[9]; +extern int dontprint; + +#undef NOTRM +#define NOTRM if (!(msw & 1) || (eflags & VM_FLAG))\ + { \ + x86_int(6); \ + return 0; \ + } + +#define OP_TABLE(name) ops_ ## name + +#define CLOCK_CYCLES(c) cycles -= (c) +#define CLOCK_CYCLES_ALWAYS(c) cycles -= (c) + +#include "x86_ops.h" + +#undef NOTRM +#define NOTRM if (!(msw & 1) || (eflags & VM_FLAG))\ + { \ + x86_int(6); \ + break; \ + } + +void exec386(int cycs) +{ + uint8_t temp; + uint32_t addr; + int tempi; + int cycdiff; + int oldcyc; + + cycles+=cycs; +// output=3; + while (cycles>0) + { + cycdiff=0; + oldcyc=cycles; + timer_start_period(cycles << TIMER_SHIFT); +// pclog("%i %02X\n", ins, ram[8]); + while (cycdiff<100) + { + /* testr[0]=EAX; testr[1]=EBX; testr[2]=ECX; testr[3]=EDX; + testr[4]=ESI; testr[5]=EDI; testr[6]=EBP; testr[7]=ESP;*/ +/* testr[8]=flags;*/ +// oldcs2=oldcs; +// oldpc2=oldpc; +opcode_realstart: + oldcs=CS; + oldpc=cpu_state.pc; + oldcpl=CPL; + op32=use32; + +dontprint=0; + + ea_seg = &_ds; + ssegs = 0; + +opcodestart: + fetchdat = fastreadl(cs + cpu_state.pc); + + if (!abrt) + { + trap = flags & T_FLAG; + opcode = fetchdat & 0xFF; + fetchdat >>= 8; + + if (output == 3) + { + pclog("%04X(%06X):%04X : %08X %08X %08X %08X %04X %04X %04X(%08X) %04X %04X %04X(%08X) %08X %08X %08X SP=%04X:%08X %02X %04X %i %08X %08X %i %i %02X %02X %02X %02X %02X %f %02X%02X %02X%02X %02X%02X %02X\n",CS,cs,cpu_state.pc,EAX,EBX,ECX,EDX,CS,DS,ES,es,FS,GS,SS,ss,EDI,ESI,EBP,SS,ESP,opcode,flags,ins,0, ldt.base, CPL, stack32, pic.pend, pic.mask, pic.mask2, pic2.pend, pic2.mask, pit.c[0], ram[0xB270+0x3F5], ram[0xB270+0x3F4], ram[0xB270+0x3F7], ram[0xB270+0x3F6], ram[0xB270+0x3F9], ram[0xB270+0x3F8], ram[0x4430+0x0D49]); + } + cpu_state.pc++; + x86_opcodes[(opcode | op32) & 0x3ff](fetchdat); + } + + if (!use32) cpu_state.pc &= 0xffff; + + if (abrt) + { + flags_rebuild(); +// pclog("Abort\n"); +// if (CS == 0x228) pclog("Abort at %04X:%04X - %i %i %i\n",CS,pc,notpresent,nullseg,abrt); +/* if (testr[0]!=EAX) pclog("EAX corrupted %08X\n",pc); + if (testr[1]!=EBX) pclog("EBX corrupted %08X\n",pc); + if (testr[2]!=ECX) pclog("ECX corrupted %08X\n",pc); + if (testr[3]!=EDX) pclog("EDX corrupted %08X\n",pc); + if (testr[4]!=ESI) pclog("ESI corrupted %08X\n",pc); + if (testr[5]!=EDI) pclog("EDI corrupted %08X\n",pc); + if (testr[6]!=EBP) pclog("EBP corrupted %08X\n",pc); + if (testr[7]!=ESP) pclog("ESP corrupted %08X\n",pc);*/ +/* if (testr[8]!=flags) pclog("FLAGS corrupted %08X\n",pc);*/ + tempi = abrt; + abrt = 0; + x86_doabrt(tempi); + if (abrt) + { + abrt = 0; + CS = oldcs; + cpu_state.pc = oldpc; + pclog("Double fault %i\n", ins); + pmodeint(8, 0); + if (abrt) + { + abrt = 0; + softresetx86(); + pclog("Triple fault - reset\n"); + } + } + } + cycdiff=oldcyc-cycles; + + if (trap) + { + flags_rebuild(); +// oldpc=pc; +// oldcs=CS; + if (msw&1) + { + pmodeint(1,0); + } + else + { + writememw(ss,(SP-2)&0xFFFF,flags); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + addr = (1 << 2) + idt.base; + flags&=~I_FLAG; + flags&=~T_FLAG; + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + } + } + else if (nmi && nmi_enable) + { + oldpc = cpu_state.pc; + oldcs = CS; +// pclog("NMI\n"); + x86_int(2); + nmi_enable = 0; + } + else if ((flags&I_FLAG) && pic_intpending) + { + temp=picinterrupt(); + if (temp!=0xFF) + { +// if (temp == 0x54) pclog("Take int 54\n"); +// if (output) output=3; +// if (temp == 0xd) pclog("Hardware int %02X %i %04X(%08X):%08X\n",temp,ins, CS,cs,pc); +// if (temp==0x54) output=3; + flags_rebuild(); + if (msw&1) + { + pmodeint(temp,0); + } + else + { + writememw(ss,(SP-2)&0xFFFF,flags); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + addr = (temp << 2) + idt.base; + flags&=~I_FLAG; + flags&=~T_FLAG; + oxpc=cpu_state.pc; + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); +// if (temp==0x76) pclog("INT to %04X:%04X\n",CS,pc); + } +// pclog("Now at %04X(%08X):%08X\n", CS, cs, pc); + } + } + + ins++; + insc++; + + if (timetolive) + { + timetolive--; + if (!timetolive) + fatal("Life expired\n"); + } + } + + tsc += cycdiff; + + timer_end_period(cycles << TIMER_SHIFT); + } +} diff --git a/src/386.h b/src/386.h new file mode 100644 index 000000000..d374f3c9e --- /dev/null +++ b/src/386.h @@ -0,0 +1,2 @@ +extern void cpu_386_flags_extract(); +extern void cpu_386_flags_rebuild(); diff --git a/src/386_common.h b/src/386_common.h new file mode 100644 index 000000000..f02a64b9d --- /dev/null +++ b/src/386_common.h @@ -0,0 +1,288 @@ +extern uint16_t ea_rseg; + +#undef readmemb +#undef writememb + + +#define readmemb(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF)?readmemb386l(s,a): *(uint8_t *)(readlookup2[(uint32_t)((s)+(a))>>12] + (uint32_t)((s) + (a))) ) +#define readmemq(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a))&0xFFF)>0xFF8)?readmemql(s,a):*(uint64_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) + +#define writememb(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF) writememb386l(s,a,v); else *(uint8_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v + +#define writememw(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a))&0xFFF)>0xFFE) writememwl(s,a,v); else *(uint16_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v +#define writememl(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a))&0xFFF)>0xFFC) writememll(s,a,v); else *(uint32_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v +#define writememq(s,a,v) if (writelookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a))&0xFFF)>0xFF8) writememql(s,a,v); else *(uint64_t *)(writelookup2[(uint32_t)((s) + (a)) >> 12] + (uint32_t)((s) + (a))) = v + + +#if 0 +#define check_io_perm(port) if (!IOPLp || (eflags&VM_FLAG)) \ + { \ + int tempi = checkio(port); \ + if (abrt) return 1; \ + if (tempi) \ + { \ + pclog("No I/O permission on port %04Xh\n", port); \ + x86gpf("check_io_perm(): no permission",0); \ + return 1; \ + } \ + } + +#define checkio_perm(port) if (!IOPLp || (eflags&VM_FLAG)) \ + { \ + tempi = checkio(port); \ + if (abrt) break; \ + if (tempi) \ + { \ + x86gpf("checkio_perm(): no permission",0); \ + break; \ + } \ + } +#endif + +#define check_io_perm(port) if (msw&1 && ((CPL > IOPL) || (eflags&VM_FLAG))) \ + { \ + int tempi = checkio(port); \ + if (abrt) return 1; \ + if (tempi) \ + { \ + pclog("No I/O permission on port %04Xh\n", port); \ + x86gpf("check_io_perm(): no permission",0); \ + return 1; \ + } \ + } + +#define checkio_perm(port) if (msw&1 && ((CPL > IOPL) || (eflags&VM_FLAG))) \ + { \ + tempi = checkio(port); \ + if (abrt) break; \ + if (tempi) \ + { \ + x86gpf("checkio_perm(): no permission",0); \ + break; \ + } \ + } + +#define CHECK_READ(chseg, low, high) \ + if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high)) \ + { \ + x86gpf("Limit check (READ)", 0); \ + return 1; \ + } \ + if (msw&1 && !(eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ + { \ + if ((chseg) == &_ss) \ + x86ss(NULL,(chseg)->seg & 0xfffc); \ + else \ + pclog("Read from seg not present", (chseg)->seg & 0xfffc); \ + return 1; \ + } + +#define CHECK_WRITE(chseg, low, high) \ + if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high) || !((chseg)->access & 2)) \ + { \ + x86gpf("Limit check (WRITE)", 0); \ + return 1; \ + } \ + if (msw&1 && !(eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ + { \ + if ((chseg) == &_ss) \ + x86ss(NULL,(chseg)->seg & 0xfffc); \ + else \ + x86np("Write to seg not present", (chseg)->seg & 0xfffc); \ + return 1; \ + } + +#if 0 +#define CHECK_WRITE_REP(chseg, low, high) \ + if ((low < (chseg)->limit_low) || (high > (chseg)->limit_high)) \ + { \ + x86gpf("Limit check (WRITE_REP)", 0); \ + if (1 != 1) break; \ + } \ + if (msw&1 && !(eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ + { \ + if ((chseg) == &_ss) \ + x86ss(NULL,(chseg)->seg & 0xfffc); \ + else \ + x86np("Write (REP) to seg not present", (chseg)->seg & 0xfffc); \ + break; \ + } +#endif + +#define CHECK_WRITE_REP(chseg, low, high) \ + if (msw&1 && !(eflags&VM_FLAG) && !((chseg)->access & 0x80)) \ + { \ + if ((chseg) == &_ss) \ + x86ss(NULL,(chseg)->seg & 0xfffc); \ + else \ + x86np("Write (REP) to seg not present", (chseg)->seg & 0xfffc); \ + break; \ + } + + +#define NOTRM if (!(msw & 1) || (eflags & VM_FLAG))\ + { \ + x86_int(6); \ + return 1; \ + } + + + + +static inline uint8_t fastreadb(uint32_t a) +{ + uint8_t *t; + + if ((a >> 12) == pccache) + return *((uint8_t *)&pccache2[a]); + t = getpccache(a); + if (abrt) + return; + pccache = a >> 12; + pccache2 = t; + return *((uint8_t *)&pccache2[a]); +} + +static inline uint16_t fastreadw(uint32_t a) +{ + uint8_t *t; + uint16_t val; + if ((a&0xFFF)>0xFFE) + { + val = readmemb(0, a); + val |= (readmemb(0, a + 1) << 8); + return val; + } + if ((a>>12)==pccache) return *((uint16_t *)&pccache2[a]); + t = getpccache(a); + if (abrt) + return; + + pccache = a >> 12; + pccache2 = t; + return *((uint16_t *)&pccache2[a]); +} + +static inline uint32_t fastreadl(uint32_t a) +{ + uint8_t *t; + uint32_t val; + if ((a&0xFFF)<0xFFD) + { + if ((a>>12)!=pccache) + { + t = getpccache(a); + if (abrt) + return 0; + pccache2 = t; + pccache=a>>12; + //return *((uint32_t *)&pccache2[a]); + } + return *((uint32_t *)&pccache2[a]); + } + val =readmemb(0,a); + val |=(readmemb(0,a+1)<<8); + val |=(readmemb(0,a+2)<<16); + val |=(readmemb(0,a+3)<<24); + return val; +} + +static inline uint8_t getbyte() +{ + cpu_state.pc++; + return fastreadb(cs + (cpu_state.pc - 1)); +} + +static inline uint16_t getword() +{ + cpu_state.pc+=2; + return fastreadw(cs+(cpu_state.pc-2)); +} + +static inline uint32_t getlong() +{ + cpu_state.pc+=4; + return fastreadl(cs+(cpu_state.pc-4)); +} + +static inline uint64_t getquad() +{ + cpu_state.pc+=8; + return fastreadl(cs+(cpu_state.pc-8)) | ((uint64_t)fastreadl(cs+(cpu_state.pc-4)) << 32); +} + + + +static inline uint8_t geteab() +{ + if (mod == 3) + return (rm & 4) ? cpu_state.regs[rm & 3].b.h : cpu_state.regs[rm&3].b.l; + if (eal_r) + return *(uint8_t *)eal_r; + return readmemb(easeg, eaaddr); +} + +static inline uint16_t geteaw() +{ + if (mod == 3) + return cpu_state.regs[rm].w; +// cycles-=3; + if (eal_r) + return *(uint16_t *)eal_r; + return readmemw(easeg, eaaddr); +} + +static inline uint32_t geteal() +{ + if (mod == 3) + return cpu_state.regs[rm].l; +// cycles-=3; + if (eal_r) + return *eal_r; + return readmeml(easeg, eaaddr); +} + +static inline uint64_t geteaq() +{ + return readmemq(easeg, eaaddr); +} + +static inline uint8_t geteab_mem() +{ + if (eal_r) return *(uint8_t *)eal_r; + return readmemb(easeg,eaaddr); +} +static inline uint16_t geteaw_mem() +{ + if (eal_r) return *(uint16_t *)eal_r; + return readmemw(easeg,eaaddr); +} +static inline uint32_t geteal_mem() +{ + if (eal_r) return *eal_r; + return readmeml(easeg,eaaddr); +} + +static inline void seteaq(uint64_t v) +{ + writememql(easeg, eaaddr, v); +} + +#define seteab(v) if (mod!=3) { if (eal_w) *(uint8_t *)eal_w=v; else writememb386l(easeg,eaaddr,v); } else if (rm&4) cpu_state.regs[rm&3].b.h=v; else cpu_state.regs[rm].b.l=v +#define seteaw(v) if (mod!=3) { if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg,eaaddr,v); } else cpu_state.regs[rm].w=v +#define seteal(v) if (mod!=3) { if (eal_w) *eal_w=v; else writememll(easeg,eaaddr,v); } else cpu_state.regs[rm].l=v + +#define seteab_mem(v) if (eal_w) *(uint8_t *)eal_w=v; else writememb386l(easeg,eaaddr,v); +#define seteaw_mem(v) if (eal_w) *(uint16_t *)eal_w=v; else writememwl(easeg,eaaddr,v); +#define seteal_mem(v) if (eal_w) *eal_w=v; else writememll(easeg,eaaddr,v); + +#define getbytef() ((uint8_t)(fetchdat)); cpu_state.pc++ +#define getwordf() ((uint16_t)(fetchdat)); cpu_state.pc+=2 +#define getbyte2f() ((uint8_t)(fetchdat>>8)); cpu_state.pc++ +#define getword2f() ((uint16_t)(fetchdat>>8)); cpu_state.pc+=2 + + +#define rmdat rmdat32 +#define fetchdat rmdat32 + +void x86_int(int num); diff --git a/src/386_dynarec.c b/src/386_dynarec.c new file mode 100644 index 000000000..ee9d33f1b --- /dev/null +++ b/src/386_dynarec.c @@ -0,0 +1,1544 @@ +#include +#include +#include +#include "ibm.h" +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "mem.h" +#include "codegen.h" +#include "cpu.h" +#include "fdc.h" +#include "timer.h" + +#include "386_common.h" + +#define CPU_BLOCK_END() cpu_block_end = 1 + +int cpu_reps, cpu_reps_latched; +int cpu_notreps, cpu_notreps_latched; + +int inrecomp = 0; +int cpu_recomp_blocks, cpu_recomp_ins, cpu_recomp_full_ins, cpu_new_blocks; +int cpu_recomp_blocks_latched, cpu_recomp_ins_latched, cpu_recomp_full_ins_latched, cpu_new_blocks_latched; + +int cpu_block_end = 0; + +x86seg *ea_seg; + +int nmi_enable = 1; + +int inscounts[256]; +uint32_t oldpc2; + +int trap; + + + +int cpl_override=0; + +int has_fpu; +int fpucount=0; +int times; +uint16_t rds; +uint16_t ea_rseg; + +int is486; +int cgate32; + + +uint8_t romext[32768]; +uint8_t *ram,*rom; +uint32_t biosmask; + +uint32_t rmdat32; +uint32_t backupregs[16]; +int oddeven=0; +int inttype,abrt; + + +uint32_t oldcs2; +uint32_t oldecx; +uint32_t op32; + + + + +uint32_t *eal_r, *eal_w; + +uint16_t *mod1add[2][8]; +uint32_t *mod1seg[8]; + +static inline void fetch_ea_32_long(uint32_t rmdat) +{ + eal_r = eal_w = NULL; + easeg = ea_seg->base; + ea_rseg = ea_seg->seg; + if (rm == 4) + { + uint8_t sib = rmdat >> 8; + + switch (mod) + { + case 0: + eaaddr = cpu_state.regs[sib & 7].l; + cpu_state.pc++; + break; + case 1: + cpu_state.pc++; + eaaddr = ((uint32_t)(int8_t)getbyte()) + cpu_state.regs[sib & 7].l; +// cpu_state.pc++; + break; + case 2: + eaaddr = (fastreadl(cs + cpu_state.pc + 1)) + cpu_state.regs[sib & 7].l; + cpu_state.pc += 5; + break; + } + /*SIB byte present*/ + if ((sib & 7) == 5 && !mod) + eaaddr = getlong(); + else if ((sib & 6) == 4 && !ssegs) + { + easeg = ss; + ea_rseg = SS; + ea_seg = &_ss; + } + if (((sib >> 3) & 7) != 4) + eaaddr += cpu_state.regs[(sib >> 3) & 7].l << (sib >> 6); + } + else + { + eaaddr = cpu_state.regs[rm].l; + if (mod) + { + if (rm == 5 && !ssegs) + { + easeg = ss; + ea_rseg = SS; + ea_seg = &_ss; + } + if (mod == 1) + { + eaaddr += ((uint32_t)(int8_t)(rmdat >> 8)); + cpu_state.pc++; + } + else + { + eaaddr += getlong(); + } + } + else if (rm == 5) + { + eaaddr = getlong(); + } + } + if (easeg != 0xFFFFFFFF && ((easeg + eaaddr) & 0xFFF) <= 0xFFC) + { + uint32_t addr = easeg + eaaddr; + if ( readlookup2[addr >> 12] != -1) + eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); + if (writelookup2[addr >> 12] != -1) + eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); + } +} + +static inline void fetch_ea_16_long(uint32_t rmdat) +{ + eal_r = eal_w = NULL; + easeg = ea_seg->base; + ea_rseg = ea_seg->seg; + if (!mod && rm == 6) + { + eaaddr = getword(); + } + else + { + switch (mod) + { + case 0: + eaaddr = 0; + break; + case 1: + eaaddr = (uint16_t)(int8_t)(rmdat >> 8); cpu_state.pc++; + break; + case 2: + eaaddr = getword(); + break; + } + eaaddr += (*mod1add[0][rm]) + (*mod1add[1][rm]); + if (mod1seg[rm] == &ss && !ssegs) + { + easeg = ss; + ea_rseg = SS; + ea_seg = &_ss; + } + eaaddr &= 0xFFFF; + } + if (easeg != 0xFFFFFFFF && ((easeg + eaaddr) & 0xFFF) <= 0xFFC) + { + uint32_t addr = easeg + eaaddr; + if ( readlookup2[addr >> 12] != -1) + eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); + if (writelookup2[addr >> 12] != -1) + eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); + } +} + +#define fetch_ea_16(rmdat) cpu_state.pc++; mod=(rmdat >> 6) & 3; reg=(rmdat >> 3) & 7; rm = rmdat & 7; if (mod != 3) { fetch_ea_16_long(rmdat); if (abrt) return 1; } +#define fetch_ea_32(rmdat) cpu_state.pc++; mod=(rmdat >> 6) & 3; reg=(rmdat >> 3) & 7; rm = rmdat & 7; if (mod != 3) { fetch_ea_32_long(rmdat); } if (abrt) return 1 + +#include "x86_flags.h" + +void x86_int(int num) +{ + uint32_t addr; +// pclog("x86_int %02x %04x:%04x\n", num, CS,pc); + flags_rebuild(); + cpu_state.pc=oldpc; + if (msw&1) + { + pmodeint(num,0); + } + else + { + if (stack32) + { + writememw(ss,ESP-2,flags); + writememw(ss,ESP-4,CS); + writememw(ss,ESP-6,cpu_state.pc); + ESP-=6; + } + else + { + writememw(ss,((SP-2)&0xFFFF),flags); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); + SP-=6; + } + addr = (num << 2) + idt.base; + + flags&=~I_FLAG; + flags&=~T_FLAG; + oxpc=cpu_state.pc; + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + } + cycles-=70; + CPU_BLOCK_END(); +} + +void x86_int_sw(int num) +{ + uint32_t addr; +// pclog("x86_int_sw %02x %04x:%04x\n", num, CS,pc); +// pclog("x86_int\n"); + flags_rebuild(); + cycles -= timing_int; + if (msw&1) + { + pmodeint(num,1); + } + else + { + if (stack32) + { + writememw(ss,ESP-2,flags); + writememw(ss,ESP-4,CS); + writememw(ss,ESP-6,cpu_state.pc); + ESP-=6; + } + else + { + writememw(ss,((SP-2)&0xFFFF),flags); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); + SP-=6; + } + addr = (num << 2) + idt.base; + + flags&=~I_FLAG; + flags&=~T_FLAG; + oxpc=cpu_state.pc; + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + cycles -= timing_int_rm; + } + trap = 0; + CPU_BLOCK_END(); +} + +void x86illegal() +{ + uint16_t addr; +// pclog("x86 illegal %04X %08X %04X:%08X %02X\n",msw,cr0,CS,pc,opcode); + +// if (output) +// { +// dumpregs(); +// exit(-1); +// } + x86_int(6); +} + + +int rep386(int fv) +{ + uint8_t temp; + uint32_t c;//=CX; + uint8_t temp2; + uint16_t tempw,tempw2,of; + uint32_t ipc=oldpc;//pc-1; + uint32_t oldds; + uint32_t rep32=op32; + uint32_t templ,templ2; + int tempz; + int tempi; + /*Limit the amount of time the instruction is uninterruptable for, so + that high frequency timers still work okay. This amount is different + for interpreter and recompiler*/ + int cycles_end = cycles - ((is386 && cpu_use_dynarec) ? 1000 : 100); + + cpu_reps++; + + flags_rebuild(); + of = flags; +// if (inrecomp) pclog("REP32 %04X %04X ",use32,rep32); + startrep: + temp=opcode2=readmemb(cs,cpu_state.pc); cpu_state.pc++; +// if (firstrepcycle && temp==0xA5) pclog("REP MOVSW %06X:%04X %06X:%04X\n",ds,SI,es,DI); +// if (inrecomp) pclog("REP %02X %04X\n",temp,ipc); + c=(rep32&0x200)?ECX:CX; +/* if (rep32 && (msw&1)) + { + if (temp!=0x67 && temp!=0x66 && (rep32|temp)!=0x1AB && (rep32|temp)!=0x3AB) pclog("32-bit REP %03X %08X %04X:%06X\n",temp|rep32,c,CS,pc); + }*/ + switch (temp|rep32) + { + case 0xC3: case 0x1C3: case 0x2C3: case 0x3C3: + cpu_state.pc--; + break; + case 0x08: + cpu_state.pc=ipc+1; + break; + case 0x26: case 0x126: case 0x226: case 0x326: /*ES:*/ + ea_seg = &_es; + goto startrep; + break; + case 0x2E: case 0x12E: case 0x22E: case 0x32E: /*CS:*/ + ea_seg = &_cs; + goto startrep; + case 0x36: case 0x136: case 0x236: case 0x336: /*SS:*/ + ea_seg = &_ss; + goto startrep; + case 0x3E: case 0x13E: case 0x23E: case 0x33E: /*DS:*/ + ea_seg = &_ds; + goto startrep; + case 0x64: case 0x164: case 0x264: case 0x364: /*FS:*/ + ea_seg = &_fs; + goto startrep; + case 0x65: case 0x165: case 0x265: case 0x365: /*GS:*/ + ea_seg = &_gs; + goto startrep; + case 0x66: case 0x166: case 0x266: case 0x366: /*Data size prefix*/ + rep32 = (rep32 & 0x200) | ((use32 ^ 0x100) & 0x100); + goto startrep; + case 0x67: case 0x167: case 0x267: case 0x367: /*Address size prefix*/ + rep32 = (rep32 & 0x100) | ((use32 ^ 0x200) & 0x200); + goto startrep; + case 0x6C: case 0x16C: /*REP INSB*/ +// cpu_notreps++; + if (c>0) + { + checkio_perm(DX); + temp2=inb(DX); + writememb(es,DI,temp2); + if (abrt) break; + if (flags&D_FLAG) DI--; + else DI++; + c--; + cycles-=15; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x26C: case 0x36C: /*REP INSB*/ +// cpu_notreps++; + if (c>0) + { + checkio_perm(DX); + temp2=inb(DX); + writememb(es,EDI,temp2); + if (abrt) break; + if (flags&D_FLAG) EDI--; + else EDI++; + c--; + cycles-=15; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x6D: /*REP INSW*/ +// cpu_notreps++; + if (c>0) + { +// pclog("REP INSW %04x %04x:%04x %04x\n", DX, ES, DI, CX); + tempw=inw(DX); + writememw(es,DI,tempw); + if (abrt) break; + if (flags&D_FLAG) DI-=2; + else DI+=2; + c--; + cycles-=15; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x16D: /*REP INSL*/ +// cpu_notreps++; + if (c>0) + { + templ=inl(DX); + writememl(es,DI,templ); + if (abrt) break; + if (flags&D_FLAG) DI-=4; + else DI+=4; + c--; + cycles-=15; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x26D: /*REP INSW*/ +// cpu_notreps++; + if (c>0) + { + tempw=inw(DX); + writememw(es,EDI,tempw); + if (abrt) break; + if (flags&D_FLAG) EDI-=2; + else EDI+=2; + c--; + cycles-=15; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x36D: /*REP INSL*/ +// cpu_notreps++; + if (c>0) + { + templ=inl(DX); + writememl(es,EDI,templ); + if (abrt) break; + if (flags&D_FLAG) EDI-=4; + else EDI+=4; + c--; + cycles-=15; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x6E: case 0x16E: /*REP OUTSB*/ +// cpu_notreps++; + if (c>0) + { + temp2 = readmemb(ea_seg->base, SI); + if (abrt) break; + checkio_perm(DX); + outb(DX,temp2); + if (flags&D_FLAG) SI--; + else SI++; + c--; + cycles-=14; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x26E: case 0x36E: /*REP OUTSB*/ +// cpu_notreps++; + if (c>0) + { + temp2 = readmemb(ea_seg->base, ESI); + if (abrt) break; + checkio_perm(DX); + outb(DX,temp2); + if (flags&D_FLAG) ESI--; + else ESI++; + c--; + cycles-=14; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x6F: /*REP OUTSW*/ +// cpu_notreps++; + if (c>0) + { + tempw = readmemw(ea_seg->base, SI); + if (abrt) break; +// pclog("OUTSW %04X -> %04X\n",SI,tempw); + outw(DX,tempw); + if (flags&D_FLAG) SI-=2; + else SI+=2; + c--; + cycles-=14; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x16F: /*REP OUTSL*/ +// cpu_notreps++; + if (c > 0) + { + templ = readmeml(ea_seg->base, SI); + if (abrt) break; + outl(DX, templ); + if (flags & D_FLAG) SI -= 4; + else SI += 4; + c--; + cycles -= 14; + } + if (c > 0) { firstrepcycle = 0; cpu_state.pc = ipc; } + else firstrepcycle = 1; + break; + case 0x26F: /*REP OUTSW*/ +// cpu_notreps++; + if (c>0) + { + tempw = readmemw(ea_seg->base, ESI); + if (abrt) break; + outw(DX,tempw); + if (flags&D_FLAG) ESI-=2; + else ESI+=2; + c--; + cycles-=14; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x36F: /*REP OUTSL*/ +// cpu_notreps++; + if (c > 0) + { + templ = readmeml(ea_seg->base, ESI); + if (abrt) break; + outl(DX, templ); + if (flags & D_FLAG) ESI -= 4; + else ESI += 4; + c--; + cycles -= 14; + } + if (c > 0) { firstrepcycle = 0; cpu_state.pc = ipc; } + else firstrepcycle = 1; + break; + case 0x90: case 0x190: /*REP NOP*/ + case 0x290: case 0x390: +// cpu_notreps++; + break; + case 0xA4: case 0x1A4: /*REP MOVSB*/ + while (c > 0) + { + CHECK_WRITE_REP(&_es, DI, DI); + temp2 = readmemb(ea_seg->base, SI); if (abrt) break; + writememb(es,DI,temp2); if (abrt) break; +// if (output==3) pclog("MOVSB %08X:%04X -> %08X:%04X %02X\n",ds,SI,es,DI,temp2); + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + c--; + cycles-=(is486)?3:4; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x2A4: case 0x3A4: /*REP MOVSB*/ + while (c > 0) + { + CHECK_WRITE_REP(&_es, EDI, EDI); + temp2 = readmemb(ea_seg->base, ESI); if (abrt) break; + writememb(es,EDI,temp2); if (abrt) break; + if (flags&D_FLAG) { EDI--; ESI--; } + else { EDI++; ESI++; } + c--; + cycles-=(is486)?3:4; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0xA5: /*REP MOVSW*/ + while (c > 0) + { + CHECK_WRITE_REP(&_es, DI, DI+1); + tempw = readmemw(ea_seg->base, SI); if (abrt) break; + writememw(es,DI,tempw); if (abrt) break; + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + c--; + cycles-=(is486)?3:4; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x1A5: /*REP MOVSL*/ + while (c > 0) + { + CHECK_WRITE_REP(&_es, DI, DI+3); + templ = readmeml(ea_seg->base, SI); if (abrt) break; +// pclog("MOVSD %08X from %08X to %08X (%04X:%08X)\n", templ, ds+SI, es+DI, CS, pc); + writememl(es,DI,templ); if (abrt) break; + if (flags&D_FLAG) { DI-=4; SI-=4; } + else { DI+=4; SI+=4; } + c--; + cycles-=(is486)?3:4; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x2A5: /*REP MOVSW*/ + while (c > 0) + { + CHECK_WRITE_REP(&_es, EDI, EDI+1); + tempw = readmemw(ea_seg->base, ESI); if (abrt) break; + writememw(es,EDI,tempw); if (abrt) break; +// if (output) pclog("Written %04X from %08X to %08X %i %08X %04X %08X %04X\n",tempw,ds+ESI,es+EDI,c,ds,ES,es,ES); + if (flags&D_FLAG) { EDI-=2; ESI-=2; } + else { EDI+=2; ESI+=2; } + c--; + cycles-=(is486)?3:4; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x3A5: /*REP MOVSL*/ + while (c > 0) + { + CHECK_WRITE_REP(&_es, EDI, EDI+3); + templ = readmeml(ea_seg->base, ESI); if (abrt) break; +// if ((EDI&0xFFFF0000)==0xA0000) cycles-=12; + writememl(es,EDI,templ); if (abrt) break; +// if (output) pclog("Load %08X from %08X to %08X %04X %08X %04X %08X\n",templ,ESI,EDI,DS,ds,ES,es); + if (flags&D_FLAG) { EDI-=4; ESI-=4; } + else { EDI+=4; ESI+=4; } + c--; + cycles-=(is486)?3:4; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0xA6: case 0x1A6: /*REP CMPSB*/ +// cpu_notreps++; + tempz = (fv) ? 1 : 0; + if ((c>0) && (fv==tempz)) + { + temp = readmemb(ea_seg->base, SI); + temp2=readmemb(es,DI); + if (abrt) { flags=of; break; } + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + c--; + cycles-=(is486)?7:9; + setsub8(temp,temp2); + tempz = (ZF_SET()) ? 1 : 0; + } + if ((c>0) && (fv==tempz)) { cpu_state.pc=ipc; firstrepcycle=0; } + else firstrepcycle=1; + break; + case 0x2A6: case 0x3A6: /*REP CMPSB*/ +// cpu_notreps++; + tempz = (fv) ? 1 : 0; + if ((c>0) && (fv==tempz)) + { + temp = readmemb(ea_seg->base, ESI); + temp2=readmemb(es,EDI); + if (abrt) { flags=of; break; } + if (flags&D_FLAG) { EDI--; ESI--; } + else { EDI++; ESI++; } + c--; + cycles-=(is486)?7:9; + setsub8(temp,temp2); + tempz = (ZF_SET()) ? 1 : 0; + } + if ((c>0) && (fv==tempz)) { cpu_state.pc=ipc; firstrepcycle=0; } + else firstrepcycle=1; + break; + case 0xA7: /*REP CMPSW*/ +// cpu_notreps++; + tempz = (fv) ? 1 : 0; + if ((c>0) && (fv==tempz)) + { +// pclog("CMPSW (%04x:%04x)%05X (%04x:%04x)%05X ", DS,SI, ds+SI, ES,DI, es+DI); + tempw = readmemw(ea_seg->base, SI); + tempw2=readmemw(es,DI); +// pclog("%04X %04X %c%c %c%c\n", tempw, tempw2, tempw & 0xff, tempw >> 8, tempw2 & 0xff, tempw2 >> 8); + + if (abrt) { flags=of; break; } + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + c--; + cycles-=(is486)?7:9; + setsub16(tempw,tempw2); + tempz = (ZF_SET()) ? 1 : 0; + } + if ((c>0) && (fv==tempz)) { cpu_state.pc=ipc; firstrepcycle=0; } + else firstrepcycle=1; + break; + case 0x1A7: /*REP CMPSL*/ +// cpu_notreps++; + tempz = (fv) ? 1 : 0; + if ((c>0) && (fv==tempz)) + { + templ = readmeml(ea_seg->base, SI); + templ2=readmeml(es,DI); + if (abrt) { flags=of; break; } + if (flags&D_FLAG) { DI-=4; SI-=4; } + else { DI+=4; SI+=4; } + c--; + cycles-=(is486)?7:9; + setsub32(templ,templ2); + tempz = (ZF_SET()) ? 1 : 0; + } + if ((c>0) && (fv==tempz)) { cpu_state.pc=ipc; firstrepcycle=0; } + else firstrepcycle=1; + break; + case 0x2A7: /*REP CMPSW*/ +// cpu_notreps++; + tempz = (fv) ? 1 : 0; + if ((c>0) && (fv==tempz)) + { + tempw = readmemw(ea_seg->base, ESI); + tempw2=readmemw(es,EDI); + if (abrt) { flags=of; break; } + if (flags&D_FLAG) { EDI-=2; ESI-=2; } + else { EDI+=2; ESI+=2; } + c--; + cycles-=(is486)?7:9; + setsub16(tempw,tempw2); + tempz = (ZF_SET()) ? 1 : 0; + } + if ((c>0) && (fv==tempz)) { cpu_state.pc=ipc; firstrepcycle=0; } + else firstrepcycle=1; + break; + case 0x3A7: /*REP CMPSL*/ +// cpu_notreps++; + tempz = (fv) ? 1 : 0; + if ((c>0) && (fv==tempz)) + { + templ = readmeml(ea_seg->base, ESI); + templ2=readmeml(es,EDI); + if (abrt) { flags=of; break; } + if (flags&D_FLAG) { EDI-=4; ESI-=4; } + else { EDI+=4; ESI+=4; } + c--; + cycles-=(is486)?7:9; + setsub32(templ,templ2); + tempz = (ZF_SET()) ? 1 : 0; + } + if ((c>0) && (fv==tempz)) { cpu_state.pc=ipc; firstrepcycle=0; } + else firstrepcycle=1; + break; + + case 0xAA: case 0x1AA: /*REP STOSB*/ + while (c > 0) + { + CHECK_WRITE_REP(&_es, DI, DI); + writememb(es,DI,AL); + if (abrt) break; + if (flags&D_FLAG) DI--; + else DI++; + c--; + cycles-=(is486)?4:5; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x2AA: case 0x3AA: /*REP STOSB*/ + while (c > 0) + { + CHECK_WRITE_REP(&_es, EDI, EDI); + writememb(es,EDI,AL); + if (abrt) break; + if (flags&D_FLAG) EDI--; + else EDI++; + c--; + cycles-=(is486)?4:5; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0xAB: /*REP STOSW*/ + while (c > 0) + { + CHECK_WRITE_REP(&_es, DI, DI+1); + writememw(es,DI,AX); + if (abrt) break; + if (flags&D_FLAG) DI-=2; + else DI+=2; + c--; + cycles-=(is486)?4:5; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x2AB: /*REP STOSW*/ + while (c > 0) + { + CHECK_WRITE_REP(&_es, EDI, EDI+1); + writememw(es,EDI,AX); + if (abrt) break; + if (flags&D_FLAG) EDI-=2; + else EDI+=2; + c--; + cycles-=(is486)?4:5; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x1AB: /*REP STOSL*/ + while (c > 0) + { + CHECK_WRITE_REP(&_es, DI, DI+3); + writememl(es,DI,EAX); + if (abrt) break; + if (flags&D_FLAG) DI-=4; + else DI+=4; + c--; + cycles-=(is486)?4:5; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x3AB: /*REP STOSL*/ + while (c > 0) + { + CHECK_WRITE_REP(&_es, EDI, EDI+3); + writememl(es,EDI,EAX); + if (abrt) break; + if (flags&D_FLAG) EDI-=4; + else EDI+=4; + c--; + cycles-=(is486)?4:5; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0xAC: case 0x1AC: /*REP LODSB*/ +// cpu_notreps++; +// if (ds==0xFFFFFFFF) pclog("Null selector REP LODSB %04X(%06X):%06X\n",CS,cs,pc); + if (c>0) + { + AL = readmemb(ea_seg->base, SI); + if (abrt) break; + if (flags&D_FLAG) SI--; + else SI++; + c--; + cycles-=5; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x2AC: case 0x3AC: /*REP LODSB*/ +// cpu_notreps++; +// if (ds==0xFFFFFFFF) pclog("Null selector REP LODSB %04X(%06X):%06X\n",CS,cs,pc); + if (c>0) + { + AL = readmemb(ea_seg->base, ESI); + if (abrt) break; + if (flags&D_FLAG) ESI--; + else ESI++; + c--; + cycles-=5; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0xAD: /*REP LODSW*/ +// cpu_notreps++; +// if (ds==0xFFFFFFFF) pclog("Null selector REP LODSW %04X(%06X):%06X\n",CS,cs,pc); + if (c>0) + { + AX = readmemw(ea_seg->base, SI); + if (abrt) break; + if (flags&D_FLAG) SI-=2; + else SI+=2; + c--; + cycles-=5; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x1AD: /*REP LODSL*/ +// cpu_notreps++; +// if (ds==0xFFFFFFFF) pclog("Null selector REP LODSL %04X(%06X):%06X\n",CS,cs,pc); + if (c>0) + { + EAX = readmeml(ea_seg->base, SI); + if (abrt) break; + if (flags&D_FLAG) SI-=4; + else SI+=4; + c--; + cycles-=5; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x2AD: /*REP LODSW*/ +// cpu_notreps++; +// if (ds==0xFFFFFFFF) pclog("Null selector REP LODSW %04X(%06X):%06X\n",CS,cs,pc); + if (c>0) + { + AX = readmemw(ea_seg->base, ESI); + if (abrt) break; + if (flags&D_FLAG) ESI-=2; + else ESI+=2; + c--; + cycles-=5; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0x3AD: /*REP LODSL*/ +// cpu_notreps++; +// if (ds==0xFFFFFFFF) pclog("Null selector REP LODSL %04X(%06X):%06X\n",CS,cs,pc); + if (c>0) + { + EAX = readmeml(ea_seg->base, ESI); + if (abrt) break; + if (flags&D_FLAG) ESI-=4; + else ESI+=4; + c--; + cycles-=5; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; } + else firstrepcycle=1; + break; + case 0xAE: case 0x1AE: /*REP SCASB*/ + cpu_notreps++; +// if (es==0xFFFFFFFF) pclog("Null selector REP SCASB %04X(%06X):%06X\n",CS,cs,pc); +// tempz=(fv)?1:0; + tempz = (fv) ? 1 : 0; + while ((c > 0) && (fv == tempz)) + { + temp2=readmemb(es,DI); + if (abrt) { flags=of; break; } + setsub8(AL,temp2); + tempz = (ZF_SET()) ? 1 : 0; + if (flags&D_FLAG) DI--; + else DI++; + c--; + cycles-=(is486)?5:8; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if ((c>0) && (fv==tempz)) { cpu_state.pc=ipc; firstrepcycle=0; } + else firstrepcycle=1; + break; + case 0x2AE: case 0x3AE: /*REP SCASB*/ + cpu_notreps++; +// if (es==0xFFFFFFFF) pclog("Null selector REP SCASB %04X(%06X):%06X\n",CS,cs,pc); +// tempz=(fv)?1:0; + tempz = (fv) ? 1 : 0; + while ((c > 0) && (fv == tempz)) + { + temp2=readmemb(es,EDI); + if (abrt) { flags=of; break; } +// if (output) pclog("Compare %02X,%02X\n",temp2,AL); + setsub8(AL,temp2); + tempz = (ZF_SET()) ? 1 : 0; + if (flags&D_FLAG) EDI--; + else EDI++; + c--; + cycles-=(is486)?5:8; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if ((c>0) && (fv==tempz)) { cpu_state.pc=ipc; firstrepcycle=0; } + else firstrepcycle=1; + break; + case 0xAF: /*REP SCASW*/ + cpu_notreps++; +// if (es==0xFFFFFFFF) pclog("Null selector REP SCASW %04X(%06X):%06X\n",CS,cs,pc); + tempz = (fv) ? 1 : 0; + while ((c > 0) && (fv == tempz)) + { + tempw=readmemw(es,DI); + if (abrt) { flags=of; break; } + setsub16(AX,tempw); + tempz = (ZF_SET()) ? 1 : 0; + if (flags&D_FLAG) DI-=2; + else DI+=2; + c--; + cycles-=(is486)?5:8; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if ((c>0) && (fv==tempz)) { cpu_state.pc=ipc; firstrepcycle=0; } + else firstrepcycle=1; + break; + case 0x1AF: /*REP SCASL*/ + cpu_notreps++; +// if (es==0xFFFFFFFF) pclog("Null selector REP SCASL %04X(%06X):%06X\n",CS,cs,pc); + tempz = (fv) ? 1 : 0; + while ((c > 0) && (fv == tempz)) + { + templ=readmeml(es,DI); + if (abrt) { flags=of; break; } + setsub32(EAX,templ); + tempz = (ZF_SET()) ? 1 : 0; + if (flags&D_FLAG) DI-=4; + else DI+=4; + c--; + cycles-=(is486)?5:8; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if ((c>0) && (fv==tempz)) { cpu_state.pc=ipc; firstrepcycle=0; } + else firstrepcycle=1; + break; + case 0x2AF: /*REP SCASW*/ + cpu_notreps++; +// if (es==0xFFFFFFFF) pclog("Null selector REP SCASW %04X(%06X):%06X\n",CS,cs,pc); + tempz = (fv) ? 1 : 0; + while ((c > 0) && (fv == tempz)) + { + tempw=readmemw(es,EDI); + if (abrt) { flags=of; break; } + setsub16(AX,tempw); + tempz = (ZF_SET()) ? 1 : 0; + if (flags&D_FLAG) EDI-=2; + else EDI+=2; + c--; + cycles-=(is486)?5:8; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if ((c>0) && (fv==tempz)) { cpu_state.pc=ipc; firstrepcycle=0; } + else firstrepcycle=1; + break; + case 0x3AF: /*REP SCASL*/ + cpu_notreps++; +// if (es==0xFFFFFFFF) pclog("Null selector REP SCASL %04X(%06X):%06X\n",CS,cs,pc); + tempz = (fv) ? 1 : 0; + while ((c > 0) && (fv == tempz)) + { + templ=readmeml(es,EDI); + if (abrt) { flags=of; break; } + setsub32(EAX,templ); + tempz = (ZF_SET()) ? 1 : 0; + if (flags&D_FLAG) EDI-=4; + else EDI+=4; + c--; + cycles-=(is486)?5:8; + ins++; + if (cycles < cycles_end) + break; + } + ins--; + if ((c>0) && (fv==tempz)) { cpu_state.pc=ipc; firstrepcycle=0; } + else firstrepcycle=1; + break; + + + default: + cpu_state.pc = ipc+1; + //pclog("Bad REP %02X %i\n", temp, rep32 >> 8); + break; + } + if (rep32&0x200) ECX=c; + else CX=c; + CPU_BLOCK_END(); + return abrt; +//pclog("rep cpu_block_end=%d %p\n", cpu_block_end, (void *)&cpu_block_end); +// if (output) pclog("%03X %03X\n",rep32,use32); +} + +int checkio(int port) +{ + uint16_t t; + uint8_t d; + cpl_override = 1; + t = readmemw(tr.base, 0x66); + cpl_override = 0; +// pclog("CheckIO 1 %08X %04x %02x\n",tr.base, eflags, _cs.access); + if (abrt) return 0; +// pclog("CheckIO %04X %01X %01X %02X %04X %04X %08X ",CS,CPL,IOPL,port,t,t+(port>>3),tr.base+t+(port>>3)); + if ((t+(port>>3))>tr.limit) return 1; + cpl_override = 1; + // d = readmemb386l(0, tr.base + t + (port >> 3)); + d=readmemb(tr.base,t+(port>>3)); + cpl_override = 0; + if (d&(1<<(port&7))) pclog("%02X %02X %08X:%04X\n",d,d&(1<<(port&7)), tr.base, t); + if ((port & 0xfff8) == 0x1f0) + { + // if (d&(1<<(port&7))) fatal("Trying to read from IDE port %04X without permission\n", port); + } + return d&(1<<(port&7)); +} + +int xout=0; + + +#define divexcp() { \ + pclog("Divide exception at %04X(%06X):%04X\n",CS,cs,cpu_state.pc); \ + x86_int(0); \ +} + +int divl(uint32_t val) +{ + if (val==0) + { + divexcp(); + return 1; + } + uint64_t num=(((uint64_t)EDX)<<32)|EAX; + uint64_t quo=num/val; + uint32_t rem=num%val; + uint32_t quo32=(uint32_t)(quo&0xFFFFFFFF); + if (quo!=(uint64_t)quo32) + { + divexcp(); + return 1; + } + EDX=rem; + EAX=quo32; + return 0; +} +int idivl(int32_t val) +{ + if (val==0) + { + divexcp(); + return 1; + } + int64_t num=(((uint64_t)EDX)<<32)|EAX; + int64_t quo=num/val; + int32_t rem=num%val; + int32_t quo32=(int32_t)(quo&0xFFFFFFFF); + if (quo!=(int64_t)quo32) + { + divexcp(); + return 1; + } + EDX=rem; + EAX=quo32; + return 0; +} + + +void cpu_386_flags_extract() +{ + flags_extract(); +} +void cpu_386_flags_rebuild() +{ + flags_rebuild(); +} + +int oldi; + +uint32_t testr[9]; +int dontprint=0; + +#define OP_TABLE(name) ops_ ## name +#define CLOCK_CYCLES(c) cycles -= (c) +#define CLOCK_CYCLES_ALWAYS(c) cycles -= (c) + +#include "386_ops.h" + + +#define CACHE_ON() (!(cr0 & (1 << 30)) /*&& (cr0 & 1)*/ && !(flags & T_FLAG)) +//#define CACHE_ON() 0 + +static int cycles_main = 0; +void exec386_dynarec(int cycs) +{ + uint8_t temp; + uint32_t addr; + int tempi; + int cycdiff; + int oldcyc; + +//output = 3; + cycles_main += cycs; + while (cycles_main > 0) + { + int cycles_start; + + cycles += 1000; + cycles_start = cycles; + + timer_start_period(cycles << TIMER_SHIFT); +// output=3; + while (cycles>0) + { + oldcs = CS; + oldpc = cpu_state.pc; + oldcpl = CPL; + op32 = use32; + + + cycdiff=0; + oldcyc=cycles; +// if (output && CACHE_ON()) pclog("Block %04x:%04x %04x:%08x\n", CS, pc, SS,ESP); + if (!CACHE_ON()) /*Interpret block*/ + { + cpu_block_end = 0; +// if (output) pclog("Interpret block at %04x:%04x %04x %04x %04x %04x %04x %04x %04x\n", CS, pc, AX, BX, CX, DX, SI, DI, SP); + while (!cpu_block_end) + { + oldcs=CS; + oldpc=cpu_state.pc; + oldcpl=CPL; + op32=use32; + + ea_seg = &_ds; + ssegs = 0; + + opcodestart: + fetchdat = fastreadl(cs + cpu_state.pc); +// if (!fetchdat) +// fatal("Dead with cache off\n"); + if (!abrt) + { + trap = flags & T_FLAG; + opcode = fetchdat & 0xFF; + fetchdat >>= 8; + +// if (output == 3) +// pclog("int %04X(%06X):%04X : %08X %08X %08X %08X %04X %04X %04X(%08X) %04X %04X %04X(%08X) %08X %08X %08X SP=%04X:%08X %02X %04X %i %08X %08X %i %i %02X %02X %02X %02X %02X %f %02X%02X %02X%02X\n",CS,cs,pc,EAX,EBX,ECX,EDX,CS,DS,ES,es,FS,GS,SS,ss,EDI,ESI,EBP,SS,ESP,opcode,flags,ins,0, ldt.base, CPL, stack32, pic.pend, pic.mask, pic.mask2, pic2.pend, pic2.mask, pit.c[0], ram[0x8f13f], ram[0x8f13e], ram[0x8f141], ram[0x8f140]); + + cpu_state.pc++; + x86_opcodes[(opcode | op32) & 0x3ff](fetchdat); + } + + if (!use32) cpu_state.pc &= 0xffff; + + if (((cs + cpu_state.pc) >> 12) != pccache) + CPU_BLOCK_END(); + +/* if (ssegs) + { + ds=oldds; + ss=oldss; + ssegs=0; + }*/ + if (abrt) + CPU_BLOCK_END(); + if (trap) + CPU_BLOCK_END(); + + ins++; + insc++; + +/* if ((cs + pc) == 4) + fatal("4\n");*/ +/* if (ins >= 141400000) + output = 3;*/ + } + } + else + { + uint32_t phys_addr = get_phys(cs+cpu_state.pc); + int hash = HASH(phys_addr); + codeblock_t *block = codeblock_hash[hash]; + int valid_block = 0; + trap = 0; + + if (block && !abrt) + { + page_t *page = &pages[phys_addr >> 12]; + + /*Block must match current CS, PC, code segment size, + and physical address. The physical address check will + also catch any page faults at this stage*/ + valid_block = (block->pc == cs + cpu_state.pc) && (block->_cs == cs) && + (block->use32 == use32) && (block->phys == phys_addr) && (block->stack32 == stack32); + if (!valid_block) + { + uint64_t mask = (uint64_t)1 << ((phys_addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); + + if (page->code_present_mask & mask) + { + /*Walk page tree to see if we find the correct block*/ + codeblock_t *new_block = codeblock_tree_find(phys_addr); + if (new_block) + { + valid_block = (new_block->pc == cs + cpu_state.pc) && (new_block->_cs == cs) && + (new_block->use32 == use32) && (new_block->phys == phys_addr) && (new_block->stack32 == stack32); + if (valid_block) + block = new_block; + } + } + } + if (valid_block && (block->page_mask & page->dirty_mask)) + { + codegen_check_flush(page, page->dirty_mask, phys_addr); + page->dirty_mask = 0; + if (!block->pc) + valid_block = 0; + } + if (valid_block && block->page_mask2) + { + /*We don't want the second page to cause a page + fault at this stage - that would break any + code crossing a page boundary where the first + page is present but the second isn't. Instead + allow the first page to be interpreted and for + the page fault to occur when the page boundary + is actually crossed.*/ + uint32_t phys_addr_2 = get_phys_noabrt(block->endpc) & ~0xfff; + page_t *page_2 = &pages[phys_addr_2 >> 12]; + + if ((block->phys_2 ^ phys_addr_2) & ~0xfff) + valid_block = 0; + else if (block->page_mask2 & page_2->dirty_mask) + { + codegen_check_flush(page_2, page_2->dirty_mask, phys_addr_2); + page_2->dirty_mask = 0; + if (!block->pc) + valid_block = 0; + } + } + } + + if (valid_block) + { + void (*code)() = (void *)&block->data[BLOCK_START]; + + codeblock_hash[hash] = block; +// if (output) pclog("Run block at %04x:%04x %04x %04x %04x %04x %04x %04x ESP=%08x %04x %08x %08x %016llx %08x\n", CS, pc, AX, BX, CX, DX, SI, DI, ESP, BP, get_phys(cs+pc), block->phys, block->page_mask, block->endpc); + +inrecomp=1; + code(); +inrecomp=0; + if (!use32) cpu_state.pc &= 0xffff; +// cpu_recomp_ins += block->ins; + cpu_recomp_blocks++; +/* ins += codeblock_ins[index]; + insc += codeblock_ins[index];*/ +/* pclog("Exit block now %04X:%04X\n", CS, pc);*/ + } + else if (!abrt) + { + uint32_t start_page = cpu_state.pc >> 12; + uint32_t start_pc = cpu_state.pc; + +// pclog("Hash %08x %i\n", codeblock_hash_pc[HASH(cs + pc)], codeblock_page_dirty[(cs + pc) >> 12]); + cpu_block_end = 0; + x86_was_reset = 0; + + cpu_new_blocks++; + + codegen_block_init(phys_addr); + codegen_in_recompile = 1; + +// if (output) pclog("Recompile block at %04x:%04x %04x %04x %04x %04x %04x %04x ESP=%04x %04x %02x%02x:%02x%02x %02x%02x:%02x%02x %02x%02x:%02x%02x\n", CS, pc, AX, BX, CX, DX, SI, DI, ESP, BP, ram[0x116330+0x6df4+0xa+3], ram[0x116330+0x6df4+0xa+2], ram[0x116330+0x6df4+0xa+1], ram[0x116330+0x6df4+0xa+0], ram[0x11d136+3],ram[0x11d136+2],ram[0x11d136+1],ram[0x11d136+0], ram[(0x119abe)+0x3],ram[(0x119abe)+0x2],ram[(0x119abe)+0x1],ram[(0x119abe)+0x0]); + while (!cpu_block_end) + { + oldcs=CS; + oldpc=cpu_state.pc; + oldcpl=CPL; + op32=use32; + + ea_seg = &_ds; + ssegs = 0; + + opcodestart_compile: + fetchdat = fastreadl(cs + cpu_state.pc); +// if (fetchdat == 0xffffffff) +// fatal("Dead ffffffff\n"); +// if (!fetchdat) +// fatal("Dead\n"); + if (!abrt) + { + trap = flags & T_FLAG; + opcode = fetchdat & 0xFF; + fetchdat >>= 8; + +// if (output == 3) +// pclog("%04X(%06X):%04X : %08X %08X %08X %08X %04X %04X %04X(%08X) %04X %04X %04X(%08X) %08X %08X %08X SP=%04X:%08X %02X %04X %i %08X %08X %i %i %02X %02X %02X %02X %02X %08x %08x\n",CS,cs,pc,EAX,EBX,ECX,EDX,CS,DS,ES,es,FS,GS,SS,ss,EDI,ESI,EBP,SS,ESP,opcode,flags,ins,0, ldt.base, CPL, stack32, pic.pend, pic.mask, pic.mask2, pic2.pend, pic2.mask, cs+pc, pccache); + + cpu_state.pc++; + + codegen_generate_call(opcode, x86_opcodes[(opcode | op32) & 0x3ff], fetchdat, cpu_state.pc, cpu_state.pc-1); + + x86_opcodes[(opcode | op32) & 0x3ff](fetchdat); + + if (x86_was_reset) + break; + } + + if (!use32) cpu_state.pc &= 0xffff; + + /*Cap source code at 4000 bytes per block; this + will prevent any block from spanning more than + 2 pages. In practice this limit will never be + hit, as host block size is only 2kB*/ + if ((cpu_state.pc - start_pc) > 4000) + CPU_BLOCK_END(); + + if (trap) + CPU_BLOCK_END(); + + + if (abrt) + { + codegen_block_remove(); + CPU_BLOCK_END(); + } + + ins++; + insc++; + } + + if (!abrt && !x86_was_reset) + codegen_block_end(); + + if (x86_was_reset) + codegen_reset(); + + codegen_in_recompile = 0; +// output &= ~2; + } +// if (output && (SP & 1)) +// fatal("odd SP\n"); + } + + cycdiff=oldcyc-cycles; + tsc += cycdiff; + +// timer_end_period(cycles); + + if (abrt) + { + flags_rebuild(); + tempi = abrt; + abrt = 0; + x86_doabrt(tempi); + if (abrt) + { + abrt = 0; + CS = oldcs; + cpu_state.pc = oldpc; + pclog("Double fault %i\n", ins); + pmodeint(8, 0); + if (abrt) + { + abrt = 0; + softresetx86(); + pclog("Triple fault - reset\n"); + } + } + } + + if (trap) + { + + flags_rebuild(); +// oldpc=pc; +// oldcs=CS; + if (msw&1) + { + pmodeint(1,0); + } + else + { + writememw(ss,(SP-2)&0xFFFF,flags); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + addr = (1 << 2) + idt.base; + flags&=~I_FLAG; + flags&=~T_FLAG; + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + } + } + else if ((flags&I_FLAG) && pic_intpending) + { + temp=picinterrupt(); + if (temp!=0xFF) + { +// pclog("IRQ %02X %04X:%04X %04X:%04X\n", temp, SS, SP, CS, pc); + CPU_BLOCK_END(); + flags_rebuild(); + if (msw&1) + { + pmodeint(temp,0); + } + else + { + writememw(ss,(SP-2)&0xFFFF,flags); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + addr=temp<<2; + flags&=~I_FLAG; + flags&=~T_FLAG; + oxpc=cpu_state.pc; + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + } + } + } + } + timer_end_period(cycles << TIMER_SHIFT); + cycles_main -= (cycles_start - cycles); + } +} diff --git a/src/386_dynarec_ops.c b/src/386_dynarec_ops.c new file mode 100644 index 000000000..bfa316488 --- /dev/null +++ b/src/386_dynarec_ops.c @@ -0,0 +1,57 @@ +#include "ibm.h" +#include "cpu.h" +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "x86_flags.h" +#include "mem.h" +#include "codegen.h" + +#define CPU_BLOCK_END() cpu_block_end = 1 + +#include "386_common.h" + + +extern uint16_t *mod1add[2][8]; +extern uint32_t *mod1seg[8]; + +static inline void fetch_ea_32_long(uint32_t rmdat) +{ + eal_r = eal_w = NULL; + easeg = ea_seg->base; + ea_rseg = ea_seg->seg; + if (easeg != 0xFFFFFFFF && ((easeg + eaaddr) & 0xFFF) <= 0xFFC) + { + uint32_t addr = easeg + eaaddr; + if ( readlookup2[addr >> 12] != -1) + eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); + if (writelookup2[addr >> 12] != -1) + eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); + } +} + +static inline void fetch_ea_16_long(uint32_t rmdat) +{ + eal_r = eal_w = NULL; + easeg = ea_seg->base; + ea_rseg = ea_seg->seg; + if (easeg != 0xFFFFFFFF && ((easeg + eaaddr) & 0xFFF) <= 0xFFC) + { + uint32_t addr = easeg + eaaddr; + if ( readlookup2[addr >> 12] != -1) + eal_r = (uint32_t *)(readlookup2[addr >> 12] + addr); + if (writelookup2[addr >> 12] != -1) + eal_w = (uint32_t *)(writelookup2[addr >> 12] + addr); + } +} + +#define fetch_ea_16(rmdat) cpu_state.pc++; if (mod != 3) fetch_ea_16_long(rmdat); +#define fetch_ea_32(rmdat) cpu_state.pc++; if (mod != 3) fetch_ea_32_long(rmdat); + + + +#define OP_TABLE(name) dynarec_ops_ ## name +#define CLOCK_CYCLES(c) +#define CLOCK_CYCLES_ALWAYS(c) cycles -= (c) + +#include "386_ops.h" diff --git a/src/386_ops.h b/src/386_ops.h new file mode 100644 index 000000000..2aee7194c --- /dev/null +++ b/src/386_ops.h @@ -0,0 +1,1371 @@ +#include "x86_ops.h" + + +#define ILLEGAL_ON(cond) \ + do \ + { \ + if ((cond)) \ + { \ + cpu_state.pc = oldpc; \ + x86illegal(); \ + return 0; \ + } \ + } while (0) + +static inline void PUSH_W(uint16_t val) +{ + if (stack32) + { + writememw(ss, ESP - 2, val); if (abrt) return; + ESP -= 2; + } + else + { + writememw(ss, (SP - 2) & 0xFFFF, val); if (abrt) return; + SP -= 2; + } +} + +static inline void PUSH_L(uint32_t val) +{ + if (stack32) + { + writememl(ss, ESP - 4, val); if (abrt) return; + ESP -= 4; + } + else + { + writememl(ss, (SP - 4) & 0xFFFF, val); if (abrt) return; + SP -= 4; + } +} + +static inline uint16_t POP_W() +{ + uint16_t ret; + if (stack32) + { + ret = readmemw(ss, ESP); if (abrt) return 0; + ESP += 2; + } + else + { + ret = readmemw(ss, SP); if (abrt) return 0; + SP += 2; + } + return ret; +} + +static inline uint32_t POP_L() +{ + uint32_t ret; + if (stack32) + { + ret = readmeml(ss, ESP); if (abrt) return 0; + ESP += 4; + } + else + { + ret = readmeml(ss, SP); if (abrt) return 0; + SP += 4; + } + return ret; +} + +static inline uint16_t POP_W_seg(uint32_t seg) +{ + uint16_t ret; + if (stack32) + { + ret = readmemw(seg, ESP); if (abrt) return 0; + ESP += 2; + } + else + { + ret = readmemw(seg, SP); if (abrt) return 0; + SP += 2; + } + return ret; +} + +static inline uint32_t POP_L_seg(uint32_t seg) +{ + uint32_t ret; + if (stack32) + { + ret = readmeml(seg, ESP); if (abrt) return 0; + ESP += 4; + } + else + { + ret = readmeml(seg, SP); if (abrt) return 0; + SP += 4; + } + return ret; +} + +#include "x86seg.h" +#include "x86_ops_arith.h" +#include "x86_ops_atomic.h" +#include "x86_ops_bcd.h" +#include "x86_ops_bit.h" +#include "x86_ops_bitscan.h" +#include "x86_ops_call.h" +#include "x86_ops_flag.h" +#include "x86_ops_fpu.h" +#include "x86_ops_inc_dec.h" +#include "x86_ops_int.h" +#include "x86_ops_io.h" +#include "x86_ops_jump.h" +#include "x86_ops_misc.h" +#include "x86_ops_mmx.h" +#include "x86_ops_mmx_arith.h" +#include "x86_ops_mmx_cmp.h" +#include "x86_ops_mmx_logic.h" +#include "x86_ops_mmx_mov.h" +#include "x86_ops_mmx_pack.h" +#include "x86_ops_mmx_shift.h" +#include "x86_ops_mov.h" +#include "x86_ops_mov_ctrl.h" +#include "x86_ops_mov_seg.h" +#include "x86_ops_movx.h" +#include "x86_ops_msr.h" +#include "x86_ops_mul.h" +#include "x86_ops_pmode.h" +#include "x86_ops_prefix.h" +#include "x86_ops_rep.h" +#include "x86_ops_ret.h" +#include "x86_ops_set.h" +#include "x86_ops_shift.h" +#include "x86_ops_stack.h" +#include "x86_ops_string.h" +#include "x86_ops_xchg.h" + +static int ILLEGAL(uint32_t fetchdat) +{ + cpu_state.pc = oldpc; + +// fatal("Illegal instruction %08X\n", fetchdat); + pclog("Illegal instruction %08X\n", fetchdat); + x86illegal(); + return 0; +} + +static int op0F_w_a16(uint32_t fetchdat) +{ + int opcode = fetchdat & 0xff; + cpu_state.pc++; + + // pclog("A16W: 0F %02X\n", opcode); + return x86_opcodes_0f[opcode](fetchdat >> 8); +} +static int op0F_l_a16(uint32_t fetchdat) +{ + int opcode = fetchdat & 0xff; + cpu_state.pc++; + + // pclog("A16L: 0F %02X\n", opcode); + return x86_opcodes_0f[opcode | 0x100](fetchdat >> 8); +} +static int op0F_w_a32(uint32_t fetchdat) +{ + int opcode = fetchdat & 0xff; + cpu_state.pc++; + + // pclog("A32W: 0F %02X\n", opcode); + return x86_opcodes_0f[opcode | 0x200](fetchdat >> 8); +} +static int op0F_l_a32(uint32_t fetchdat) +{ + int opcode = fetchdat & 0xff; + cpu_state.pc++; + + // pclog("A32L: 0F %02X\n", opcode); + return x86_opcodes_0f[opcode | 0x300](fetchdat >> 8); +} + +#include "x87_ops.h" +#include "x86_ops_i686.h" + +OpFn OP_TABLE(286_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_286, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*90*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*a0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*b0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_286, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*90*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*a0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*b0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_286, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*90*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*a0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*b0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_286, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opLOADALL, opCLTS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*90*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*a0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*b0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*c0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +OpFn OP_TABLE(386_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, ILLEGAL, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ ILLEGAL, ILLEGAL, opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, ILLEGAL, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ ILLEGAL, ILLEGAL, opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, ILLEGAL, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ ILLEGAL, ILLEGAL, opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, ILLEGAL, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ ILLEGAL, ILLEGAL, opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +OpFn OP_TABLE(486_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, opLOADALL386, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +OpFn OP_TABLE(winchip_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, +}; + +OpFn OP_TABLE(pentium_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +OpFn OP_TABLE(pentiummmx_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, +}; + +OpFn OP_TABLE(k6_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, opSYSCALL, opCLTS, opSYSRET, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, opSYSCALL, opCLTS, opSYSRET, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, opSYSCALL, opCLTS, opSYSRET, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, opSYSCALL, opCLTS, opSYSRET, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, +}; + +OpFn OP_TABLE(c6x86mx_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a16, opCMOVNO_w_a16, opCMOVB_w_a16, opCMOVNB_w_a16, opCMOVE_w_a16, opCMOVNE_w_a16, opCMOVBE_w_a16, opCMOVNBE_w_a16,opCMOVS_w_a16, opCMOVNS_w_a16, opCMOVP_w_a16, opCMOVNP_w_a16, opCMOVL_w_a16, opCMOVNL_w_a16, opCMOVLE_w_a16, opCMOVNLE_w_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a16, opCMOVNO_l_a16, opCMOVB_l_a16, opCMOVNB_l_a16, opCMOVE_l_a16, opCMOVNE_l_a16, opCMOVBE_l_a16, opCMOVNBE_l_a16,opCMOVS_l_a16, opCMOVNS_l_a16, opCMOVP_l_a16, opCMOVNP_l_a16, opCMOVL_l_a16, opCMOVNL_l_a16, opCMOVLE_l_a16, opCMOVNLE_l_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a32, opCMOVNO_w_a32, opCMOVB_w_a32, opCMOVNB_w_a32, opCMOVE_w_a32, opCMOVNE_w_a32, opCMOVBE_w_a32, opCMOVNBE_w_a32,opCMOVS_w_a32, opCMOVNS_w_a32, opCMOVP_w_a32, opCMOVNP_w_a32, opCMOVL_w_a32, opCMOVNL_w_a32, opCMOVLE_w_a32, opCMOVNLE_w_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a32, opCMOVNO_l_a32, opCMOVB_l_a32, opCMOVNB_l_a32, opCMOVE_l_a32, opCMOVNE_l_a32, opCMOVBE_l_a32, opCMOVNBE_l_a32,opCMOVS_l_a32, opCMOVNS_l_a32, opCMOVP_l_a32, opCMOVNP_l_a32, opCMOVL_l_a32, opCMOVNL_l_a32, opCMOVLE_l_a32, opCMOVNLE_l_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, +}; + +OpFn OP_TABLE(pentiumpro_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a16, opCMOVNO_w_a16, opCMOVB_w_a16, opCMOVNB_w_a16, opCMOVE_w_a16, opCMOVNE_w_a16, opCMOVBE_w_a16, opCMOVNBE_w_a16,opCMOVS_w_a16, opCMOVNS_w_a16, opCMOVP_w_a16, opCMOVNP_w_a16, opCMOVL_w_a16, opCMOVNL_w_a16, opCMOVLE_w_a16, opCMOVNLE_w_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a16, opCMOVNO_l_a16, opCMOVB_l_a16, opCMOVNB_l_a16, opCMOVE_l_a16, opCMOVNE_l_a16, opCMOVBE_l_a16, opCMOVNBE_l_a16,opCMOVS_l_a16, opCMOVNS_l_a16, opCMOVP_l_a16, opCMOVNP_l_a16, opCMOVL_l_a16, opCMOVNL_l_a16, opCMOVLE_l_a16, opCMOVNLE_l_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a32, opCMOVNO_w_a32, opCMOVB_w_a32, opCMOVNB_w_a32, opCMOVE_w_a32, opCMOVNE_w_a32, opCMOVBE_w_a32, opCMOVNBE_w_a32,opCMOVS_w_a32, opCMOVNS_w_a32, opCMOVP_w_a32, opCMOVNP_w_a32, opCMOVL_w_a32, opCMOVNL_w_a32, opCMOVLE_w_a32, opCMOVNLE_w_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a32, opCMOVNO_l_a32, opCMOVB_l_a32, opCMOVNB_l_a32, opCMOVE_l_a32, opCMOVNE_l_a32, opCMOVBE_l_a32, opCMOVNBE_l_a32,opCMOVS_l_a32, opCMOVNS_l_a32, opCMOVP_l_a32, opCMOVNP_l_a32, opCMOVL_l_a32, opCMOVNL_l_a32, opCMOVLE_l_a32, opCMOVNLE_l_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*70*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*e0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*f0*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +OpFn OP_TABLE(pentium2_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a16, opCMOVNO_w_a16, opCMOVB_w_a16, opCMOVNB_w_a16, opCMOVE_w_a16, opCMOVNE_w_a16, opCMOVBE_w_a16, opCMOVNBE_w_a16,opCMOVS_w_a16, opCMOVNS_w_a16, opCMOVP_w_a16, opCMOVNP_w_a16, opCMOVL_w_a16, opCMOVNL_w_a16, opCMOVLE_w_a16, opCMOVNLE_w_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,ILLEGAL, opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a16, opCMOVNO_l_a16, opCMOVB_l_a16, opCMOVNB_l_a16, opCMOVE_l_a16, opCMOVNE_l_a16, opCMOVBE_l_a16, opCMOVNBE_l_a16,opCMOVS_l_a16, opCMOVNS_l_a16, opCMOVP_l_a16, opCMOVNP_l_a16, opCMOVL_l_a16, opCMOVNL_l_a16, opCMOVLE_l_a16, opCMOVNLE_l_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,ILLEGAL, opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a32, opCMOVNO_w_a32, opCMOVB_w_a32, opCMOVNB_w_a32, opCMOVE_w_a32, opCMOVNE_w_a32, opCMOVBE_w_a32, opCMOVNBE_w_a32,opCMOVS_w_a32, opCMOVNS_w_a32, opCMOVP_w_a32, opCMOVNP_w_a32, opCMOVL_w_a32, opCMOVNL_w_a32, opCMOVLE_w_a32, opCMOVNLE_w_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,ILLEGAL, opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a32, opCMOVNO_l_a32, opCMOVB_l_a32, opCMOVNB_l_a32, opCMOVE_l_a32, opCMOVNE_l_a32, opCMOVBE_l_a32, opCMOVNBE_l_a32,opCMOVS_l_a32, opCMOVNS_l_a32, opCMOVP_l_a32, opCMOVNP_l_a32, opCMOVL_l_a32, opCMOVNL_l_a32, opCMOVLE_l_a32, opCMOVNLE_l_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,ILLEGAL, opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, +}; + +OpFn OP_TABLE(pentium2d_0f)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_w_a16, opLAR_w_a16, opLSL_w_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a16, opCMOVNO_w_a16, opCMOVB_w_a16, opCMOVNB_w_a16, opCMOVE_w_a16, opCMOVNE_w_a16, opCMOVBE_w_a16, opCMOVNBE_w_a16,opCMOVS_w_a16, opCMOVNS_w_a16, opCMOVP_w_a16, opCMOVNP_w_a16, opCMOVL_w_a16, opCMOVNL_w_a16, opCMOVLE_w_a16, opCMOVNLE_w_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a16, opSHLD_w_i_a16, opSHLD_w_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a16, opSHRD_w_i_a16, opSHRD_w_CL_a16,opFXSAVESTOR_a16,opIMUL_w_w_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_w_a16,opLSS_w_a16, opBTR_w_r_a16, opLFS_w_a16, opLGS_w_a16, opMOVZX_w_b_a16,opMOVZX_w_w_a16,ILLEGAL, ILLEGAL, opBA_w_a16, opBTC_w_r_a16, opBSF_w_a16, opBSR_w_a16, opMOVSX_w_b_a16,ILLEGAL, + +/*c0*/ opXADD_b_a16, opXADD_w_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a16, op0F01_l_a16, opLAR_l_a16, opLSL_l_a16, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a16,opMOV_r_DRx_a16,opMOV_CRx_r_a16,opMOV_DRx_r_a16,opMOV_r_TRx_a16,ILLEGAL, opMOV_TRx_r_a16,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a16, opCMOVNO_l_a16, opCMOVB_l_a16, opCMOVNB_l_a16, opCMOVE_l_a16, opCMOVNE_l_a16, opCMOVBE_l_a16, opCMOVNBE_l_a16,opCMOVS_l_a16, opCMOVNS_l_a16, opCMOVP_l_a16, opCMOVNP_l_a16, opCMOVL_l_a16, opCMOVNL_l_a16, opCMOVLE_l_a16, opCMOVNLE_l_a16, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a16,opPUNPCKLWD_a16,opPUNPCKLDQ_a16,opPACKSSWB_a16, opPCMPGTB_a16, opPCMPGTW_a16, opPCMPGTD_a16, opPACKUSWB_a16, opPUNPCKHBW_a16,opPUNPCKHWD_a16,opPUNPCKHDQ_a16,opPACKSSDW_a16, ILLEGAL, ILLEGAL, opMOVD_l_mm_a16,opMOVQ_q_mm_a16, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a16, opPCMPEQW_a16, opPCMPEQD_a16, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a16,opMOVQ_mm_q_a16, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a16, opSETNO_a16, opSETB_a16, opSETNB_a16, opSETE_a16, opSETNE_a16, opSETBE_a16, opSETNBE_a16, opSETS_a16, opSETNS_a16, opSETP_a16, opSETNP_a16, opSETL_a16, opSETNL_a16, opSETLE_a16, opSETNLE_a16, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a16, opSHLD_l_i_a16, opSHLD_l_CL_a16,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a16, opSHRD_l_i_a16, opSHRD_l_CL_a16,opFXSAVESTOR_a16,opIMUL_l_l_a16, +/*b0*/ opCMPXCHG_b_a16,opCMPXCHG_l_a16,opLSS_l_a16, opBTR_l_r_a16, opLFS_l_a16, opLGS_l_a16, opMOVZX_l_b_a16,opMOVZX_l_w_a16,ILLEGAL, ILLEGAL, opBA_l_a16, opBTC_l_r_a16, opBSF_l_a16, opBSR_l_a16, opMOVSX_l_b_a16,opMOVSX_l_w_a16, + +/*c0*/ opXADD_b_a16, opXADD_l_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a16,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a16, opPSRLD_a16, opPSRLQ_a16, ILLEGAL, opPMULLW_a16, ILLEGAL, ILLEGAL, opPSUBUSB_a16, opPSUBUSW_a16, NULL, opPAND_a16, opPADDUSB_a16, opPADDUSW_a16, NULL, opPANDN_a16, +/*e0*/ ILLEGAL, opPSRAW_a16, opPSRAD_a16, ILLEGAL, ILLEGAL, opPMULHW_a16, ILLEGAL, ILLEGAL, opPSUBSB_a16, opPSUBSW_a16, NULL, opPOR_a16, opPADDSB_a16, opPADDSW_a16, NULL, opPXOR_a16, +/*f0*/ ILLEGAL, opPSLLW_a16, opPSLLD_a16, opPSLLQ_a16, ILLEGAL, opPMADDWD_a16, ILLEGAL, ILLEGAL, opPSUBB_a16, opPSUBW_a16, opPSUBD_a16, ILLEGAL, opPADDB_a16, opPADDW_a16, opPADDD_a16, ILLEGAL, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_w_a32, opLAR_w_a32, opLSL_w_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_w_a32, opCMOVNO_w_a32, opCMOVB_w_a32, opCMOVNB_w_a32, opCMOVE_w_a32, opCMOVNE_w_a32, opCMOVBE_w_a32, opCMOVNBE_w_a32,opCMOVS_w_a32, opCMOVNS_w_a32, opCMOVP_w_a32, opCMOVNP_w_a32, opCMOVL_w_a32, opCMOVNL_w_a32, opCMOVLE_w_a32, opCMOVNLE_w_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_w, opJNO_w, opJB_w, opJNB_w, opJE_w, opJNE_w, opJBE_w, opJNBE_w, opJS_w, opJNS_w, opJP_w, opJNP_w, opJL_w, opJNL_w, opJLE_w, opJNLE_w, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_w, opPOP_FS_w, opCPUID, opBT_w_r_a32, opSHLD_w_i_a32, opSHLD_w_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_w, opPOP_GS_w, ILLEGAL, opBTS_w_r_a32, opSHRD_w_i_a32, opSHRD_w_CL_a32,opFXSAVESTOR_a32,opIMUL_w_w_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_w_a32,opLSS_w_a32, opBTR_w_r_a32, opLFS_w_a32, opLGS_w_a32, opMOVZX_w_b_a32,opMOVZX_w_w_a32,ILLEGAL, ILLEGAL, opBA_w_a32, opBTC_w_r_a32, opBSF_w_a32, opBSR_w_a32, opMOVSX_w_b_a32,ILLEGAL, + +/*c0*/ opXADD_b_a32, opXADD_w_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ op0F00_a32, op0F01_l_a32, opLAR_l_a32, opLSL_l_a32, ILLEGAL, ILLEGAL, opCLTS, ILLEGAL, opINVD, opWBINVD, ILLEGAL, ILLEGAL, ILLEGAL, opNOP, ILLEGAL, ILLEGAL, +/*10*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*20*/ opMOV_r_CRx_a32,opMOV_r_DRx_a32,opMOV_CRx_r_a32,opMOV_DRx_r_a32,opMOV_r_TRx_a32,ILLEGAL, opMOV_TRx_r_a32,ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*30*/ opWRMSR, opRDTSC, opRDMSR, opRDPMC, opSYSENTER, opSYSEXIT, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + +/*40*/ opCMOVO_l_a32, opCMOVNO_l_a32, opCMOVB_l_a32, opCMOVNB_l_a32, opCMOVE_l_a32, opCMOVNE_l_a32, opCMOVBE_l_a32, opCMOVNBE_l_a32,opCMOVS_l_a32, opCMOVNS_l_a32, opCMOVP_l_a32, opCMOVNP_l_a32, opCMOVL_l_a32, opCMOVNL_l_a32, opCMOVLE_l_a32, opCMOVNLE_l_a32, +/*50*/ ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +/*60*/ opPUNPCKLBW_a32,opPUNPCKLWD_a32,opPUNPCKLDQ_a32,opPACKSSWB_a32, opPCMPGTB_a32, opPCMPGTW_a32, opPCMPGTD_a32, opPACKUSWB_a32, opPUNPCKHBW_a32,opPUNPCKHWD_a32,opPUNPCKHDQ_a32,opPACKSSDW_a32, ILLEGAL, ILLEGAL, opMOVD_l_mm_a32,opMOVQ_q_mm_a32, +/*70*/ ILLEGAL, opPSxxW_imm, opPSxxD_imm, opPSxxQ_imm, opPCMPEQB_a32, opPCMPEQW_a32, opPCMPEQD_a32, opEMMS, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opMOVD_mm_l_a32,opMOVQ_mm_q_a32, + +/*80*/ opJO_l, opJNO_l, opJB_l, opJNB_l, opJE_l, opJNE_l, opJBE_l, opJNBE_l, opJS_l, opJNS_l, opJP_l, opJNP_l, opJL_l, opJNL_l, opJLE_l, opJNLE_l, +/*90*/ opSETO_a32, opSETNO_a32, opSETB_a32, opSETNB_a32, opSETE_a32, opSETNE_a32, opSETBE_a32, opSETNBE_a32, opSETS_a32, opSETNS_a32, opSETP_a32, opSETNP_a32, opSETL_a32, opSETNL_a32, opSETLE_a32, opSETNLE_a32, +/*a0*/ opPUSH_FS_l, opPOP_FS_l, opCPUID, opBT_l_r_a32, opSHLD_l_i_a32, opSHLD_l_CL_a32,ILLEGAL, ILLEGAL, opPUSH_GS_l, opPOP_GS_l, ILLEGAL, opBTS_l_r_a32, opSHRD_l_i_a32, opSHRD_l_CL_a32,opFXSAVESTOR_a32,opIMUL_l_l_a32, +/*b0*/ opCMPXCHG_b_a32,opCMPXCHG_l_a32,opLSS_l_a32, opBTR_l_r_a32, opLFS_l_a32, opLGS_l_a32, opMOVZX_l_b_a32,opMOVZX_l_w_a32,ILLEGAL, ILLEGAL, opBA_l_a32, opBTC_l_r_a32, opBSF_l_a32, opBSR_l_a32, opMOVSX_l_b_a32,opMOVSX_l_w_a32, + +/*c0*/ opXADD_b_a32, opXADD_l_a32, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opCMPXCHG8B_a32,opBSWAP_EAX, opBSWAP_ECX, opBSWAP_EDX, opBSWAP_EBX, opBSWAP_ESP, opBSWAP_EBP, opBSWAP_ESI, opBSWAP_EDI, +/*d0*/ ILLEGAL, opPSRLW_a32, opPSRLD_a32, opPSRLQ_a32, ILLEGAL, opPMULLW_a32, ILLEGAL, ILLEGAL, opPSUBUSB_a32, opPSUBUSW_a32, NULL, opPAND_a32, opPADDUSB_a32, opPADDUSW_a32, NULL, opPANDN_a32, +/*e0*/ ILLEGAL, opPSRAW_a32, opPSRAD_a32, ILLEGAL, ILLEGAL, opPMULHW_a32, ILLEGAL, ILLEGAL, opPSUBSB_a32, opPSUBSW_a32, NULL, opPOR_a32, opPADDSB_a32, opPADDSW_a32, NULL, opPXOR_a32, +/*f0*/ ILLEGAL, opPSLLW_a32, opPSLLD_a32, opPSLLQ_a32, ILLEGAL, opPMADDWD_a32, ILLEGAL, ILLEGAL, opPSUBB_a32, opPSUBW_a32, opPSUBD_a32, ILLEGAL, opPADDB_a32, opPADDW_a32, opPADDD_a32, ILLEGAL, +}; + +OpFn OP_TABLE(286)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, op80_a16, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF_286, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET_286, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, op80_a16, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF_286, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET_286, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, op80_a16, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF_286, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET_286, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, op80_a16, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF_286, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET_286, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, +}; + +OpFn OP_TABLE(386)[1024] = +{ + /*16-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_w_rmw_a16,opADD_b_rm_a16, opADD_w_rm_a16, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a16, opOR_w_rmw_a16, opOR_b_rm_a16, opOR_w_rm_a16, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a16, +/*10*/ opADC_b_rmw_a16,opADC_w_rmw_a16,opADC_b_rm_a16, opADC_w_rm_a16, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a16,opSBB_w_rmw_a16,opSBB_b_rm_a16, opSBB_w_rm_a16, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a16,opAND_w_rmw_a16,opAND_b_rm_a16, opAND_w_rm_a16, opAND_AL_imm, opAND_AX_imm, opES_w_a16, opDAA, opSUB_b_rmw_a16,opSUB_w_rmw_a16,opSUB_b_rm_a16, opSUB_w_rm_a16, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_w_rmw_a16,opXOR_b_rm_a16, opXOR_w_rm_a16, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a16, opAAA, opCMP_b_rmw_a16,opCMP_w_rmw_a16,opCMP_b_rm_a16, opCMP_w_rm_a16, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a16, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a16, opARPL_a16, opFS_w_a16, opGS_w_a16, op_66, op_67, opPUSH_imm_w, opIMUL_w_iw_a16,opPUSH_imm_bw, opIMUL_w_ib_a16,opINSB_a16, opINSW_a16, opOUTSB_a16, opOUTSW_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_w_a16, op80_a16, op83_w_a16, opTEST_b_a16, opTEST_w_a16, opXCHG_b_a16, opXCHG_w_a16, opMOV_b_r_a16, opMOV_w_r_a16, opMOV_r_b_a16, opMOV_r_w_a16, opMOV_w_seg_a16,opLEA_w_a16, opMOV_seg_w_a16,opPOPW_a16, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_AX_a16, opMOV_a16_AL, opMOV_a16_AX, opMOVSB_a16, opMOVSW_a16, opCMPSB_a16, opCMPSW_a16, opTEST_AL, opTEST_AX, opSTOSB_a16, opSTOSW_a16, opLODSB_a16, opLODSW_a16, opSCASB_a16, opSCASW_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a16, opC1_w_a16, opRET_w_imm, opRET_w, opLES_w_a16, opLDS_w_a16, opMOV_b_imm_a16,opMOV_w_imm_a16,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET, +/*d0*/ opD0_a16, opD1_w_a16, opD2_a16, opD3_w_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_w_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_w_a16, + + /*32-bit data, 16-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a16,opADD_l_rmw_a16,opADD_b_rm_a16, opADD_l_rm_a16, opADD_AL_imm, opADD_EAX_imm, opPUSH_ES_l, opPOP_ES_l, opOR_b_rmw_a16, opOR_l_rmw_a16, opOR_b_rm_a16, opOR_l_rm_a16, opOR_AL_imm, opOR_EAX_imm, opPUSH_CS_l, op0F_l_a16, +/*10*/ opADC_b_rmw_a16,opADC_l_rmw_a16,opADC_b_rm_a16, opADC_l_rm_a16, opADC_AL_imm, opADC_EAX_imm, opPUSH_SS_l, opPOP_SS_l, opSBB_b_rmw_a16,opSBB_l_rmw_a16,opSBB_b_rm_a16, opSBB_l_rm_a16, opSBB_AL_imm, opSBB_EAX_imm, opPUSH_DS_l, opPOP_DS_l, +/*20*/ opAND_b_rmw_a16,opAND_l_rmw_a16,opAND_b_rm_a16, opAND_l_rm_a16, opAND_AL_imm, opAND_EAX_imm, opES_l_a16, opDAA, opSUB_b_rmw_a16,opSUB_l_rmw_a16,opSUB_b_rm_a16, opSUB_l_rm_a16, opSUB_AL_imm, opSUB_EAX_imm, opCS_l_a16, opDAS, +/*30*/ opXOR_b_rmw_a16,opXOR_l_rmw_a16,opXOR_b_rm_a16, opXOR_l_rm_a16, opXOR_AL_imm, opXOR_EAX_imm, opSS_l_a16, opAAA, opCMP_b_rmw_a16,opCMP_l_rmw_a16,opCMP_b_rm_a16, opCMP_l_rm_a16, opCMP_AL_imm, opCMP_EAX_imm, opDS_l_a16, opAAS, + +/*40*/ opINC_EAX, opINC_ECX, opINC_EDX, opINC_EBX, opINC_ESP, opINC_EBP, opINC_ESI, opINC_EDI, opDEC_EAX, opDEC_ECX, opDEC_EDX, opDEC_EBX, opDEC_ESP, opDEC_EBP, opDEC_ESI, opDEC_EDI, +/*50*/ opPUSH_EAX, opPUSH_ECX, opPUSH_EDX, opPUSH_EBX, opPUSH_ESP, opPUSH_EBP, opPUSH_ESI, opPUSH_EDI, opPOP_EAX, opPOP_ECX, opPOP_EDX, opPOP_EBX, opPOP_ESP, opPOP_EBP, opPOP_ESI, opPOP_EDI, +/*60*/ opPUSHA_l, opPOPA_l, opBOUND_l_a16, opARPL_a16, opFS_l_a16, opGS_l_a16, op_66, op_67, opPUSH_imm_l, opIMUL_l_il_a16,opPUSH_imm_bl, opIMUL_l_ib_a16,opINSB_a16, opINSL_a16, opOUTSB_a16, opOUTSL_a16, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a16, op81_l_a16, op80_a16, op83_l_a16, opTEST_b_a16, opTEST_l_a16, opXCHG_b_a16, opXCHG_l_a16, opMOV_b_r_a16, opMOV_l_r_a16, opMOV_r_b_a16, opMOV_r_l_a16, opMOV_l_seg_a16,opLEA_l_a16, opMOV_seg_w_a16,opPOPL_a16, +/*90*/ opNOP, opXCHG_EAX_ECX, opXCHG_EAX_EDX, opXCHG_EAX_EBX, opXCHG_EAX_ESP, opXCHG_EAX_EBP, opXCHG_EAX_ESI, opXCHG_EAX_EDI, opCWDE, opCDQ, opCALL_far_l, opWAIT, opPUSHFD, opPOPFD, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a16, opMOV_EAX_a16, opMOV_a16_AL, opMOV_a16_EAX, opMOVSB_a16, opMOVSL_a16, opCMPSB_a16, opCMPSL_a16, opTEST_AL, opTEST_EAX, opSTOSB_a16, opSTOSL_a16, opLODSB_a16, opLODSL_a16, opSCASB_a16, opSCASL_a16, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_EAX_imm, opMOV_ECX_imm, opMOV_EDX_imm, opMOV_EBX_imm, opMOV_ESP_imm, opMOV_EBP_imm, opMOV_ESI_imm, opMOV_EDI_imm, + +/*c0*/ opC0_a16, opC1_l_a16, opRET_l_imm, opRET_l, opLES_l_a16, opLDS_l_a16, opMOV_b_imm_a16,opMOV_l_imm_a16,opENTER_l, opLEAVE_l, opRETF_a32_imm, opRETF_a32, opINT3, opINT, opINTO, opIRETD, +/*d0*/ opD0_a16, opD1_l_a16, opD2_a16, opD3_l_a16, opAAM, opAAD, opSETALC, opXLAT_a16, opESCAPE_d8_a16,opESCAPE_d9_a16,opESCAPE_da_a16,opESCAPE_db_a16,opESCAPE_dc_a16,opESCAPE_dd_a16,opESCAPE_de_a16,opESCAPE_df_a16, +/*e0*/ opLOOPNE_w, opLOOPE_w, opLOOP_w, opJCXZ, opIN_AL_imm, opIN_EAX_imm, opOUT_AL_imm, opOUT_EAX_imm, opCALL_r32, opJMP_r32, opJMP_far_a32, opJMP_r8, opIN_AL_DX, opIN_EAX_DX, opOUT_AL_DX, opOUT_EAX_DX, +/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a16, opF7_l_a16, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a16, opFF_l_a16, + + /*16-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a32,opADD_w_rmw_a32,opADD_b_rm_a32, opADD_w_rm_a32, opADD_AL_imm, opADD_AX_imm, opPUSH_ES_w, opPOP_ES_w, opOR_b_rmw_a32, opOR_w_rmw_a32, opOR_b_rm_a32, opOR_w_rm_a32, opOR_AL_imm, opOR_AX_imm, opPUSH_CS_w, op0F_w_a32, +/*10*/ opADC_b_rmw_a32,opADC_w_rmw_a32,opADC_b_rm_a32, opADC_w_rm_a32, opADC_AL_imm, opADC_AX_imm, opPUSH_SS_w, opPOP_SS_w, opSBB_b_rmw_a32,opSBB_w_rmw_a32,opSBB_b_rm_a32, opSBB_w_rm_a32, opSBB_AL_imm, opSBB_AX_imm, opPUSH_DS_w, opPOP_DS_w, +/*20*/ opAND_b_rmw_a32,opAND_w_rmw_a32,opAND_b_rm_a32, opAND_w_rm_a32, opAND_AL_imm, opAND_AX_imm, opES_w_a32, opDAA, opSUB_b_rmw_a32,opSUB_w_rmw_a32,opSUB_b_rm_a32, opSUB_w_rm_a32, opSUB_AL_imm, opSUB_AX_imm, opCS_w_a32, opDAS, +/*30*/ opXOR_b_rmw_a32,opXOR_w_rmw_a32,opXOR_b_rm_a32, opXOR_w_rm_a32, opXOR_AL_imm, opXOR_AX_imm, opSS_w_a32, opAAA, opCMP_b_rmw_a32,opCMP_w_rmw_a32,opCMP_b_rm_a32, opCMP_w_rm_a32, opCMP_AL_imm, opCMP_AX_imm, opDS_w_a32, opAAS, + +/*40*/ opINC_AX, opINC_CX, opINC_DX, opINC_BX, opINC_SP, opINC_BP, opINC_SI, opINC_DI, opDEC_AX, opDEC_CX, opDEC_DX, opDEC_BX, opDEC_SP, opDEC_BP, opDEC_SI, opDEC_DI, +/*50*/ opPUSH_AX, opPUSH_CX, opPUSH_DX, opPUSH_BX, opPUSH_SP, opPUSH_BP, opPUSH_SI, opPUSH_DI, opPOP_AX, opPOP_CX, opPOP_DX, opPOP_BX, opPOP_SP, opPOP_BP, opPOP_SI, opPOP_DI, +/*60*/ opPUSHA_w, opPOPA_w, opBOUND_w_a32, opARPL_a32, opFS_w_a32, opGS_w_a32, op_66, op_67, opPUSH_imm_w, opIMUL_w_iw_a32,opPUSH_imm_bw, opIMUL_w_ib_a32,opINSB_a32, opINSW_a32, opOUTSB_a32, opOUTSW_a32, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a32, op81_w_a32, op80_a32, op83_w_a32, opTEST_b_a32, opTEST_w_a32, opXCHG_b_a32, opXCHG_w_a32, opMOV_b_r_a32, opMOV_w_r_a32, opMOV_r_b_a32, opMOV_r_w_a32, opMOV_w_seg_a32,opLEA_w_a32, opMOV_seg_w_a32,opPOPW_a32, +/*90*/ opNOP, opXCHG_AX_CX, opXCHG_AX_DX, opXCHG_AX_BX, opXCHG_AX_SP, opXCHG_AX_BP, opXCHG_AX_SI, opXCHG_AX_DI, opCBW, opCWD, opCALL_far_w, opWAIT, opPUSHF, opPOPF, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a32, opMOV_AX_a32, opMOV_a32_AL, opMOV_a32_AX, opMOVSB_a32, opMOVSW_a32, opCMPSB_a32, opCMPSW_a32, opTEST_AL, opTEST_AX, opSTOSB_a32, opSTOSW_a32, opLODSB_a32, opLODSW_a32, opSCASB_a32, opSCASW_a32, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_AX_imm, opMOV_CX_imm, opMOV_DX_imm, opMOV_BX_imm, opMOV_SP_imm, opMOV_BP_imm, opMOV_SI_imm, opMOV_DI_imm, + +/*c0*/ opC0_a32, opC1_w_a32, opRET_w_imm, opRET_w, opLES_w_a32, opLDS_w_a32, opMOV_b_imm_a32,opMOV_w_imm_a32,opENTER_w, opLEAVE_w, opRETF_a16_imm, opRETF_a16, opINT3, opINT, opINTO, opIRET, +/*d0*/ opD0_a32, opD1_w_a32, opD2_a32, opD3_w_a32, opAAM, opAAD, opSETALC, opXLAT_a32, opESCAPE_d8_a32,opESCAPE_d9_a32,opESCAPE_da_a32,opESCAPE_db_a32,opESCAPE_dc_a32,opESCAPE_dd_a32,opESCAPE_de_a32,opESCAPE_df_a32, +/*e0*/ opLOOPNE_l, opLOOPE_l, opLOOP_l, opJECXZ, opIN_AL_imm, opIN_AX_imm, opOUT_AL_imm, opOUT_AX_imm, opCALL_r16, opJMP_r16, opJMP_far_a16, opJMP_r8, opIN_AL_DX, opIN_AX_DX, opOUT_AL_DX, opOUT_AX_DX, +/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a32, opF7_w_a32, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a32, opFF_w_a32, + + /*32-bit data, 32-bit addr*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ opADD_b_rmw_a32,opADD_l_rmw_a32,opADD_b_rm_a32, opADD_l_rm_a32, opADD_AL_imm, opADD_EAX_imm, opPUSH_ES_l, opPOP_ES_l, opOR_b_rmw_a32, opOR_l_rmw_a32, opOR_b_rm_a32, opOR_l_rm_a32, opOR_AL_imm, opOR_EAX_imm, opPUSH_CS_l, op0F_l_a32, +/*10*/ opADC_b_rmw_a32,opADC_l_rmw_a32,opADC_b_rm_a32, opADC_l_rm_a32, opADC_AL_imm, opADC_EAX_imm, opPUSH_SS_l, opPOP_SS_l, opSBB_b_rmw_a32,opSBB_l_rmw_a32,opSBB_b_rm_a32, opSBB_l_rm_a32, opSBB_AL_imm, opSBB_EAX_imm, opPUSH_DS_l, opPOP_DS_l, +/*20*/ opAND_b_rmw_a32,opAND_l_rmw_a32,opAND_b_rm_a32, opAND_l_rm_a32, opAND_AL_imm, opAND_EAX_imm, opES_l_a32, opDAA, opSUB_b_rmw_a32,opSUB_l_rmw_a32,opSUB_b_rm_a32, opSUB_l_rm_a32, opSUB_AL_imm, opSUB_EAX_imm, opCS_l_a32, opDAS, +/*30*/ opXOR_b_rmw_a32,opXOR_l_rmw_a32,opXOR_b_rm_a32, opXOR_l_rm_a32, opXOR_AL_imm, opXOR_EAX_imm, opSS_l_a32, opAAA, opCMP_b_rmw_a32,opCMP_l_rmw_a32,opCMP_b_rm_a32, opCMP_l_rm_a32, opCMP_AL_imm, opCMP_EAX_imm, opDS_l_a32, opAAS, + +/*40*/ opINC_EAX, opINC_ECX, opINC_EDX, opINC_EBX, opINC_ESP, opINC_EBP, opINC_ESI, opINC_EDI, opDEC_EAX, opDEC_ECX, opDEC_EDX, opDEC_EBX, opDEC_ESP, opDEC_EBP, opDEC_ESI, opDEC_EDI, +/*50*/ opPUSH_EAX, opPUSH_ECX, opPUSH_EDX, opPUSH_EBX, opPUSH_ESP, opPUSH_EBP, opPUSH_ESI, opPUSH_EDI, opPOP_EAX, opPOP_ECX, opPOP_EDX, opPOP_EBX, opPOP_ESP, opPOP_EBP, opPOP_ESI, opPOP_EDI, +/*60*/ opPUSHA_l, opPOPA_l, opBOUND_l_a32, opARPL_a32, opFS_l_a32, opGS_l_a32, op_66, op_67, opPUSH_imm_l, opIMUL_l_il_a32,opPUSH_imm_bl, opIMUL_l_ib_a32,opINSB_a32, opINSL_a32, opOUTSB_a32, opOUTSL_a32, +/*70*/ opJO, opJNO, opJB, opJNB, opJE, opJNE, opJBE, opJNBE, opJS, opJNS, opJP, opJNP, opJL, opJNL, opJLE, opJNLE, + +/*80*/ op80_a32, op81_l_a32, op80_a32, op83_l_a32, opTEST_b_a32, opTEST_l_a32, opXCHG_b_a32, opXCHG_l_a32, opMOV_b_r_a32, opMOV_l_r_a32, opMOV_r_b_a32, opMOV_r_l_a32, opMOV_l_seg_a32,opLEA_l_a32, opMOV_seg_w_a32,opPOPL_a32, +/*90*/ opNOP, opXCHG_EAX_ECX, opXCHG_EAX_EDX, opXCHG_EAX_EBX, opXCHG_EAX_ESP, opXCHG_EAX_EBP, opXCHG_EAX_ESI, opXCHG_EAX_EDI, opCWDE, opCDQ, opCALL_far_l, opWAIT, opPUSHFD, opPOPFD, opSAHF, opLAHF, +/*a0*/ opMOV_AL_a32, opMOV_EAX_a32, opMOV_a32_AL, opMOV_a32_EAX, opMOVSB_a32, opMOVSL_a32, opCMPSB_a32, opCMPSL_a32, opTEST_AL, opTEST_EAX, opSTOSB_a32, opSTOSL_a32, opLODSB_a32, opLODSL_a32, opSCASB_a32, opSCASL_a32, +/*b0*/ opMOV_AL_imm, opMOV_CL_imm, opMOV_DL_imm, opMOV_BL_imm, opMOV_AH_imm, opMOV_CH_imm, opMOV_DH_imm, opMOV_BH_imm, opMOV_EAX_imm, opMOV_ECX_imm, opMOV_EDX_imm, opMOV_EBX_imm, opMOV_ESP_imm, opMOV_EBP_imm, opMOV_ESI_imm, opMOV_EDI_imm, + +/*c0*/ opC0_a32, opC1_l_a32, opRET_l_imm, opRET_l, opLES_l_a32, opLDS_l_a32, opMOV_b_imm_a32,opMOV_l_imm_a32,opENTER_l, opLEAVE_l, opRETF_a32_imm, opRETF_a32, opINT3, opINT, opINTO, opIRETD, +/*d0*/ opD0_a32, opD1_l_a32, opD2_a32, opD3_l_a32, opAAM, opAAD, opSETALC, opXLAT_a32, opESCAPE_d8_a32,opESCAPE_d9_a32,opESCAPE_da_a32,opESCAPE_db_a32,opESCAPE_dc_a32,opESCAPE_dd_a32,opESCAPE_de_a32,opESCAPE_df_a32, +/*e0*/ opLOOPNE_l, opLOOPE_l, opLOOP_l, opJECXZ, opIN_AL_imm, opIN_EAX_imm, opOUT_AL_imm, opOUT_EAX_imm, opCALL_r32, opJMP_r32, opJMP_far_a32, opJMP_r8, opIN_AL_DX, opIN_EAX_DX, opOUT_AL_DX, opOUT_EAX_DX, +/*f0*/ opLOCK, ILLEGAL, opREPNE, opREPE, opHLT, opCMC, opF6_a32, opF7_l_a32, opCLC, opSTC, opCLI, opSTI, opCLD, opSTD, opINCDEC_b_a32, opFF_l_a32, +}; diff --git a/src/808x.c b/src/808x.c new file mode 100644 index 000000000..4034e90dd --- /dev/null +++ b/src/808x.c @@ -0,0 +1,3509 @@ +//1B64 - Vid_SetMode (Vid_Vesa.c) +//6689c - CONS_Printf +/*SHR AX,1 + + 4 clocks - fetch opcode + 4 clocks - fetch mod/rm + 2 clocks - execute 2 clocks - fetch opcode 1 + 2 clocks - fetch opcode 2 + 4 clocks - fetch mod/rm + 2 clocks - fetch opcode 1 2 clocks - execute + 2 clocks - fetch opcode 2 etc*/ +#include +#include "ibm.h" + +#include "cpu.h" +#include "keyboard.h" +#include "mem.h" +#include "nmi.h" +#include "pic.h" +#include "timer.h" +#include "x86.h" + +int xt_cpu_multi; +int nmi = 0; + +int nextcyc=0; +int cycdiff; +int is8086=0; + +int memcycs; +int nopageerrors=0; + +void FETCHCOMPLETE(); + +uint8_t readmembl(uint32_t addr); +void writemembl(uint32_t addr, uint8_t val); +uint16_t readmemwl(uint32_t seg, uint32_t addr); +void writememwl(uint32_t seg, uint32_t addr, uint16_t val); +uint32_t readmemll(uint32_t seg, uint32_t addr); +void writememll(uint32_t seg, uint32_t addr, uint32_t val); + +#undef readmemb +#undef readmemw +uint8_t readmemb(uint32_t a) +{ + if (a!=(cs+cpu_state.pc)) memcycs+=4; + if (readlookup2[(a)>>12]==-1) return readmembl(a); + else return *(uint8_t *)(readlookup2[(a) >> 12] + (a)); +} + +uint8_t readmembf(uint32_t a) +{ + if (readlookup2[(a)>>12]==-1) return readmembl(a); + else return *(uint8_t *)(readlookup2[(a) >> 12] + (a)); +} + +uint16_t readmemw(uint32_t s, uint16_t a) +{ + if (a!=(cs+cpu_state.pc)) memcycs+=(8>>is8086); + if ((readlookup2[((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF)) return readmemwl(s,a); + else return *(uint16_t *)(readlookup2[(s + a) >> 12] + s + a); +} + +void refreshread() { /*pclog("Refreshread\n"); */FETCHCOMPLETE(); memcycs+=4; } + +#undef fetchea +#define fetchea() { rmdat=FETCH(); \ + reg=(rmdat>>3)&7; \ + mod=(rmdat>>6)&3; \ + rm=rmdat&7; \ + if (mod!=3) fetcheal(); } + +void writemembl(uint32_t addr, uint8_t val); +void writememb(uint32_t a, uint8_t v) +{ + memcycs+=4; + if (writelookup2[(a)>>12]==-1) writemembl(a,v); + else *(uint8_t *)(writelookup2[a >> 12] + a) = v; +} +void writememwl(uint32_t seg, uint32_t addr, uint16_t val); +void writememw(uint32_t s, uint32_t a, uint16_t v) +{ + memcycs+=(8>>is8086); + if (writelookup2[((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF) writememwl(s,a,v); + else *(uint16_t *)(writelookup2[(s + a) >> 12] + s + a) = v; +} +void writememll(uint32_t seg, uint32_t addr, uint32_t val); +void writememl(uint32_t s, uint32_t a, uint32_t v) +{ + if (writelookup2[((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF) writememll(s,a,v); + else *(uint32_t *)(writelookup2[(s + a) >> 12] + s + a) = v; +} + + +void dumpregs(); +uint16_t oldcs; +int oldcpl; + +int tempc; +uint8_t opcode; +int times=0; +uint16_t pc2,pc3; +int noint=0; + +int output=0; + +int shadowbios=0; + +int ins=0; +//#define readmemb(a) (((a)<0xA0000)?ram[a]:readmembl(a)) + +int ssegs; + +int fetchcycles=0,memcycs,fetchclocks; + +uint8_t prefetchqueue[6]; +uint16_t prefetchpc; +int prefetchw=0; +inline uint8_t FETCH() +{ + uint8_t temp; +/* temp=prefetchqueue[0]; + prefetchqueue[0]=prefetchqueue[1]; + prefetchqueue[1]=prefetchqueue[2]; + prefetchqueue[2]=prefetchqueue[3]; + prefetchqueue[3]=prefetchqueue[4]; + prefetchqueue[4]=prefetchqueue[5]; + if (prefetchw<=((is8086)?4:3)) + { + prefetchqueue[prefetchw++]=readmembf(cs+prefetchpc); prefetchpc++; + if (is8086 && (prefetchpc&1)) + { + prefetchqueue[prefetchw++]=readmembf(cs+prefetchpc); prefetchpc++; + } + }*/ + +// uint8_t temp=readmemb(cs+pc); +// if (output) printf("FETCH %04X %i\n",pc,fetchcycles); + if (prefetchw==0) //(fetchcycles<4) + { + cycles-=(4-(fetchcycles&3)); + fetchclocks+=(4-(fetchcycles&3)); + fetchcycles=4; + temp=readmembf(cs+cpu_state.pc); + prefetchpc = cpu_state.pc = cpu_state.pc + 1; +// if (output) printf(" FETCH %04X:%04X %02X %04X %04X %i\n",CS,pc-1,temp,pc,prefetchpc,prefetchw); + if (is8086 && (cpu_state.pc&1)) + { + prefetchqueue[0]=readmembf(cs+cpu_state.pc); +// if (output) printf(" PREFETCHED from %04X:%04X %02X 8086\n",CS,prefetchpc,prefetchqueue[prefetchw]); + prefetchpc++; + prefetchw++; + } + } + else + { + temp=prefetchqueue[0]; + prefetchqueue[0]=prefetchqueue[1]; + prefetchqueue[1]=prefetchqueue[2]; + prefetchqueue[2]=prefetchqueue[3]; + prefetchqueue[3]=prefetchqueue[4]; + prefetchqueue[4]=prefetchqueue[5]; + prefetchw--; +// if (output) printf("PREFETCH %04X:%04X %02X %04X %04X %i\n",CS,pc,temp,pc,prefetchpc,prefetchw); + fetchcycles-=4; +// fetchclocks+=4; + cpu_state.pc++; + } +// if (output) printf("%i\n",fetchcycles); + return temp; +} + +inline void FETCHADD(int c) +{ + int d; +// if (output) printf("FETCHADD %i\n",c); + if (c<0) return; + if (prefetchw>((is8086)?4:3)) return; + d=c+(fetchcycles&3); + while (d>3 && prefetchw<((is8086)?6:4)) + { + d-=4; + if (is8086 && !(prefetchpc&1)) + { + prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); +// printf("PREFETCHED from %04X:%04X %02X 8086\n",CS,prefetchpc,prefetchqueue[prefetchw]); + prefetchpc++; + prefetchw++; + } + if (prefetchw<6) + { + prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); +// printf("PREFETCHED from %04X:%04X %02X\n",CS,prefetchpc,prefetchqueue[prefetchw]); + prefetchpc++; + prefetchw++; + } + } + fetchcycles+=c; + if (fetchcycles>16) fetchcycles=16; +// if (fetchcycles>24) fetchcycles=24; +} + +void FETCHCOMPLETE() +{ +// pclog("Fetchcomplete %i %i %i\n",fetchcycles&3,fetchcycles,prefetchw); + if (!(fetchcycles&3)) return; + if (prefetchw>((is8086)?4:3)) return; + if (!prefetchw) nextcyc=(4-(fetchcycles&3)); + cycles-=(4-(fetchcycles&3)); + fetchclocks+=(4-(fetchcycles&3)); + if (is8086 && !(prefetchpc&1)) + { + prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); +// printf("PREFETCHEDc from %04X:%04X %02X 8086\n",CS,prefetchpc,prefetchqueue[prefetchw]); + prefetchpc++; + prefetchw++; + } + if (prefetchw<6) + { + prefetchqueue[prefetchw]=readmembf(cs+prefetchpc); +// printf("PREFETCHEDc from %04X:%04X %02X\n",CS,prefetchpc,prefetchqueue[prefetchw]); + prefetchpc++; + prefetchw++; + } + fetchcycles+=(4-(fetchcycles&3)); +} + +inline void FETCHCLEAR() +{ +/* int c; + fetchcycles=0; + prefetchpc=pc; + if (is8086 && (prefetchpc&1)) cycles-=4; + for (c=0;c<((is8086)?6:4);c++) + { + prefetchqueue[c]=readmembf(cs+prefetchpc); + if (!is8086 || !(prefetchpc&1)) cycles-=4; + prefetchpc++; + } + prefetchw=(is8086)?6:4;*/ +// fetchcycles=0; + prefetchpc=cpu_state.pc; + prefetchw=0; + memcycs=cycdiff-cycles; + fetchclocks=0; +// memcycs=cycles; +/* prefetchqueue[0]=readmembf(cs+prefetchpc); + prefetchpc++; + prefetchw=1; + if (is8086 && prefetchpc&1) + { + prefetchqueue[1]=readmembf(cs+prefetchpc); + prefetchpc++; + }*/ +} + +static uint16_t getword() +{ + uint8_t temp=FETCH(); + return temp|(FETCH()<<8); +} + + +/*EA calculation*/ + +/*R/M - bits 0-2 - R/M bits 3-5 - Reg bits 6-7 - mod + From 386 programmers manual : +r8(/r) AL CL DL BL AH CH DH BH +r16(/r) AX CX DX BX SP BP SI DI +r32(/r) EAX ECX EDX EBX ESP EBP ESI EDI +/digit (Opcode) 0 1 2 3 4 5 6 7 +REG = 000 001 010 011 100 101 110 111 + ÚÄÄÄAddress +disp8 denotes an 8-bit displacement following the ModR/M byte, to be +sign-extended and added to the index. disp16 denotes a 16-bit displacement +following the ModR/M byte, to be added to the index. Default segment +register is SS for the effective addresses containing a BP index, DS for +other effective addresses. + ÄÄ¿ ÚMod R/M¿ ÚÄÄÄÄÄÄÄÄModR/M Values in HexadecimalÄÄÄÄÄÄÄÄ¿ + +[BX + SI] 000 00 08 10 18 20 28 30 38 +[BX + DI] 001 01 09 11 19 21 29 31 39 +[BP + SI] 010 02 0A 12 1A 22 2A 32 3A +[BP + DI] 011 03 0B 13 1B 23 2B 33 3B +[SI] 00 100 04 0C 14 1C 24 2C 34 3C +[DI] 101 05 0D 15 1D 25 2D 35 3D +disp16 110 06 0E 16 1E 26 2E 36 3E +[BX] 111 07 0F 17 1F 27 2F 37 3F + +[BX+SI]+disp8 000 40 48 50 58 60 68 70 78 +[BX+DI]+disp8 001 41 49 51 59 61 69 71 79 +[BP+SI]+disp8 010 42 4A 52 5A 62 6A 72 7A +[BP+DI]+disp8 011 43 4B 53 5B 63 6B 73 7B +[SI]+disp8 01 100 44 4C 54 5C 64 6C 74 7C +[DI]+disp8 101 45 4D 55 5D 65 6D 75 7D +[BP]+disp8 110 46 4E 56 5E 66 6E 76 7E +[BX]+disp8 111 47 4F 57 5F 67 6F 77 7F + +[BX+SI]+disp16 000 80 88 90 98 A0 A8 B0 B8 +[BX+DI]+disp16 001 81 89 91 99 A1 A9 B1 B9 +[BX+SI]+disp16 010 82 8A 92 9A A2 AA B2 BA +[BX+DI]+disp16 011 83 8B 93 9B A3 AB B3 BB +[SI]+disp16 10 100 84 8C 94 9C A4 AC B4 BC +[DI]+disp16 101 85 8D 95 9D A5 AD B5 BD +[BP]+disp16 110 86 8E 96 9E A6 AE B6 BE +[BX]+disp16 111 87 8F 97 9F A7 AF B7 BF + +EAX/AX/AL 000 C0 C8 D0 D8 E0 E8 F0 F8 +ECX/CX/CL 001 C1 C9 D1 D9 E1 E9 F1 F9 +EDX/DX/DL 010 C2 CA D2 DA E2 EA F2 FA +EBX/BX/BL 011 C3 CB D3 DB E3 EB F3 FB +ESP/SP/AH 11 100 C4 CC D4 DC E4 EC F4 FC +EBP/BP/CH 101 C5 CD D5 DD E5 ED F5 FD +ESI/SI/DH 110 C6 CE D6 DE E6 EE F6 FE +EDI/DI/BH 111 C7 CF D7 DF E7 EF F7 FF + +mod = 11 - register + 10 - address + 16 bit displacement + 01 - address + 8 bit displacement + 00 - address + +reg = If mod=11, (depending on data size, 16 bits/8 bits, 32 bits=extend 16 bit registers) + 0=AX/AL 1=CX/CL 2=DX/DL 3=BX/BL + 4=SP/AH 5=BP/CH 6=SI/DH 7=DI/BH + + Otherwise, LSB selects SI/DI (0=SI), NMSB selects BX/BP (0=BX), and MSB + selects whether BX/BP are used at all (0=used). + + mod=00 is an exception though + 6=16 bit displacement only + 7=[BX] + + Usage varies with instructions. + + MOV AL,BL has ModR/M as C3, for example. + mod=11, reg=0, r/m=3 + MOV uses reg as dest, and r/m as src. + reg 0 is AL, reg 3 is BL + + If BP or SP are in address calc, seg is SS, else DS +*/ + +int cycles=0; +uint32_t easeg,eaaddr; +int rm,reg,mod,rmdat; + +uint16_t zero=0; +uint16_t *mod1add[2][8]; +uint32_t *mod1seg[8]; + +int slowrm[8]; + +void makemod1table() +{ + mod1add[0][0]=&BX; mod1add[0][1]=&BX; mod1add[0][2]=&BP; mod1add[0][3]=&BP; + mod1add[0][4]=&SI; mod1add[0][5]=&DI; mod1add[0][6]=&BP; mod1add[0][7]=&BX; + mod1add[1][0]=&SI; mod1add[1][1]=&DI; mod1add[1][2]=&SI; mod1add[1][3]=&DI; + mod1add[1][4]=&zero; mod1add[1][5]=&zero; mod1add[1][6]=&zero; mod1add[1][7]=&zero; + slowrm[0]=0; slowrm[1]=1; slowrm[2]=1; slowrm[3]=0; + mod1seg[0]=&ds; mod1seg[1]=&ds; mod1seg[2]=&ss; mod1seg[3]=&ss; + mod1seg[4]=&ds; mod1seg[5]=&ds; mod1seg[6]=&ss; mod1seg[7]=&ds; +} + +static void fetcheal() +{ + if (!mod && rm==6) { eaaddr=getword(); easeg=ds; FETCHADD(6); } + else + { + switch (mod) + { + case 0: + eaaddr=0; + if (rm&4) FETCHADD(5); + else FETCHADD(7+slowrm[rm]); + break; + case 1: + eaaddr=(uint16_t)(int8_t)FETCH(); + if (rm&4) FETCHADD(9); + else FETCHADD(11+slowrm[rm]); + break; + case 2: + eaaddr=getword(); + if (rm&4) FETCHADD(9); + else FETCHADD(11+slowrm[rm]); + break; + } + eaaddr+=(*mod1add[0][rm])+(*mod1add[1][rm]); + easeg=*mod1seg[rm]; + eaaddr&=0xFFFF; + } +} + +static inline uint8_t geteab() +{ + if (mod == 3) + return (rm & 4) ? cpu_state.regs[rm & 3].b.h : cpu_state.regs[rm & 3].b.l; + return readmemb(easeg+eaaddr); +} + +static inline uint16_t geteaw() +{ + if (mod == 3) + return cpu_state.regs[rm].w; +// if (output==3) printf("GETEAW %04X:%08X\n",easeg,eaaddr); + return readmemw(easeg,eaaddr); +} + +static inline uint16_t geteaw2() +{ + if (mod == 3) + return cpu_state.regs[rm].w; +// printf("Getting addr from %04X:%04X %05X\n",easeg,eaaddr+2,easeg+eaaddr+2); + return readmemw(easeg,(eaaddr+2)&0xFFFF); +} + +static inline void seteab(uint8_t val) +{ + if (mod == 3) + { + if (rm & 4) + cpu_state.regs[rm & 3].b.h = val; + else + cpu_state.regs[rm & 3].b.l = val; + } + else + { + writememb(easeg+eaaddr,val); + } +} + +static inline void seteaw(uint16_t val) +{ + if (mod == 3) + cpu_state.regs[rm].w = val; + else + { + writememw(easeg,eaaddr,val); +// writememb(easeg+eaaddr+1,val>>8); + } +} + +#define getr8(r) ((r & 4) ? cpu_state.regs[r & 3].b.h : cpu_state.regs[r & 3].b.l) + +#define setr8(r,v) if (r & 4) cpu_state.regs[r & 3].b.h = v; \ + else cpu_state.regs[r & 3].b.l = v; + + +/*Flags*/ +uint8_t znptable8[256]; +uint16_t znptable16[65536]; + +void makeznptable() +{ + int c,d; + for (c=0;c<256;c++) + { + d=0; + if (c&1) d++; + if (c&2) d++; + if (c&4) d++; + if (c&8) d++; + if (c&16) d++; + if (c&32) d++; + if (c&64) d++; + if (c&128) d++; + if (d&1) + znptable8[c]=0; + else + znptable8[c]=P_FLAG; + if (c == 0xb1) pclog("znp8 b1 = %i %02X\n", d, znptable8[c]); + if (!c) znptable8[c]|=Z_FLAG; + if (c&0x80) znptable8[c]|=N_FLAG; + } + for (c=0;c<65536;c++) + { + d=0; + if (c&1) d++; + if (c&2) d++; + if (c&4) d++; + if (c&8) d++; + if (c&16) d++; + if (c&32) d++; + if (c&64) d++; + if (c&128) d++; + if (d&1) + znptable16[c]=0; + else + znptable16[c]=P_FLAG; + if (c == 0xb1) pclog("znp16 b1 = %i %02X\n", d, znptable16[c]); + if (c == 0x65b1) pclog("znp16 65b1 = %i %02X\n", d, znptable16[c]); + if (!c) znptable16[c]|=Z_FLAG; + if (c&0x8000) znptable16[c]|=N_FLAG; + } + +// makemod1table(); +} +int timetolive=0; + +extern uint32_t oldcs2; +extern uint32_t oldpc2; + +int indump = 0; + +void dumpregs() +{ + int c,d=0,e=0,ff; +#ifndef RELEASE_BUILD + FILE *f; + if (indump) return; + indump = 1; +// return; + output=0; +// return; +// savenvr(); +// return; +chdir(pcempath); + nopageerrors=1; +/* f=fopen("rram3.dmp","wb"); + for (c=0;c<0x8000000;c++) putc(readmemb(c+0x10000000),f); + fclose(f);*/ + f=fopen("ram.dmp","wb"); + fwrite(ram,mem_size*1024,1,f); + fclose(f); +/* pclog("Dumping rram5.dmp\n"); + f=fopen("rram5.dmp","wb"); + for (c=0;c<0x1000000;c++) putc(readmemb(c+0x10150000),f); + fclose(f);*/ + pclog("Dumping rram.dmp\n"); + f=fopen("rram.dmp","wb"); + for (c=0;c<0x1000000;c++) putc(readmemb(c),f); + fclose(f); +/* f=fopen("rram2.dmp","wb"); + for (c=0;c<0x100000;c++) putc(readmemb(c+0xbff00000),f); + fclose(f); + f = fopen("stack.dmp","wb"); + for (c = 0; c < 0x6000; c++) putc(readmemb(c+0xFFDFA000), f); + fclose(f); + f = fopen("tempx.dmp","wb"); + for (c = 0; c < 0x10000; c++) putc(readmemb(c+0xFC816000), f); + fclose(f); + f = fopen("tempx2.dmp","wb"); + for (c = 0; c < 0x10000; c++) putc(readmemb(c+0xFDEF5000), f); + fclose(f);*/ + pclog("Dumping rram4.dmp\n"); + f=fopen("rram4.dmp","wb"); + for (c=0;c<0x0050000;c++) + { + abrt = 0; + putc(readmemb386l(0,c+0x80000000),f); + } + fclose(f); + pclog("Dumping done\n"); +/* f=fopen("rram6.dmp","wb"); + for (c=0;c<0x1000000;c++) putc(readmemb(c+0xBF000000),f); + fclose(f);*/ +/* f=fopen("ram6.bin","wb"); + fwrite(ram+0x10100,0xA000,1,f); + fclose(f); + f=fopen("boot.bin","wb"); + fwrite(ram+0x7C00,0x200,1,f); + fclose(f); + f=fopen("ram7.bin","wb"); + fwrite(ram+0x11100,0x2000,1,f); + fclose(f); + f=fopen("ram8.bin","wb"); + fwrite(ram+0x3D210,0x200,1,f); + fclose(f); */ +/* f=fopen("bios.dmp","wb"); + fwrite(rom,0x20000,1,f); + fclose(f);*/ +/* f=fopen("kernel.dmp","wb"); + for (c=0;c<0x200000;c++) putc(readmemb(c+0xC0000000),f); + fclose(f);*/ +/* f=fopen("rram.dmp","wb"); + for (c=0;c<0x1500000;c++) putc(readmemb(c),f); + fclose(f); + if (!times) + { + f=fopen("thing.dmp","wb"); + fwrite(ram+0x11E50,0x1000,1,f); + fclose(f); + }*/ +#endif + if (is386) + printf("EAX=%08X EBX=%08X ECX=%08X EDX=%08X\nEDI=%08X ESI=%08X EBP=%08X ESP=%08X\n",EAX,EBX,ECX,EDX,EDI,ESI,EBP,ESP); + else + printf("AX=%04X BX=%04X CX=%04X DX=%04X DI=%04X SI=%04X BP=%04X SP=%04X\n",AX,BX,CX,DX,DI,SI,BP,SP); + printf("PC=%04X CS=%04X DS=%04X ES=%04X SS=%04X FLAGS=%04X\n",cpu_state.pc,CS,DS,ES,SS,flags); + printf("%04X:%04X %04X:%04X\n",oldcs,oldpc, oldcs2, oldpc2); + printf("%i ins\n",ins); + if (is386) + printf("In %s mode\n",(msw&1)?((eflags&VM_FLAG)?"V86":"protected"):"real"); + else + printf("In %s mode\n",(msw&1)?"protected":"real"); + printf("CS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",cs,_cs.limit,_cs.access, _cs.limit_low, _cs.limit_high); + printf("DS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",ds,_ds.limit,_ds.access, _ds.limit_low, _ds.limit_high); + printf("ES : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",es,_es.limit,_es.access, _es.limit_low, _es.limit_high); + if (is386) + { + printf("FS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",seg_fs,_fs.limit,_fs.access, _fs.limit_low, _fs.limit_high); + printf("GS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",gs,_gs.limit,_gs.access, _gs.limit_low, _gs.limit_high); + } + printf("SS : base=%06X limit=%08X access=%02X limit_low=%08X limit_high=%08X\n",ss,_ss.limit,_ss.access, _ss.limit_low, _ss.limit_high); + printf("GDT : base=%06X limit=%04X\n",gdt.base,gdt.limit); + printf("LDT : base=%06X limit=%04X\n",ldt.base,ldt.limit); + printf("IDT : base=%06X limit=%04X\n",idt.base,idt.limit); + printf("TR : base=%06X limit=%04X\n", tr.base, tr.limit); + if (is386) + { + printf("386 in %s mode stack in %s mode\n",(use32)?"32-bit":"16-bit",(stack32)?"32-bit":"16-bit"); + printf("CR0=%08X CR2=%08X CR3=%08X\n",cr0,cr2,cr3); + } + printf("Entries in readlookup : %i writelookup : %i\n",readlnum,writelnum); + for (c=0;c<1024*1024;c++) + { + if (readlookup2[c]!=0xFFFFFFFF) d++; + if (writelookup2[c]!=0xFFFFFFFF) e++; + } + printf("Entries in readlookup : %i writelookup : %i\n",d,e); + x87_dumpregs(); + indump = 0; +} + +int resets = 0; +int x86_was_reset = 0; +void resetx86() +{ + pclog("x86 reset\n"); + resets++; + ins = 0; + use32=0; + stack32=0; +// i86_Reset(); +// cs=0xFFFF0; + cpu_state.pc=0; + msw=0; + if (is486) + cr0 = 1 << 30; + else + cr0 = 0; + cr4 = 0; + eflags=0; + cgate32=0; + loadcs(0xFFFF); + rammask=0xFFFFFFFF; + idt.base = 0; + flags=2; + makeznptable(); + resetreadlookup(); + makemod1table(); + resetmcr(); + FETCHCLEAR(); + x87_reset(); + cpu_set_edx(); + ESP=0; + mmu_perm=4; + memset(inscounts, 0, sizeof(inscounts)); + x86seg_reset(); + codegen_reset(); + x86_was_reset = 1; +} + +void softresetx86() +{ +// dumpregs(); +// exit(-1); + use32=0; + stack32=0; +// i86_Reset(); +// cs=0xFFFF0; + cpu_state.pc=0; + msw=0; + cr0=0; + cr4 = 0; + eflags=0; + cgate32=0; + loadcs(0xFFFF); + //rammask=0xFFFFFFFF; + flags=2; + idt.base = 0; + x86seg_reset(); + x86_was_reset = 1; +} + +static void setznp8(uint8_t val) +{ + flags&=~0xC4; + flags|=znptable8[val]; +} + +static void setznp16(uint16_t val) +{ + flags&=~0xC4; + flags|=znptable16[val]; +} + +static void setadd8(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a+(uint16_t)b; + flags&=~0x8D5; + flags|=znptable8[c&0xFF]; + if (c&0x100) flags|=C_FLAG; + if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +static void setadd8nc(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a+(uint16_t)b; + flags&=~0x8D4; + flags|=znptable8[c&0xFF]; + if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +static void setadc8(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a+(uint16_t)b+tempc; + flags&=~0x8D5; + flags|=znptable8[c&0xFF]; + if (c&0x100) flags|=C_FLAG; + if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +static void setadd16(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a+(uint32_t)b; + flags&=~0x8D5; + flags|=znptable16[c&0xFFFF]; + if (c&0x10000) flags|=C_FLAG; + if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +static void setadd16nc(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a+(uint32_t)b; + flags&=~0x8D4; + flags|=znptable16[c&0xFFFF]; + if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +static void setadc16(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a+(uint32_t)b+tempc; + flags&=~0x8D5; + flags|=znptable16[c&0xFFFF]; + if (c&0x10000) flags|=C_FLAG; + if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} + +static void setsub8(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a-(uint16_t)b; + flags&=~0x8D5; + flags|=znptable8[c&0xFF]; + if (c&0x100) flags|=C_FLAG; + if ((a^b)&(a^c)&0x80) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +static void setsub8nc(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a-(uint16_t)b; + flags&=~0x8D4; + flags|=znptable8[c&0xFF]; + if ((a^b)&(a^c)&0x80) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +static void setsbc8(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a-(((uint16_t)b)+tempc); + flags&=~0x8D5; + flags|=znptable8[c&0xFF]; + if (c&0x100) flags|=C_FLAG; + if ((a^b)&(a^c)&0x80) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +static void setsub16(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a-(uint32_t)b; + flags&=~0x8D5; + flags|=znptable16[c&0xFFFF]; + if (c&0x10000) flags|=C_FLAG; + if ((a^b)&(a^c)&0x8000) flags|=V_FLAG; +// if (output) printf("%04X %04X %i\n",a^b,a^c,flags&V_FLAG); + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +static void setsub16nc(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a-(uint32_t)b; + flags&=~0x8D4; + flags|=(znptable16[c&0xFFFF]&~4); + flags|=(znptable8[c&0xFF]&4); + if ((a^b)&(a^c)&0x8000) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +static void setsbc16(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a-(((uint32_t)b)+tempc); + flags&=~0x8D5; + flags|=(znptable16[c&0xFFFF]&~4); + flags|=(znptable8[c&0xFF]&4); + if (c&0x10000) flags|=C_FLAG; + if ((a^b)&(a^c)&0x8000) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} + +int current_diff = 0; +void clockhardware() +{ + int diff = cycdiff - cycles - current_diff; + + current_diff += diff; + + timer_end_period(cycles*xt_cpu_multi); +} + +static int takeint = 0; + + +int firstrepcycle=1; + +void rep(int fv) +{ + uint8_t temp; + int c=CX; + uint8_t temp2; + uint16_t tempw,tempw2; + uint16_t ipc=oldpc;//pc-1; + int changeds=0; + uint32_t oldds; + startrep: + temp=FETCH(); + +// if (firstrepcycle && temp==0xA5) printf("REP MOVSW %06X:%04X %06X:%04X\n",ds,SI,es,DI); +// if (output) printf("REP %02X %04X\n",temp,ipc); + switch (temp) + { + case 0x08: + cpu_state.pc=ipc+1; + cycles-=2; + FETCHCLEAR(); + break; + case 0x26: /*ES:*/ + oldds=ds; + ds=es; + changeds=1; + cycles-=2; + goto startrep; + break; + case 0x2E: /*CS:*/ + oldds=ds; + ds=cs; + changeds=1; + cycles-=2; + goto startrep; + break; + case 0x36: /*SS:*/ + oldds=ds; + ds=ss; + changeds=1; + cycles-=2; + goto startrep; + break; + case 0x6E: /*REP OUTSB*/ + if (c>0) + { + temp2=readmemb(ds+SI); + outb(DX,temp2); + if (flags&D_FLAG) SI--; + else SI++; + c--; + cycles-=5; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; if (ssegs) ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; + break; + case 0xA4: /*REP MOVSB*/ + while (c>0 && !IRQTEST) + { + temp2=readmemb(ds+SI); + writememb(es+DI,temp2); +// if (output) printf("Moved %02X from %04X:%04X to %04X:%04X\n",temp2,ds>>4,SI,es>>4,DI); + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + c--; + cycles-=17; + clockhardware(); + FETCHADD(17-memcycs); + } + if (IRQTEST && c>0) cpu_state.pc=ipc; +// if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; FETCHCLEAR(); } +// else firstrepcycle=1; +// } + break; + case 0xA5: /*REP MOVSW*/ + while (c>0 && !IRQTEST) + { + memcycs=0; + tempw=readmemw(ds,SI); + writememw(es,DI,tempw); + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + c--; + cycles-=17; + clockhardware(); + FETCHADD(17 - memcycs); + } + if (IRQTEST && c>0) cpu_state.pc=ipc; +// if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; FETCHCLEAR(); } +// else firstrepcycle=1; +// } + break; + case 0xA6: /*REP CMPSB*/ + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + while ((c>0) && (fv==((flags&Z_FLAG)?1:0)) && !IRQTEST) + { + memcycs=0; + temp=readmemb(ds+SI); + temp2=readmemb(es+DI); +// printf("CMPSB %c %c %i %05X %05X %04X:%04X\n",temp,temp2,c,ds+SI,es+DI,cs>>4,pc); + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + c--; + cycles -= 30; + setsub8(temp,temp2); + clockhardware(); + FETCHADD(30 - memcycs); + } + if (IRQTEST && c>0 && (fv==((flags&Z_FLAG)?1:0))) cpu_state.pc=ipc; +// if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; FETCHCLEAR(); } +// else firstrepcycle=1; + break; + case 0xA7: /*REP CMPSW*/ + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + while ((c>0) && (fv==((flags&Z_FLAG)?1:0)) && !IRQTEST) + { + memcycs=0; + tempw=readmemw(ds,SI); + tempw2=readmemw(es,DI); + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + c--; + cycles -= 30; + setsub16(tempw,tempw2); + clockhardware(); + FETCHADD(30 - memcycs); + } + if (IRQTEST && c>0 && (fv==((flags&Z_FLAG)?1:0))) cpu_state.pc=ipc; +// if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; FETCHCLEAR(); } +// else firstrepcycle=1; +// if (firstrepcycle) printf("REP CMPSW %06X:%04X %06X:%04X %04X %04X\n",ds,SI,es,DI,tempw,tempw2); + break; + case 0xAA: /*REP STOSB*/ + while (c>0 && !IRQTEST) + { + memcycs=0; + writememb(es+DI,AL); + if (flags&D_FLAG) DI--; + else DI++; + c--; + cycles -= 10; + clockhardware(); + FETCHADD(10 - memcycs); + } + if (IRQTEST && c>0) cpu_state.pc=ipc; +// if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; FETCHCLEAR(); } +// else firstrepcycle=1; + break; + case 0xAB: /*REP STOSW*/ + while (c>0 && !IRQTEST) + { + memcycs=0; + writememw(es,DI,AX); + if (flags&D_FLAG) DI-=2; + else DI+=2; + c--; + cycles -= 10; + clockhardware(); + FETCHADD(10 - memcycs); + } + if (IRQTEST && c>0) cpu_state.pc=ipc; +// if (c>0) { firstrepcycle=0; pc=ipc; if (ssegs) ssegs++; FETCHCLEAR(); } +// else firstrepcycle=1; + break; + case 0xAC: /*REP LODSB*/ + if (c>0) + { + temp2=readmemb(ds+SI); + if (flags&D_FLAG) SI--; + else SI++; + c--; + cycles-=4; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; if (ssegs) ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; + break; + case 0xAD: /*REP LODSW*/ + if (c>0) + { + tempw2=readmemw(ds,SI); + if (flags&D_FLAG) SI-=2; + else SI+=2; + c--; + cycles-=4; + } + if (c>0) { firstrepcycle=0; cpu_state.pc=ipc; if (ssegs) ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; + break; + case 0xAE: /*REP SCASB*/ + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) + { + temp2=readmemb(es+DI); +// if (output) printf("SCASB %02X %c %02X %05X ",temp2,temp2,AL,es+DI); + setsub8(AL,temp2); +// if (output && flags&Z_FLAG) printf("Match %02X %02X\n",AL,temp2); + if (flags&D_FLAG) DI--; + else DI++; + c--; + cycles -= 15; + } +//if (output) printf("%i %i %i %i\n",c,(c>0),(fv==((flags&Z_FLAG)?1:0)),((c>0) && (fv==((flags&Z_FLAG)?1:0)))); + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { cpu_state.pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; +// cycles-=120; + break; + case 0xAF: /*REP SCASW*/ + if (fv) flags|=Z_FLAG; + else flags&=~Z_FLAG; + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) + { + tempw=readmemw(es,DI); + setsub16(AX,tempw); + if (flags&D_FLAG) DI-=2; + else DI+=2; + c--; + cycles -= 15; + } + if ((c>0) && (fv==((flags&Z_FLAG)?1:0))) { cpu_state.pc=ipc; firstrepcycle=0; if (ssegs) ssegs++; FETCHCLEAR(); } + else firstrepcycle=1; + break; + default: + cpu_state.pc = ipc+1; + cycles-=20; + FETCHCLEAR(); +// printf("Bad REP %02X\n",temp); +// dumpregs(); +// exit(-1); + } + CX=c; + if (changeds) ds=oldds; + if (IRQTEST) + takeint = 1; +// if (pc==ipc) FETCHCLEAR(); +} + + +int inhlt=0; +uint16_t lastpc,lastcs; +int firstrepcycle; +int skipnextprint=0; + +int instime=0; +//#if 0 +void execx86(int cycs) +{ + uint8_t temp,temp2; + uint16_t addr,tempw,tempw2,tempw3,tempw4; + int8_t offset; + int tempws; + uint32_t templ; + int c; + int tempi; + int trap; + +// printf("Run x86! %i %i\n",cycles,cycs); + cycles+=cycs; +// i86_Execute(cycs); +// return; + while (cycles>0) + { +// old83=old82; +// old82=old8; +// old8=oldpc|(oldcs<<16); +// if (pc==0x96B && cs==0x9E040) { printf("Hit it\n"); output=1; timetolive=150; } +// if (pc<0x8000) printf("%04X : %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %02X %04X %i\n",pc,AX,BX,CX,DX,cs>>4,ds>>4,es>>4,ss>>4,DI,SI,BP,SP,opcode,flags,disctime); + cycdiff=cycles; + timer_start_period(cycles*xt_cpu_multi); + current_diff = 0; + cycles-=nextcyc; +// if (instime) pclog("Cycles %i %i\n",cycles,cycdiff); + nextcyc=0; +// if (output) printf("CLOCK %i %i\n",cycdiff,cycles); + fetchclocks=0; + oldcs=CS; + oldpc=cpu_state.pc; + opcodestart: + opcode=FETCH(); + tempc=flags&C_FLAG; + trap=flags&T_FLAG; + cpu_state.pc--; +// output=1; +// if (output) printf("%04X:%04X : %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %02X %04X\n",cs>>4,pc,AX,BX,CX,DX,cs>>4,ds>>4,es>>4,ss>>4,DI,SI,BP,SP,opcode,flags&~0x200,rmdat); +//#if 0 + if (output) + { +// if ((opcode!=0xF2 && opcode!=0xF3) || firstrepcycle) +// { + if (!skipnextprint) printf("%04X:%04X : %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %04X %02X %04X %i %p %02X\n",cs,cpu_state.pc,AX,BX,CX,DX,CS,DS,ES,SS,DI,SI,BP,SP,opcode,flags, ins, ram, ram[0x1a925]); + skipnextprint=0; +// ins++; +// } + } +//#endif + cpu_state.pc++; + inhlt=0; +// if (ins==500000) { dumpregs(); exit(0); }*/ + switch (opcode) + { + case 0x00: /*ADD 8,reg*/ + fetchea(); +/* if (!rmdat) pc--; + if (!rmdat) + { + fatal("Crashed\n"); +// clear_keybuf(); +// readkey(); + }*/ + temp=geteab(); + setadd8(temp,getr8(reg)); + temp+=getr8(reg); + seteab(temp); + cycles-=((mod==3)?3:24); + break; + case 0x01: /*ADD 16,reg*/ + fetchea(); + tempw=geteaw(); + setadd16(tempw, cpu_state.regs[reg].w); + tempw += cpu_state.regs[reg].w; + seteaw(tempw); + cycles-=((mod==3)?3:24); + break; + case 0x02: /*ADD reg,8*/ + fetchea(); + temp=geteab(); + setadd8(getr8(reg),temp); + setr8(reg,getr8(reg)+temp); + cycles-=((mod==3)?3:13); + break; + case 0x03: /*ADD reg,16*/ + fetchea(); + tempw=geteaw(); + setadd16(cpu_state.regs[reg].w,tempw); + cpu_state.regs[reg].w+=tempw; + cycles-=((mod==3)?3:13); + break; + case 0x04: /*ADD AL,#8*/ + temp=FETCH(); + setadd8(AL,temp); + AL+=temp; + cycles-=4; + break; + case 0x05: /*ADD AX,#16*/ + tempw=getword(); + setadd16(AX,tempw); + AX+=tempw; + cycles-=4; + break; + + case 0x06: /*PUSH ES*/ + if (ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),ES); + SP-=2; + cycles-=14; + break; + case 0x07: /*POP ES*/ + if (ssegs) ss=oldss; + tempw=readmemw(ss,SP); + loadseg(tempw,&_es); + SP+=2; + cycles-=12; + break; + + case 0x08: /*OR 8,reg*/ + fetchea(); + temp=geteab(); + temp|=getr8(reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((mod==3)?3:24); + break; + case 0x09: /*OR 16,reg*/ + fetchea(); + tempw=geteaw(); + tempw|=cpu_state.regs[reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((mod==3)?3:24); + break; + case 0x0A: /*OR reg,8*/ + fetchea(); + temp=geteab(); + temp|=getr8(reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + setr8(reg,temp); + cycles-=((mod==3)?3:13); + break; + case 0x0B: /*OR reg,16*/ + fetchea(); + tempw=geteaw(); + tempw|=cpu_state.regs[reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.regs[reg].w=tempw; + cycles-=((mod==3)?3:13); + break; + case 0x0C: /*OR AL,#8*/ + AL|=FETCH(); + setznp8(AL); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + case 0x0D: /*OR AX,#16*/ + AX|=getword(); + setznp16(AX); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + + case 0x0E: /*PUSH CS*/ + if (ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),CS); + SP-=2; + cycles-=14; + break; + case 0x0F: /*POP CS - 8088/8086 only*/ + if (ssegs) ss=oldss; + tempw=readmemw(ss,SP); + loadseg(tempw,&_cs); + SP+=2; + cycles-=12; + break; + + case 0x10: /*ADC 8,reg*/ + fetchea(); + temp=geteab(); + temp2=getr8(reg); + setadc8(temp,temp2); + temp+=temp2+tempc; + seteab(temp); + cycles-=((mod==3)?3:24); + break; + case 0x11: /*ADC 16,reg*/ + fetchea(); + tempw=geteaw(); + tempw2=cpu_state.regs[reg].w; + setadc16(tempw,tempw2); + tempw+=tempw2+tempc; + seteaw(tempw); + cycles-=((mod==3)?3:24); + break; + case 0x12: /*ADC reg,8*/ + fetchea(); + temp=geteab(); + setadc8(getr8(reg),temp); + setr8(reg,getr8(reg)+temp+tempc); + cycles-=((mod==3)?3:13); + break; + case 0x13: /*ADC reg,16*/ + fetchea(); + tempw=geteaw(); + setadc16(cpu_state.regs[reg].w,tempw); + cpu_state.regs[reg].w+=tempw+tempc; + cycles-=((mod==3)?3:13); + break; + case 0x14: /*ADC AL,#8*/ + tempw=FETCH(); + setadc8(AL,tempw); + AL+=tempw+tempc; + cycles-=4; + break; + case 0x15: /*ADC AX,#16*/ + tempw=getword(); + setadc16(AX,tempw); + AX+=tempw+tempc; + cycles-=4; + break; + + case 0x16: /*PUSH SS*/ + if (ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),SS); + SP-=2; + cycles-=14; + break; + case 0x17: /*POP SS*/ + if (ssegs) ss=oldss; + tempw=readmemw(ss,SP); + loadseg(tempw,&_ss); + SP+=2; + noint=1; + cycles-=12; +// output=1; + break; + + case 0x18: /*SBB 8,reg*/ + fetchea(); + temp=geteab(); + temp2=getr8(reg); + setsbc8(temp,temp2); + temp-=(temp2+tempc); + seteab(temp); + cycles-=((mod==3)?3:24); + break; + case 0x19: /*SBB 16,reg*/ + fetchea(); + tempw=geteaw(); + tempw2=cpu_state.regs[reg].w; +// printf("%04X:%04X SBB %04X-%04X,%i\n",cs>>4,pc,tempw,tempw2,tempc); + setsbc16(tempw,tempw2); + tempw-=(tempw2+tempc); + seteaw(tempw); + cycles-=((mod==3)?3:24); + break; + case 0x1A: /*SBB reg,8*/ + fetchea(); + temp=geteab(); + setsbc8(getr8(reg),temp); + setr8(reg,getr8(reg)-(temp+tempc)); + cycles-=((mod==3)?3:13); + break; + case 0x1B: /*SBB reg,16*/ + fetchea(); + tempw=geteaw(); + tempw2=cpu_state.regs[reg].w; +// printf("%04X:%04X SBB %04X-%04X,%i\n",cs>>4,pc,tempw,tempw2,tempc); + setsbc16(tempw2,tempw); + tempw2-=(tempw+tempc); + cpu_state.regs[reg].w=tempw2; + cycles-=((mod==3)?3:13); + break; + case 0x1C: /*SBB AL,#8*/ + temp=FETCH(); + setsbc8(AL,temp); + AL-=(temp+tempc); + cycles-=4; + break; + case 0x1D: /*SBB AX,#16*/ + tempw=getword(); + setsbc16(AX,tempw); + AX-=(tempw+tempc); + cycles-=4; + break; + + case 0x1E: /*PUSH DS*/ + if (ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),DS); + SP-=2; + cycles-=14; + break; + case 0x1F: /*POP DS*/ + if (ssegs) ss=oldss; + tempw=readmemw(ss,SP); + loadseg(tempw,&_ds); + if (ssegs) oldds=ds; + SP+=2; + cycles-=12; + break; + + case 0x20: /*AND 8,reg*/ + fetchea(); + temp=geteab(); + temp&=getr8(reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((mod==3)?3:24); + break; + case 0x21: /*AND 16,reg*/ + fetchea(); + tempw=geteaw(); + tempw&=cpu_state.regs[reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((mod==3)?3:24); + break; + case 0x22: /*AND reg,8*/ + fetchea(); + temp=geteab(); + temp&=getr8(reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + setr8(reg,temp); + cycles-=((mod==3)?3:13); + break; + case 0x23: /*AND reg,16*/ + fetchea(); + tempw=geteaw(); + tempw&=cpu_state.regs[reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.regs[reg].w=tempw; + cycles-=((mod==3)?3:13); + break; + case 0x24: /*AND AL,#8*/ + AL&=FETCH(); + setznp8(AL); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + case 0x25: /*AND AX,#16*/ + AX&=getword(); + setznp16(AX); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + + case 0x26: /*ES:*/ + oldss=ss; + oldds=ds; + ds=ss=es; + ssegs=2; + cycles-=4; + goto opcodestart; +// break; + + case 0x27: /*DAA*/ + if ((flags&A_FLAG) || ((AL&0xF)>9)) + { + tempi=((uint16_t)AL)+6; + AL+=6; + flags|=A_FLAG; + if (tempi&0x100) flags|=C_FLAG; + } +// else +// flags&=~A_FLAG; + if ((flags&C_FLAG) || (AL>0x9F)) + { + AL+=0x60; + flags|=C_FLAG; + } +// else +// flags&=~C_FLAG; + setznp8(AL); + cycles-=4; + break; + + case 0x28: /*SUB 8,reg*/ + fetchea(); + temp=geteab(); + setsub8(temp,getr8(reg)); + temp-=getr8(reg); + seteab(temp); + cycles-=((mod==3)?3:24); + break; + case 0x29: /*SUB 16,reg*/ + fetchea(); + tempw=geteaw(); +// printf("%04X:%04X %04X-%04X\n",cs>>4,pc,tempw,cpu_state.regs[reg].w); + setsub16(tempw,cpu_state.regs[reg].w); + tempw-=cpu_state.regs[reg].w; + seteaw(tempw); + cycles-=((mod==3)?3:24); + break; + case 0x2A: /*SUB reg,8*/ + fetchea(); + temp=geteab(); + setsub8(getr8(reg),temp); + setr8(reg,getr8(reg)-temp); + cycles-=((mod==3)?3:13); + break; + case 0x2B: /*SUB reg,16*/ + fetchea(); + tempw=geteaw(); +// printf("%04X:%04X %04X-%04X\n",cs>>4,pc,cpu_state.regs[reg].w,tempw); + setsub16(cpu_state.regs[reg].w,tempw); + cpu_state.regs[reg].w-=tempw; + cycles-=((mod==3)?3:13); + break; + case 0x2C: /*SUB AL,#8*/ + temp=FETCH(); + setsub8(AL,temp); + AL-=temp; + cycles-=4; + break; + case 0x2D: /*SUB AX,#16*/ +// printf("INS %i\n",ins); +// output=1; + tempw=getword(); + setsub16(AX,tempw); + AX-=tempw; + cycles-=4; + break; + case 0x2E: /*CS:*/ + oldss=ss; + oldds=ds; + ds=ss=cs; + ssegs=2; + cycles-=4; + goto opcodestart; + case 0x2F: /*DAS*/ + if ((flags&A_FLAG)||((AL&0xF)>9)) + { + tempi=((uint16_t)AL)-6; + AL-=6; + flags|=A_FLAG; + if (tempi&0x100) flags|=C_FLAG; + } +// else +// flags&=~A_FLAG; + if ((flags&C_FLAG)||(AL>0x9F)) + { + AL-=0x60; + flags|=C_FLAG; + } +// else +// flags&=~C_FLAG; + setznp8(AL); + cycles-=4; + break; + case 0x30: /*XOR 8,reg*/ + fetchea(); + temp=geteab(); + temp^=getr8(reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((mod==3)?3:24); + break; + case 0x31: /*XOR 16,reg*/ + fetchea(); + tempw=geteaw(); + tempw^=cpu_state.regs[reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((mod==3)?3:24); + break; + case 0x32: /*XOR reg,8*/ + fetchea(); + temp=geteab(); + temp^=getr8(reg); + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + setr8(reg,temp); + cycles-=((mod==3)?3:13); + break; + case 0x33: /*XOR reg,16*/ + fetchea(); + tempw=geteaw(); + tempw^=cpu_state.regs[reg].w; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cpu_state.regs[reg].w=tempw; + cycles-=((mod==3)?3:13); + break; + case 0x34: /*XOR AL,#8*/ + AL^=FETCH(); + setznp8(AL); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + case 0x35: /*XOR AX,#16*/ + AX^=getword(); + setznp16(AX); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=4; + break; + + case 0x36: /*SS:*/ + oldss=ss; + oldds=ds; + ds=ss=ss; + ssegs=2; + cycles-=4; + goto opcodestart; +// break; + + case 0x37: /*AAA*/ + if ((flags&A_FLAG)||((AL&0xF)>9)) + { + AL+=6; + AH++; + flags|=(A_FLAG|C_FLAG); + } + else + flags&=~(A_FLAG|C_FLAG); + AL&=0xF; + cycles-=8; + break; + + case 0x38: /*CMP 8,reg*/ + fetchea(); + temp=geteab(); +// if (output) printf("CMP %02X-%02X\n",temp,getr8(reg)); + setsub8(temp,getr8(reg)); + cycles-=((mod==3)?3:13); + break; + case 0x39: /*CMP 16,reg*/ + fetchea(); + tempw=geteaw(); +// if (output) printf("CMP %04X-%04X\n",tempw,cpu_state.regs[reg].w); + setsub16(tempw,cpu_state.regs[reg].w); + cycles-=((mod==3)?3:13); + break; + case 0x3A: /*CMP reg,8*/ + fetchea(); + temp=geteab(); +// if (output) printf("CMP %02X-%02X\n",getr8(reg),temp); + setsub8(getr8(reg),temp); + cycles-=((mod==3)?3:13); + break; + case 0x3B: /*CMP reg,16*/ + fetchea(); + tempw=geteaw(); +// printf("CMP %04X-%04X\n",cpu_state.regs[reg].w,tempw); + setsub16(cpu_state.regs[reg].w,tempw); + cycles-=((mod==3)?3:13); + break; + case 0x3C: /*CMP AL,#8*/ + temp=FETCH(); + setsub8(AL,temp); + cycles-=4; + break; + case 0x3D: /*CMP AX,#16*/ + tempw=getword(); + setsub16(AX,tempw); + cycles-=4; + break; + + case 0x3E: /*DS:*/ + oldss=ss; + oldds=ds; + ds=ss=ds; + ssegs=2; + cycles-=4; + goto opcodestart; +// break; + + case 0x3F: /*AAS*/ + if ((flags&A_FLAG)||((AL&0xF)>9)) + { + AL-=6; + AH--; + flags|=(A_FLAG|C_FLAG); + } + else + flags&=~(A_FLAG|C_FLAG); + AL&=0xF; + cycles-=8; + break; + + case 0x40: case 0x41: case 0x42: case 0x43: /*INC r16*/ + case 0x44: case 0x45: case 0x46: case 0x47: + setadd16nc(cpu_state.regs[opcode&7].w,1); + cpu_state.regs[opcode&7].w++; + cycles-=3; + break; + case 0x48: case 0x49: case 0x4A: case 0x4B: /*DEC r16*/ + case 0x4C: case 0x4D: case 0x4E: case 0x4F: + setsub16nc(cpu_state.regs[opcode&7].w,1); + cpu_state.regs[opcode&7].w--; + cycles-=3; + break; + + case 0x50: case 0x51: case 0x52: case 0x53: /*PUSH r16*/ + case 0x54: case 0x55: case 0x56: case 0x57: + if (ssegs) ss=oldss; + SP-=2; + writememw(ss,SP,cpu_state.regs[opcode&7].w); + cycles-=15; + break; + case 0x58: case 0x59: case 0x5A: case 0x5B: /*POP r16*/ + case 0x5C: case 0x5D: case 0x5E: case 0x5F: + if (ssegs) ss=oldss; + SP+=2; + cpu_state.regs[opcode&7].w=readmemw(ss,(SP-2)&0xFFFF); + cycles-=12; + break; + + + case 0x60: /*JO alias*/ + case 0x70: /*JO*/ + offset=(int8_t)FETCH(); + if (flags&V_FLAG) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x61: /*JNO alias*/ + case 0x71: /*JNO*/ + offset=(int8_t)FETCH(); + if (!(flags&V_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x62: /*JB alias*/ + case 0x72: /*JB*/ + offset=(int8_t)FETCH(); + if (flags&C_FLAG) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x63: /*JNB alias*/ + case 0x73: /*JNB*/ + offset=(int8_t)FETCH(); + if (!(flags&C_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x64: /*JE alias*/ + case 0x74: /*JE*/ + offset=(int8_t)FETCH(); + if (flags&Z_FLAG) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x65: /*JNE alias*/ + case 0x75: /*JNE*/ + offset=(int8_t)FETCH(); + cycles-=4; + if (!(flags&Z_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + break; + case 0x66: /*JBE alias*/ + case 0x76: /*JBE*/ + offset=(int8_t)FETCH(); + if (flags&(C_FLAG|Z_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x67: /*JNBE alias*/ + case 0x77: /*JNBE*/ + offset=(int8_t)FETCH(); + if (!(flags&(C_FLAG|Z_FLAG))) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x68: /*JS alias*/ + case 0x78: /*JS*/ + offset=(int8_t)FETCH(); + if (flags&N_FLAG) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x69: /*JNS alias*/ + case 0x79: /*JNS*/ + offset=(int8_t)FETCH(); + if (!(flags&N_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x6A: /*JP alias*/ + case 0x7A: /*JP*/ + offset=(int8_t)FETCH(); + if (flags&P_FLAG) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x6B: /*JNP alias*/ + case 0x7B: /*JNP*/ + offset=(int8_t)FETCH(); + if (!(flags&P_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x6C: /*JL alias*/ + case 0x7C: /*JL*/ + offset=(int8_t)FETCH(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if (temp!=temp2) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x6D: /*JNL alias*/ + case 0x7D: /*JNL*/ + offset=(int8_t)FETCH(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if (temp==temp2) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x6E: /*JLE alias*/ + case 0x7E: /*JLE*/ + offset=(int8_t)FETCH(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if ((flags&Z_FLAG) || (temp!=temp2)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + case 0x6F: /*JNLE alias*/ + case 0x7F: /*JNLE*/ + offset=(int8_t)FETCH(); + temp=(flags&N_FLAG)?1:0; + temp2=(flags&V_FLAG)?1:0; + if (!((flags&Z_FLAG) || (temp!=temp2))) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=4; + break; + + case 0x80: case 0x82: + fetchea(); + temp=geteab(); + temp2=FETCH(); + switch (rmdat&0x38) + { + case 0x00: /*ADD b,#8*/ + setadd8(temp,temp2); + seteab(temp+temp2); + cycles-=((mod==3)?4:23); + break; + case 0x08: /*OR b,#8*/ + temp|=temp2; + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((mod==3)?4:23); + break; + case 0x10: /*ADC b,#8*/ +// temp2+=(flags&C_FLAG); + setadc8(temp,temp2); + seteab(temp+temp2+tempc); + cycles-=((mod==3)?4:23); + break; + case 0x18: /*SBB b,#8*/ +// temp2+=(flags&C_FLAG); + setsbc8(temp,temp2); + seteab(temp-(temp2+tempc)); + cycles-=((mod==3)?4:23); + break; + case 0x20: /*AND b,#8*/ + temp&=temp2; + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((mod==3)?4:23); + break; + case 0x28: /*SUB b,#8*/ + setsub8(temp,temp2); + seteab(temp-temp2); + cycles-=((mod==3)?4:23); + break; + case 0x30: /*XOR b,#8*/ + temp^=temp2; + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteab(temp); + cycles-=((mod==3)?4:23); + break; + case 0x38: /*CMP b,#8*/ + setsub8(temp,temp2); + cycles-=((mod==3)?4:14); + break; + +// default: +// printf("Bad 80 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0x81: + fetchea(); + tempw=geteaw(); + tempw2=getword(); + switch (rmdat&0x38) + { + case 0x00: /*ADD w,#16*/ + setadd16(tempw,tempw2); + tempw+=tempw2; + seteaw(tempw); + cycles-=((mod==3)?4:23); + break; + case 0x08: /*OR w,#16*/ + tempw|=tempw2; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((mod==3)?4:23); + break; + case 0x10: /*ADC w,#16*/ +// tempw2+=(flags&C_FLAG); + setadc16(tempw,tempw2); + tempw+=tempw2+tempc; + seteaw(tempw); + cycles-=((mod==3)?4:23); + break; + case 0x20: /*AND w,#16*/ + tempw&=tempw2; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((mod==3)?4:23); + break; + case 0x18: /*SBB w,#16*/ +// tempw2+=(flags&C_FLAG); + setsbc16(tempw,tempw2); + seteaw(tempw-(tempw2+tempc)); + cycles-=((mod==3)?4:23); + break; + case 0x28: /*SUB w,#16*/ + setsub16(tempw,tempw2); + tempw-=tempw2; + seteaw(tempw); + cycles-=((mod==3)?4:23); + break; + case 0x30: /*XOR w,#16*/ + tempw^=tempw2; + setznp16(tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + seteaw(tempw); + cycles-=((mod==3)?4:23); + break; + case 0x38: /*CMP w,#16*/ +// printf("CMP %04X %04X\n",tempw,tempw2); + setsub16(tempw,tempw2); + cycles-=((mod==3)?4:14); + break; + +// default: +// printf("Bad 81 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0x83: + fetchea(); + tempw=geteaw(); + tempw2=FETCH(); + if (tempw2&0x80) tempw2|=0xFF00; + switch (rmdat&0x38) + { + case 0x00: /*ADD w,#8*/ + setadd16(tempw,tempw2); + tempw+=tempw2; + seteaw(tempw); + cycles-=((mod==3)?4:23); + break; + case 0x08: /*OR w,#8*/ + tempw|=tempw2; + setznp16(tempw); + seteaw(tempw); + flags&=~(C_FLAG|A_FLAG|V_FLAG); + cycles-=((mod==3)?4:23); + break; + case 0x10: /*ADC w,#8*/ +// tempw2+=(flags&C_FLAG); + setadc16(tempw,tempw2); + tempw+=tempw2+tempc; + seteaw(tempw); + cycles-=((mod==3)?4:23); + break; + case 0x18: /*SBB w,#8*/ +// tempw2+=(flags&C_FLAG); + setsbc16(tempw,tempw2); + tempw-=(tempw2+tempc); + seteaw(tempw); + cycles-=((mod==3)?4:23); + break; + case 0x20: /*AND w,#8*/ + tempw&=tempw2; + setznp16(tempw); + seteaw(tempw); + cycles-=((mod==3)?4:23); + flags&=~(C_FLAG|A_FLAG|V_FLAG); + break; + case 0x28: /*SUB w,#8*/ + setsub16(tempw,tempw2); + tempw-=tempw2; + seteaw(tempw); + cycles-=((mod==3)?4:23); + break; + case 0x30: /*XOR w,#8*/ + tempw^=tempw2; + setznp16(tempw); + seteaw(tempw); + cycles-=((mod==3)?4:23); + flags&=~(C_FLAG|A_FLAG|V_FLAG); + break; + case 0x38: /*CMP w,#8*/ + setsub16(tempw,tempw2); + cycles-=((mod==3)?4:14); + break; + +// default: +// printf("Bad 83 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0x84: /*TEST b,reg*/ + fetchea(); + temp=geteab(); + temp2=getr8(reg); + setznp8(temp&temp2); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=((mod==3)?3:13); + break; + case 0x85: /*TEST w,reg*/ + fetchea(); + tempw=geteaw(); + tempw2=cpu_state.regs[reg].w; + setznp16(tempw&tempw2); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=((mod==3)?3:13); + break; + case 0x86: /*XCHG b,reg*/ + fetchea(); + temp=geteab(); + seteab(getr8(reg)); + setr8(reg,temp); + cycles-=((mod==3)?4:25); + break; + case 0x87: /*XCHG w,reg*/ + fetchea(); + tempw=geteaw(); + seteaw(cpu_state.regs[reg].w); + cpu_state.regs[reg].w=tempw; + cycles-=((mod==3)?4:25); + break; + + case 0x88: /*MOV b,reg*/ + fetchea(); + seteab(getr8(reg)); + cycles-=((mod==3)?2:13); + break; + case 0x89: /*MOV w,reg*/ + fetchea(); + seteaw(cpu_state.regs[reg].w); + cycles-=((mod==3)?2:13); + break; + case 0x8A: /*MOV reg,b*/ + fetchea(); + temp=geteab(); + setr8(reg,temp); + cycles-=((mod==3)?2:12); + break; + case 0x8B: /*MOV reg,w*/ + fetchea(); + tempw=geteaw(); + cpu_state.regs[reg].w=tempw; + cycles-=((mod==3)?2:12); + break; + + case 0x8C: /*MOV w,sreg*/ + fetchea(); + switch (rmdat&0x38) + { + case 0x00: /*ES*/ + seteaw(ES); + break; + case 0x08: /*CS*/ + seteaw(CS); + break; + case 0x18: /*DS*/ + if (ssegs) ds=oldds; + seteaw(DS); + break; + case 0x10: /*SS*/ + if (ssegs) ss=oldss; + seteaw(SS); + break; + } + cycles-=((mod==3)?2:13); + break; + + case 0x8D: /*LEA*/ + fetchea(); + cpu_state.regs[reg].w=eaaddr; + cycles-=2; + break; + + case 0x8E: /*MOV sreg,w*/ +// if (output) printf("MOV %04X ",pc); + fetchea(); +// if (output) printf("%04X %02X\n",pc,rmdat); + switch (rmdat&0x38) + { + case 0x00: /*ES*/ + tempw=geteaw(); + loadseg(tempw,&_es); + break; + case 0x08: /*CS - 8088/8086 only*/ + tempw=geteaw(); + loadseg(tempw,&_cs); + break; + case 0x18: /*DS*/ + tempw=geteaw(); + loadseg(tempw,&_ds); + if (ssegs) oldds=ds; + break; + case 0x10: /*SS*/ + tempw=geteaw(); + loadseg(tempw,&_ss); + if (ssegs) oldss=ss; +// printf("LOAD SS %04X %04X\n",tempw,SS); +// printf("SS loaded with %04X %04X:%04X %04X %04X %04X\n",ss>>4,cs>>4,pc,CX,DX,es>>4); + break; + } + cycles-=((mod==3)?2:12); + skipnextprint=1; + noint=1; + break; + + case 0x8F: /*POPW*/ + fetchea(); + if (ssegs) ss=oldss; + tempw=readmemw(ss,SP); + SP+=2; + seteaw(tempw); + cycles-=25; + break; + + case 0x90: /*NOP*/ + cycles-=3; + break; + + case 0x91: case 0x92: case 0x93: /*XCHG AX*/ + case 0x94: case 0x95: case 0x96: case 0x97: + tempw=AX; + AX=cpu_state.regs[opcode&7].w; + cpu_state.regs[opcode&7].w=tempw; + cycles-=3; + break; + + case 0x98: /*CBW*/ + AH=(AL&0x80)?0xFF:0; + cycles-=2; + break; + case 0x99: /*CWD*/ + DX=(AX&0x8000)?0xFFFF:0; + cycles-=5; + break; + case 0x9A: /*CALL FAR*/ + tempw=getword(); + tempw2=getword(); + tempw3=CS; + tempw4=cpu_state.pc; + if (ssegs) ss=oldss; + cpu_state.pc=tempw; +// printf("0x9a"); + loadcs(tempw2); + writememw(ss,(SP-2)&0xFFFF,tempw3); + writememw(ss,(SP-4)&0xFFFF,tempw4); + SP-=4; + cycles-=36; + FETCHCLEAR(); + break; + case 0x9B: /*WAIT*/ + cycles-=4; + break; + case 0x9C: /*PUSHF*/ + if (ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),flags|0xF000); + SP-=2; + cycles-=14; + break; + case 0x9D: /*POPF*/ + if (ssegs) ss=oldss; + flags=readmemw(ss,SP)&0xFFF; + SP+=2; + cycles-=12; + break; + case 0x9E: /*SAHF*/ + flags=(flags&0xFF00)|AH; + cycles-=4; + break; + case 0x9F: /*LAHF*/ + AH=flags&0xFF; + cycles-=4; + break; + + case 0xA0: /*MOV AL,(w)*/ + addr=getword(); + AL=readmemb(ds+addr); + cycles-=14; + break; + case 0xA1: /*MOV AX,(w)*/ + addr=getword(); +// printf("Reading AX from %05X %04X:%04X\n",ds+addr,ds>>4,addr); + AX=readmemw(ds,addr); + cycles-=!4; + break; + case 0xA2: /*MOV (w),AL*/ + addr=getword(); + writememb(ds+addr,AL); + cycles-=14; + break; + case 0xA3: /*MOV (w),AX*/ + addr=getword(); +// if (!addr) printf("Write !addr %04X:%04X\n",cs>>4,pc); + writememw(ds,addr,AX); + cycles-=14; + break; + + case 0xA4: /*MOVSB*/ + temp=readmemb(ds+SI); + writememb(es+DI,temp); + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + cycles-=18; + break; + case 0xA5: /*MOVSW*/ + tempw=readmemw(ds,SI); + writememw(es,DI,tempw); + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + cycles-=18; + break; + case 0xA6: /*CMPSB*/ + temp =readmemb(ds+SI); + temp2=readmemb(es+DI); + setsub8(temp,temp2); + if (flags&D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + cycles-=30; + break; + case 0xA7: /*CMPSW*/ + tempw =readmemw(ds,SI); + tempw2=readmemw(es,DI); +// printf("CMPSW %04X %04X\n",tempw,tempw2); + setsub16(tempw,tempw2); + if (flags&D_FLAG) { DI-=2; SI-=2; } + else { DI+=2; SI+=2; } + cycles-=30; + break; + case 0xA8: /*TEST AL,#8*/ + temp=FETCH(); + setznp8(AL&temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=5; + break; + case 0xA9: /*TEST AX,#16*/ + tempw=getword(); + setznp16(AX&tempw); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=5; + break; + case 0xAA: /*STOSB*/ + writememb(es+DI,AL); + if (flags&D_FLAG) DI--; + else DI++; + cycles-=11; + break; + case 0xAB: /*STOSW*/ + writememw(es,DI,AX); + if (flags&D_FLAG) DI-=2; + else DI+=2; + cycles-=11; + break; + case 0xAC: /*LODSB*/ + AL=readmemb(ds+SI); +// printf("LODSB %04X:%04X %02X %04X:%04X\n",cs>>4,pc,AL,ds>>4,SI); + if (flags&D_FLAG) SI--; + else SI++; + cycles-=16; + break; + case 0xAD: /*LODSW*/ +// if (times) printf("LODSW %04X:%04X\n",cs>>4,pc); + AX=readmemw(ds,SI); + if (flags&D_FLAG) SI-=2; + else SI+=2; + cycles-=16; + break; + case 0xAE: /*SCASB*/ + temp=readmemb(es+DI); + setsub8(AL,temp); + if (flags&D_FLAG) DI--; + else DI++; + cycles-=19; + break; + case 0xAF: /*SCASW*/ + tempw=readmemw(es,DI); + setsub16(AX,tempw); + if (flags&D_FLAG) DI-=2; + else DI+=2; + cycles-=19; + break; + + case 0xB0: /*MOV AL,#8*/ + AL=FETCH(); + cycles-=4; + break; + case 0xB1: /*MOV CL,#8*/ + CL=FETCH(); + cycles-=4; + break; + case 0xB2: /*MOV DL,#8*/ + DL=FETCH(); + cycles-=4; + break; + case 0xB3: /*MOV BL,#8*/ + BL=FETCH(); + cycles-=4; + break; + case 0xB4: /*MOV AH,#8*/ + AH=FETCH(); + cycles-=4; + break; + case 0xB5: /*MOV CH,#8*/ + CH=FETCH(); + cycles-=4; + break; + case 0xB6: /*MOV DH,#8*/ + DH=FETCH(); + cycles-=4; + break; + case 0xB7: /*MOV BH,#8*/ + BH=FETCH(); + cycles-=4; + break; + case 0xB8: case 0xB9: case 0xBA: case 0xBB: /*MOV reg,#16*/ + case 0xBC: case 0xBD: case 0xBE: case 0xBF: + cpu_state.regs[opcode&7].w=getword(); + cycles-=4; + break; + + case 0xC0: /*RET alias*/ + case 0xC2: /*RET*/ + tempw=getword(); + if (ssegs) ss=oldss; + cpu_state.pc=readmemw(ss,SP); +// printf("C2\n"); +// printf("RET to %04X\n",pc); + SP+=2+tempw; + cycles-=24; + FETCHCLEAR(); + break; + case 0xC1: /*RET alias*/ + case 0xC3: /*RET*/ + if (ssegs) ss=oldss; + cpu_state.pc=readmemw(ss,SP); +// printf("C3\n"); +// if (output) printf("RET to %04X %05X\n",pc,ss+SP); + SP+=2; + cycles-=20; + FETCHCLEAR(); + break; + case 0xC4: /*LES*/ + fetchea(); + cpu_state.regs[reg].w=readmemw(easeg,eaaddr); //geteaw(); + tempw=readmemw(easeg,(eaaddr+2)&0xFFFF); //geteaw2(); + loadseg(tempw,&_es); + cycles-=24; + break; + case 0xC5: /*LDS*/ + fetchea(); + cpu_state.regs[reg].w=readmemw(easeg,eaaddr); + tempw=readmemw(easeg,(eaaddr+2)&0xFFFF); + loadseg(tempw,&_ds); + if (ssegs) oldds=ds; + cycles-=24; + break; + case 0xC6: /*MOV b,#8*/ + fetchea(); + temp=FETCH(); + seteab(temp); + cycles-=((mod==3)?4:14); + break; + case 0xC7: /*MOV w,#16*/ + fetchea(); + tempw=getword(); + seteaw(tempw); + cycles-=((mod==3)?4:14); + break; + + case 0xC8: /*RETF alias*/ + case 0xCA: /*RETF*/ + tempw=getword(); + if (ssegs) ss=oldss; + cpu_state.pc=readmemw(ss,SP); +// printf("CA\n"); + loadcs(readmemw(ss,SP+2)); + SP+=4; + SP+=tempw; + cycles-=33; + FETCHCLEAR(); + break; + case 0xC9: /*RETF alias*/ + case 0xCB: /*RETF*/ + if (ssegs) ss=oldss; + cpu_state.pc=readmemw(ss,SP); +// printf("CB\n"); + loadcs(readmemw(ss,SP+2)); + SP+=4; + cycles-=34; + FETCHCLEAR(); + break; + case 0xCC: /*INT 3*/ + if (ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),flags|0xF000); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); + SP-=6; + addr=3<<2; + flags&=~I_FLAG; + flags&=~T_FLAG; +// printf("CC %04X:%04X ",CS,pc); + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + FETCHCLEAR(); +// printf("%04X:%04X\n",CS,pc); + cycles-=72; + break; + case 0xCD: /*INT*/ + lastpc=cpu_state.pc; + lastcs=CS; + temp=FETCH(); + + if (ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),flags|0xF000); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); + flags&=~T_FLAG; + SP-=6; + addr=temp<<2; + cpu_state.pc=readmemw(0,addr); + + loadcs(readmemw(0,addr+2)); + FETCHCLEAR(); + + cycles-=71; + break; + case 0xCF: /*IRET*/ + if (ssegs) ss=oldss; + tempw=CS; + tempw2=cpu_state.pc; + cpu_state.pc=readmemw(ss,SP); +// printf("CF\n"); + loadcs(readmemw(ss,((SP+2)&0xFFFF))); + flags=readmemw(ss,((SP+4)&0xFFFF))&0xFFF; + SP+=6; + cycles-=44; + FETCHCLEAR(); + nmi_enable = 1; + break; + case 0xD0: + fetchea(); + temp=geteab(); + switch (rmdat&0x38) + { + case 0x00: /*ROL b,1*/ + if (temp&0x80) flags|=C_FLAG; + else flags&=~C_FLAG; + temp<<=1; + if (flags&C_FLAG) temp|=1; + seteab(temp); +// setznp8(temp); + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?2:23); + break; + case 0x08: /*ROR b,1*/ + if (temp&1) flags|=C_FLAG; + else flags&=~C_FLAG; + temp>>=1; + if (flags&C_FLAG) temp|=0x80; + seteab(temp); +// setznp8(temp); + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?2:23); + break; + case 0x10: /*RCL b,1*/ + temp2=flags&C_FLAG; + if (temp&0x80) flags|=C_FLAG; + else flags&=~C_FLAG; + temp<<=1; + if (temp2) temp|=1; + seteab(temp); +// setznp8(temp); + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?2:23); + break; + case 0x18: /*RCR b,1*/ + temp2=flags&C_FLAG; + if (temp&1) flags|=C_FLAG; + else flags&=~C_FLAG; + temp>>=1; + if (temp2) temp|=0x80; + seteab(temp); +// setznp8(temp); + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?2:23); + break; + case 0x20: case 0x30: /*SHL b,1*/ + if (temp&0x80) flags|=C_FLAG; + else flags&=~C_FLAG; + if ((temp^(temp<<1))&0x80) flags|=V_FLAG; + else flags&=~V_FLAG; + temp<<=1; + seteab(temp); + setznp8(temp); + cycles-=((mod==3)?2:23); + flags|=A_FLAG; + break; + case 0x28: /*SHR b,1*/ + if (temp&1) flags|=C_FLAG; + else flags&=~C_FLAG; + if (temp&0x80) flags|=V_FLAG; + else flags&=~V_FLAG; + temp>>=1; + seteab(temp); + setznp8(temp); + cycles-=((mod==3)?2:23); + flags|=A_FLAG; + break; + case 0x38: /*SAR b,1*/ + if (temp&1) flags|=C_FLAG; + else flags&=~C_FLAG; + temp>>=1; + if (temp&0x40) temp|=0x80; + seteab(temp); + setznp8(temp); + cycles-=((mod==3)?2:23); + flags|=A_FLAG; + flags&=~V_FLAG; + break; + +// default: +// printf("Bad D0 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0xD1: + fetchea(); + tempw=geteaw(); + switch (rmdat&0x38) + { + case 0x00: /*ROL w,1*/ + if (tempw&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw<<=1; + if (flags&C_FLAG) tempw|=1; + seteaw(tempw); +// setznp16(tempw); + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?2:23); + break; + case 0x08: /*ROR w,1*/ + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw>>=1; + if (flags&C_FLAG) tempw|=0x8000; + seteaw(tempw); +// setznp16(tempw); + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?2:23); + break; + case 0x10: /*RCL w,1*/ + temp2=flags&C_FLAG; + if (tempw&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw<<=1; + if (temp2) tempw|=1; + seteaw(tempw); + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?2:23); + break; + case 0x18: /*RCR w,1*/ + temp2=flags&C_FLAG; + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw>>=1; + if (temp2) tempw|=0x8000; + seteaw(tempw); +// setznp16(tempw); + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?2:23); + break; + case 0x20: case 0x30: /*SHL w,1*/ + if (tempw&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + if ((tempw^(tempw<<1))&0x8000) flags|=V_FLAG; + else flags&=~V_FLAG; + tempw<<=1; + seteaw(tempw); + setznp16(tempw); + cycles-=((mod==3)?2:23); + flags|=A_FLAG; + break; + case 0x28: /*SHR w,1*/ + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + if (tempw&0x8000) flags|=V_FLAG; + else flags&=~V_FLAG; + tempw>>=1; + seteaw(tempw); + setznp16(tempw); + cycles-=((mod==3)?2:23); + flags|=A_FLAG; + break; + + case 0x38: /*SAR w,1*/ + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw>>=1; + if (tempw&0x4000) tempw|=0x8000; + seteaw(tempw); + setznp16(tempw); + cycles-=((mod==3)?2:23); + flags|=A_FLAG; + flags&=~V_FLAG; + break; + +// default: +// printf("Bad D1 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0xD2: + fetchea(); + temp=geteab(); + c=CL; +// cycles-=c; + if (!c) break; +// if (c>7) printf("Shiftb %i %02X\n",rmdat&0x38,c); + switch (rmdat&0x38) + { + case 0x00: /*ROL b,CL*/ + while (c>0) + { + temp2=(temp&0x80)?1:0; + temp=(temp<<1)|temp2; + c--; + cycles-=4; + } + if (temp2) flags|=C_FLAG; + else flags&=~C_FLAG; + seteab(temp); +// setznp8(temp); + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?8:28); + break; + case 0x08: /*ROR b,CL*/ + while (c>0) + { + temp2=temp&1; + temp>>=1; + if (temp2) temp|=0x80; + c--; + cycles-=4; + } + if (temp2) flags|=C_FLAG; + else flags&=~C_FLAG; + seteab(temp); + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?8:28); + break; + case 0x10: /*RCL b,CL*/ +// printf("RCL %i %02X %02X\n",c,CL,temp); + while (c>0) + { + templ=flags&C_FLAG; + temp2=temp&0x80; + temp<<=1; + if (temp2) flags|=C_FLAG; + else flags&=~C_FLAG; + if (templ) temp|=1; + c--; + cycles-=4; + } +// printf("Now %02X\n",temp); + seteab(temp); + if ((flags&C_FLAG)^(temp>>7)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?8:28); + break; + case 0x18: /*RCR b,CL*/ + while (c>0) + { + templ=flags&C_FLAG; + temp2=temp&1; + temp>>=1; + if (temp2) flags|=C_FLAG; + else flags&=~C_FLAG; + if (templ) temp|=0x80; + c--; + cycles-=4; + } +// if (temp2) flags|=C_FLAG; +// else flags&=~C_FLAG; + seteab(temp); + if ((temp^(temp>>1))&0x40) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?8:28); + break; + case 0x20: case 0x30: /*SHL b,CL*/ + if ((temp<<(c-1))&0x80) flags|=C_FLAG; + else flags&=~C_FLAG; + temp<<=c; + seteab(temp); + setznp8(temp); + cycles-=(c*4); + cycles-=((mod==3)?8:28); + flags|=A_FLAG; + break; + case 0x28: /*SHR b,CL*/ + if ((temp>>(c-1))&1) flags|=C_FLAG; + else flags&=~C_FLAG; + temp>>=c; + seteab(temp); + setznp8(temp); + cycles-=(c*4); + cycles-=((mod==3)?8:28); + flags|=A_FLAG; + break; + case 0x38: /*SAR b,CL*/ + if ((temp>>(c-1))&1) flags|=C_FLAG; + else flags&=~C_FLAG; + while (c>0) + { + temp>>=1; + if (temp&0x40) temp|=0x80; + c--; + cycles-=4; + } + seteab(temp); + setznp8(temp); + cycles-=((mod==3)?8:28); + flags|=A_FLAG; + break; + +// default: +// printf("Bad D2 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0xD3: + fetchea(); + tempw=geteaw(); + c=CL; +// cycles-=c; + if (!c) break; +// if (c>15) printf("Shiftw %i %02X\n",rmdat&0x38,c); + switch (rmdat&0x38) + { + case 0x00: /*ROL w,CL*/ + while (c>0) + { + temp=(tempw&0x8000)?1:0; + tempw=(tempw<<1)|temp; + c--; + cycles-=4; + } + if (temp) flags|=C_FLAG; + else flags&=~C_FLAG; + seteaw(tempw); + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?8:28); + break; + case 0x08: /*ROR w,CL*/ + while (c>0) + { + tempw2=(tempw&1)?0x8000:0; + tempw=(tempw>>1)|tempw2; + c--; + cycles-=4; + } + if (tempw2) flags|=C_FLAG; + else flags&=~C_FLAG; + seteaw(tempw); + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?8:28); + break; + case 0x10: /*RCL w,CL*/ + while (c>0) + { + templ=flags&C_FLAG; + if (tempw&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw=(tempw<<1)|templ; + c--; + cycles-=4; + } + if (temp) flags|=C_FLAG; + else flags&=~C_FLAG; + seteaw(tempw); + if ((flags&C_FLAG)^(tempw>>15)) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?8:28); + break; + case 0x18: /*RCR w,CL*/ + while (c>0) + { + templ=flags&C_FLAG; + tempw2=(templ&1)?0x8000:0; + if (tempw&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw=(tempw>>1)|tempw2; + c--; + cycles-=4; + } + if (tempw2) flags|=C_FLAG; + else flags&=~C_FLAG; + seteaw(tempw); + if ((tempw^(tempw>>1))&0x4000) flags|=V_FLAG; + else flags&=~V_FLAG; + cycles-=((mod==3)?8:28); + break; + + case 0x20: case 0x30: /*SHL w,CL*/ + if (c>16) + { + tempw=0; + flags&=~C_FLAG; + } + else + { + if ((tempw<<(c-1))&0x8000) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw<<=c; + } + seteaw(tempw); + setznp16(tempw); + cycles-=(c*4); + cycles-=((mod==3)?8:28); + flags|=A_FLAG; + break; + + case 0x28: /*SHR w,CL*/ + if ((tempw>>(c-1))&1) flags|=C_FLAG; + else flags&=~C_FLAG; + tempw>>=c; + seteaw(tempw); + setznp16(tempw); + cycles-=(c*4); + cycles-=((mod==3)?8:28); + flags|=A_FLAG; + break; + + case 0x38: /*SAR w,CL*/ + tempw2=tempw&0x8000; + if ((tempw>>(c-1))&1) flags|=C_FLAG; + else flags&=~C_FLAG; + while (c>0) + { + tempw=(tempw>>1)|tempw2; + c--; + cycles-=4; + } + seteaw(tempw); + setznp16(tempw); + cycles-=((mod==3)?8:28); + flags|=A_FLAG; + break; + +// default: +// printf("Bad D3 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0xD4: /*AAM*/ + tempws=FETCH(); + AH=AL/tempws; + AL%=tempws; + setznp16(AX); + cycles-=83; + break; + case 0xD5: /*AAD*/ + tempws=FETCH(); + AL=(AH*tempws)+AL; + AH=0; + setznp16(AX); + cycles-=60; + break; + case 0xD6: /*SETALC*/ + AL = (flags & C_FLAG) ? 0xff : 0; + cycles -= 4; + break; + case 0xD7: /*XLAT*/ + addr=BX+AL; + AL=readmemb(ds+addr); + cycles-=11; + break; + case 0xD9: case 0xDA: case 0xDB: case 0xDD: /*ESCAPE*/ + case 0xDC: case 0xDE: case 0xDF: case 0xD8: + fetchea(); + geteab(); + break; + + case 0xE0: /*LOOPNE*/ + offset=(int8_t)FETCH(); + CX--; + if (CX && !(flags&Z_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=6; + break; + case 0xE1: /*LOOPE*/ + offset=(int8_t)FETCH(); + CX--; + if (CX && (flags&Z_FLAG)) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=6; + break; + case 0xE2: /*LOOP*/ +// printf("LOOP start\n"); + offset=(int8_t)FETCH(); + CX--; + if (CX) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=5; +// printf("LOOP end!\n"); + break; + case 0xE3: /*JCXZ*/ + offset=(int8_t)FETCH(); + if (!CX) { cpu_state.pc+=offset; cycles-=12; FETCHCLEAR(); } + cycles-=6; + break; + + case 0xE4: /*IN AL*/ + temp=FETCH(); + AL=inb(temp); + cycles-=14; + break; + case 0xE5: /*IN AX*/ + temp=FETCH(); + AL=inb(temp); + AH=inb(temp+1); + cycles-=14; + break; + case 0xE6: /*OUT AL*/ + temp=FETCH(); + outb(temp,AL); + cycles-=14; + break; + case 0xE7: /*OUT AX*/ + temp=FETCH(); + outb(temp,AL); + outb(temp+1,AH); + cycles-=14; + break; + + case 0xE8: /*CALL rel 16*/ + tempw=getword(); + if (ssegs) ss=oldss; +// writememb(ss+((SP-1)&0xFFFF),pc>>8); + writememw(ss,((SP-2)&0xFFFF),cpu_state.pc); + SP-=2; + cpu_state.pc+=tempw; + cycles-=23; + FETCHCLEAR(); + break; + case 0xE9: /*JMP rel 16*/ +// pclog("PC was %04X\n",cpu_state.pc); + tempw = getword(); + cpu_state.pc += tempw; +// pclog("PC now %04X\n",cpu_state.pc); + cycles-=15; + FETCHCLEAR(); + break; + case 0xEA: /*JMP far*/ + addr=getword(); + tempw=getword(); + cpu_state.pc=addr; +// printf("EA\n"); + loadcs(tempw); +// cs=loadcs(CS); +// cs=CS<<4; + cycles-=15; + FETCHCLEAR(); + break; + case 0xEB: /*JMP rel*/ + offset=(int8_t)FETCH(); + cpu_state.pc+=offset; + cycles-=15; + FETCHCLEAR(); + break; + case 0xEC: /*IN AL,DX*/ + AL=inb(DX); + cycles-=12; + break; + case 0xED: /*IN AX,DX*/ + AL=inb(DX); + AH=inb(DX+1); + cycles-=12; + break; + case 0xEE: /*OUT DX,AL*/ + outb(DX,AL); + cycles-=12; + break; + case 0xEF: /*OUT DX,AX*/ + outb(DX,AL); + outb(DX+1,AH); + cycles-=12; + break; + + case 0xF0: /*LOCK*/ + case 0xF1: /*LOCK alias*/ + cycles-=4; + break; + + case 0xF2: /*REPNE*/ + rep(0); + break; + case 0xF3: /*REPE*/ + rep(1); + break; + + case 0xF4: /*HLT*/ +// printf("IN HLT!!!! %04X:%04X %08X %08X %08X\n",oldcs,oldpc,old8,old82,old83); +/* if (!(flags & I_FLAG)) + { + pclog("HLT\n"); + dumpregs(); + exit(-1); + }*/ + inhlt=1; + cpu_state.pc--; + FETCHCLEAR(); + cycles-=2; + break; + case 0xF5: /*CMC*/ + flags^=C_FLAG; + cycles-=2; + break; + + case 0xF6: + fetchea(); + temp=geteab(); + switch (rmdat&0x38) + { + case 0x00: /*TEST b,#8*/ + temp2=FETCH(); + temp&=temp2; + setznp8(temp); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=((mod==3)?5:11); + break; + case 0x10: /*NOT b*/ + temp=~temp; + seteab(temp); + cycles-=((mod==3)?3:24); + break; + case 0x18: /*NEG b*/ + setsub8(0,temp); + temp=0-temp; + seteab(temp); + cycles-=((mod==3)?3:24); + break; + case 0x20: /*MUL AL,b*/ + setznp8(AL); + AX=AL*temp; + if (AX) flags&=~Z_FLAG; + else flags|=Z_FLAG; + if (AH) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); + cycles-=70; + break; + case 0x28: /*IMUL AL,b*/ + setznp8(AL); + tempws=(int)((int8_t)AL)*(int)((int8_t)temp); + AX=tempws&0xFFFF; + if (AX) flags&=~Z_FLAG; + else flags|=Z_FLAG; + if (AH) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); + cycles-=80; + break; + case 0x30: /*DIV AL,b*/ + tempw=AX; + if (temp) + { + tempw2=tempw%temp; +/* if (!tempw) + { + writememw((ss+SP)-2,flags|0xF000); + writememw((ss+SP)-4,cs>>4); + writememw((ss+SP)-6,pc); + SP-=6; + flags&=~I_FLAG; + pc=readmemw(0); + cs=readmemw(2)<<4; + printf("Div by zero %04X:%04X\n",cs>>4,pc); +// dumpregs(); +// exit(-1); + } + else + {*/ + AH=tempw2; + tempw/=temp; + AL=tempw&0xFF; +// } + } + else + { + printf("DIVb BY 0 %04X:%04X\n",cs>>4,cpu_state.pc); + writememw(ss,(SP-2)&0xFFFF,flags|0xF000); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + flags&=~I_FLAG; + flags&=~T_FLAG; + cpu_state.pc=readmemw(0,0); +// printf("F6 30\n"); + loadcs(readmemw(0,2)); + FETCHCLEAR(); +// cs=loadcs(CS); +// cs=CS<<4; +// printf("Div by zero %04X:%04X %02X %02X\n",cs>>4,pc,0xf6,0x30); +// dumpregs(); +// exit(-1); + } + cycles-=80; + break; + case 0x38: /*IDIV AL,b*/ + tempws=(int)AX; + if (temp) + { + tempw2=tempws%(int)((int8_t)temp); +/* if (!tempw) + { + writememw((ss+SP)-2,flags|0xF000); + writememw((ss+SP)-4,cs>>4); + writememw((ss+SP)-6,pc); + SP-=6; + flags&=~I_FLAG; + pc=readmemw(0); + cs=readmemw(2)<<4; + printf("Div by zero %04X:%04X\n",cs>>4,pc); + } + else + {*/ + AH=tempw2&0xFF; + tempws/=(int)((int8_t)temp); + AL=tempws&0xFF; +// } + } + else + { + printf("IDIVb BY 0 %04X:%04X\n",cs>>4,cpu_state.pc); + writememw(ss,(SP-2)&0xFFFF,flags|0xF000); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + flags&=~I_FLAG; + flags&=~T_FLAG; + cpu_state.pc=readmemw(0,0); +// printf("F6 38\n"); + loadcs(readmemw(0,2)); + FETCHCLEAR(); +// cs=loadcs(CS); +// cs=CS<<4; +// printf("Div by zero %04X:%04X %02X %02X\n",cs>>4,pc,0xf6,0x38); + } + cycles-=101; + break; + +// default: +// printf("Bad F6 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0xF7: + fetchea(); + tempw=geteaw(); + switch (rmdat&0x38) + { + case 0x00: /*TEST w*/ + tempw2=getword(); + setznp16(tempw&tempw2); + flags&=~(C_FLAG|V_FLAG|A_FLAG); + cycles-=((mod==3)?5:11); + break; + case 0x10: /*NOT w*/ + seteaw(~tempw); + cycles-=((mod==3)?3:24); + break; + case 0x18: /*NEG w*/ + setsub16(0,tempw); + tempw=0-tempw; + seteaw(tempw); + cycles-=((mod==3)?3:24); + break; + case 0x20: /*MUL AX,w*/ + setznp16(AX); + templ=AX*tempw; +// if (output) printf("%04X*%04X=%08X\n",AX,tempw,templ); + AX=templ&0xFFFF; + DX=templ>>16; + if (AX|DX) flags&=~Z_FLAG; + else flags|=Z_FLAG; + if (DX) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); + cycles-=118; + break; + case 0x28: /*IMUL AX,w*/ + setznp16(AX); +// printf("IMUL %i %i ",(int)((int16_t)AX),(int)((int16_t)tempw)); + tempws=(int)((int16_t)AX)*(int)((int16_t)tempw); + if ((tempws>>15) && ((tempws>>15)!=-1)) flags|=(C_FLAG|V_FLAG); + else flags&=~(C_FLAG|V_FLAG); +// printf("%i ",tempws); + AX=tempws&0xFFFF; + tempws=(uint16_t)(tempws>>16); + DX=tempws&0xFFFF; +// printf("%04X %04X\n",AX,DX); +// dumpregs(); +// exit(-1); + if (AX|DX) flags&=~Z_FLAG; + else flags|=Z_FLAG; + cycles-=128; + break; + case 0x30: /*DIV AX,w*/ + templ=(DX<<16)|AX; +// printf("DIV %08X/%04X\n",templ,tempw); + if (tempw) + { + tempw2=templ%tempw; + DX=tempw2; + templ/=tempw; + AX=templ&0xFFFF; + } + else + { + printf("DIVw BY 0 %04X:%04X\n",cs>>4,cpu_state.pc); + writememw(ss,(SP-2)&0xFFFF,flags|0xF000); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + flags&=~I_FLAG; + flags&=~T_FLAG; + cpu_state.pc=readmemw(0,0); +// printf("F7 30\n"); + loadcs(readmemw(0,2)); + FETCHCLEAR(); + } + cycles-=144; + break; + case 0x38: /*IDIV AX,w*/ + tempws=(int)((DX<<16)|AX); +// printf("IDIV %i %i ",tempws,tempw); + if (tempw) + { + tempw2=tempws%(int)((int16_t)tempw); +// printf("%04X ",tempw2); + DX=tempw2; + tempws/=(int)((int16_t)tempw); + AX=tempws&0xFFFF; + } + else + { + printf("IDIVw BY 0 %04X:%04X\n",cs>>4,cpu_state.pc); + writememw(ss,(SP-2)&0xFFFF,flags|0xF000); + writememw(ss,(SP-4)&0xFFFF,CS); + writememw(ss,(SP-6)&0xFFFF,cpu_state.pc); + SP-=6; + flags&=~I_FLAG; + flags&=~T_FLAG; + cpu_state.pc=readmemw(0,0); +// printf("F7 38\n"); + loadcs(readmemw(0,2)); + FETCHCLEAR(); + } + cycles-=165; + break; + +// default: +// printf("Bad F7 opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + case 0xF8: /*CLC*/ + flags&=~C_FLAG; + cycles-=2; + break; + case 0xF9: /*STC*/ +// printf("STC %04X\n",pc); + flags|=C_FLAG; + cycles-=2; + break; + case 0xFA: /*CLI*/ + flags&=~I_FLAG; +// printf("CLI at %04X:%04X\n",cs>>4,pc); + cycles-=3; + break; + case 0xFB: /*STI*/ + flags|=I_FLAG; +// printf("STI at %04X:%04X\n",cs>>4,pc); + cycles-=2; + break; + case 0xFC: /*CLD*/ + flags&=~D_FLAG; + cycles-=2; + break; + case 0xFD: /*STD*/ + flags|=D_FLAG; + cycles-=2; + break; + + case 0xFE: /*INC/DEC b*/ + fetchea(); + temp=geteab(); + flags&=~V_FLAG; + if (rmdat&0x38) + { + setsub8nc(temp,1); + temp2=temp-1; + if ((temp&0x80) && !(temp2&0x80)) flags|=V_FLAG; + } + else + { + setadd8nc(temp,1); + temp2=temp+1; + if ((temp2&0x80) && !(temp&0x80)) flags|=V_FLAG; + } +// setznp8(temp2); + seteab(temp2); + cycles-=((mod==3)?3:23); + break; + + case 0xFF: + fetchea(); + switch (rmdat&0x38) + { + case 0x00: /*INC w*/ + tempw=geteaw(); + setadd16nc(tempw,1); +// setznp16(tempw+1); + seteaw(tempw+1); + cycles-=((mod==3)?3:23); + break; + case 0x08: /*DEC w*/ + tempw=geteaw(); +// setsub16(tempw,1); + setsub16nc(tempw,1); +// setznp16(tempw-1); + seteaw(tempw-1); +// if (output) printf("DEC - %04X\n",tempw); + cycles-=((mod==3)?3:23); + break; + case 0x10: /*CALL*/ + tempw=geteaw(); + if (ssegs) ss=oldss; + writememw(ss,(SP-2)&0xFFFF,cpu_state.pc); + SP-=2; + cpu_state.pc=tempw; +// printf("FF 10\n"); + cycles-=((mod==3)?20:29); + FETCHCLEAR(); + break; + case 0x18: /*CALL far*/ + tempw=readmemw(easeg,eaaddr); + tempw2=readmemw(easeg,(eaaddr+2)&0xFFFF); //geteaw2(); + tempw3=CS; + tempw4=cpu_state.pc; + if (ssegs) ss=oldss; + cpu_state.pc=tempw; +// printf("FF 18\n"); + loadcs(tempw2); + writememw(ss,(SP-2)&0xFFFF,tempw3); + writememw(ss,((SP-4)&0xFFFF),tempw4); + SP-=4; + cycles-=53; + FETCHCLEAR(); + break; + case 0x20: /*JMP*/ + cpu_state.pc=geteaw(); +// printf("FF 20\n"); + cycles-=((mod==3)?11:18); + FETCHCLEAR(); + break; + case 0x28: /*JMP far*/ + cpu_state.pc=readmemw(easeg,eaaddr); //geteaw(); +// printf("FF 28\n"); + loadcs(readmemw(easeg,(eaaddr+2)&0xFFFF)); //geteaw2(); +// cs=loadcs(CS); +// cs=CS<<4; + cycles-=24; + FETCHCLEAR(); + break; + case 0x30: /*PUSH w*/ + tempw=geteaw(); +// if (output) printf("PUSH %04X %i %02X %04X %04X %02X %02X\n",tempw,rm,rmdat,easeg,eaaddr,ram[0x22340+0x5638],ram[0x22340+0x5639]); + if (ssegs) ss=oldss; + writememw(ss,((SP-2)&0xFFFF),tempw); + SP-=2; + cycles-=((mod==3)?15:24); + break; + +// default: +// printf("Bad FF opcode %02X\n",rmdat&0x38); +// dumpregs(); +// exit(-1); + } + break; + + default: + FETCH(); + cycles-=8; + break; + +/* printf("Bad opcode %02X at %04X:%04X from %04X:%04X %08X\n",opcode,cs>>4,pc,old8>>16,old8&0xFFFF,old82); + dumpregs(); + exit(-1);*/ + } + cpu_state.pc&=0xFFFF; + +/* if ((CS & 0xf000) == 0xa000) + { + dumpregs(); + exit(-1); + }*/ +// output = 3; +/* if (CS == 0xf000) + { + dumpregs(); + exit(-1); + } + output = 3;*/ + if (ssegs) + { + ds=oldds; + ss=oldss; + ssegs=0; + } + +// output = 3; + // if (instime) printf("%i %i %i %i\n",cycdiff,cycles,memcycs,fetchclocks); + FETCHADD(((cycdiff-cycles)-memcycs)-fetchclocks); + if ((cycdiff-cycles) + + +Your application description here. + + + + + + diff --git a/src/acer386sx.c b/src/acer386sx.c new file mode 100644 index 000000000..4b6452583 --- /dev/null +++ b/src/acer386sx.c @@ -0,0 +1,33 @@ +#include "ibm.h" +#include "io.h" +#include "cpu.h" + +#include "acer386sx.h" + +static int acer_index = 0; +static uint8_t acer_regs[256]; + +void acer386sx_write(uint16_t addr, uint8_t val, void *priv) +{ + if (addr & 1) + acer_regs[acer_index] = val; + else + acer_index = val; +} + +uint8_t acer386sx_read(uint16_t addr, void *priv) +{ + if (addr & 1) + { + if ((acer_index >= 0xc0 || acer_index == 0x20) && cpu_iscyrix) + return 0xff; /*Don't conflict with Cyrix config registers*/ + return acer_regs[acer_index]; + } + else + return acer_index; +} + +void acer386sx_init() +{ + io_sethandler(0x0022, 0x0002, acer386sx_read, NULL, NULL, acer386sx_write, NULL, NULL, NULL); +} diff --git a/src/acer386sx.h b/src/acer386sx.h new file mode 100644 index 000000000..729fbf708 --- /dev/null +++ b/src/acer386sx.h @@ -0,0 +1 @@ +void acer386sx_init(); diff --git a/src/acerm3a.c b/src/acerm3a.c new file mode 100644 index 000000000..c9a14f302 --- /dev/null +++ b/src/acerm3a.c @@ -0,0 +1,29 @@ +#include "ibm.h" +#include "io.h" +#include "acerm3a.h" + +static int acerm3a_index; + +static void acerm3a_out(uint16_t port, uint8_t val, void *p) +{ + if (port == 0xea) + acerm3a_index = val; +} + +static uint8_t acerm3a_in(uint16_t port, void *p) +{ + if (port == 0xeb) + { + switch (acerm3a_index) + { + case 2: + return 0xfd; + } + } + return 0xff; +} + +void acerm3a_io_init() +{ + io_sethandler(0x00ea, 0x0002, acerm3a_in, NULL, NULL, acerm3a_out, NULL, NULL, NULL); +} diff --git a/src/acerm3a.h b/src/acerm3a.h new file mode 100644 index 000000000..370d7200f --- /dev/null +++ b/src/acerm3a.h @@ -0,0 +1 @@ +void acerm3a_io_init(); diff --git a/src/ali1429.c b/src/ali1429.c new file mode 100644 index 000000000..29b654b14 --- /dev/null +++ b/src/ali1429.c @@ -0,0 +1,86 @@ +#include +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "cpu.h" + +#include "ali1429.h" + +static int ali1429_index; +static uint8_t ali1429_regs[256]; + +static void ali1429_recalc() +{ + int c; + + for (c = 0; c < 8; c++) + { + uint32_t base = 0xc0000 + (c << 15); + if (ali1429_regs[0x13] & (1 << c)) + { + switch (ali1429_regs[0x14] & 3) + { + case 0: + mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 1: + mem_set_mem_state(base, 0x8000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 2: + mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(base, 0x8000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + } + else + mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + + flushmmucache(); +} + +void ali1429_write(uint16_t port, uint8_t val, void *priv) +{ + int c; + + if (!(port & 1)) + ali1429_index = val; + else + { + ali1429_regs[ali1429_index] = val; +// pclog("ALI1429 write %02X %02X %04X:%04X %i\n",ali1429_index,val,CS,pc,ins); + switch (ali1429_index) + { + case 0x13: + ali1429_recalc(); + break; + case 0x14: + shadowbios = val & 1; + shadowbios_write = val & 2; + ali1429_recalc(); + break; + } + } +} + +uint8_t ali1429_read(uint16_t port, void *priv) +{ + if (!(port & 1)) + return ali1429_index; + if ((ali1429_index >= 0xc0 || ali1429_index == 0x20) && cpu_iscyrix) + return 0xff; /*Don't conflict with Cyrix config registers*/ + return ali1429_regs[ali1429_index]; +} + + +void ali1429_reset() +{ + memset(ali1429_regs, 0xff, 256); +} + +void ali1429_init() +{ + io_sethandler(0x0022, 0x0002, ali1429_read, NULL, NULL, ali1429_write, NULL, NULL, NULL); +} diff --git a/src/ali1429.h b/src/ali1429.h new file mode 100644 index 000000000..5a64f2ec5 --- /dev/null +++ b/src/ali1429.h @@ -0,0 +1 @@ +void ali1429_init(); diff --git a/src/allegro-gui-configure.c b/src/allegro-gui-configure.c new file mode 100644 index 000000000..689284c46 --- /dev/null +++ b/src/allegro-gui-configure.c @@ -0,0 +1,636 @@ +#include "ibm.h" +#include "device.h" +#include "allegro-main.h" +#include "allegro-gui.h" +#include "cpu.h" +#include "fdd.h" +#include "gameport.h" +#include "model.h" +#include "sound.h" +#include "video.h" +#include "vid_voodoo.h" + +static int romstolist[ROM_MAX], listtomodel[ROM_MAX], romstomodel[ROM_MAX], modeltolist[ROM_MAX]; +static int settings_sound_to_list[20], settings_list_to_sound[20]; + +typedef struct allegro_list_t +{ + char name[256]; + int num; +} allegro_list_t; + +static allegro_list_t model_list[ROM_MAX+1]; +static allegro_list_t video_list[GFX_MAX+1]; +static allegro_list_t sound_list[GFX_MAX+1]; +static allegro_list_t cpumanu_list[4]; +static allegro_list_t cpu_list[32]; +static allegro_list_t joystick_list[32]; + +static char mem_size_str[10], mem_size_units[3]; + +static allegro_list_t cache_list[] = +{ + {"A little", 0}, + {"A bit", 1}, + {"Some", 2}, + {"A lot", 3}, + {"Infinite", 4}, + {"", -1} +}; + +static allegro_list_t vidspeed_list[] = +{ + {"8-bit", 0}, + {"Slow 16-bit", 1}, + {"Fast 16-bit", 2}, + {"Slow VLB/PCI", 3}, + {"Mid VLB/PCI", 4}, + {"Fast VLB/PCI", 5}, + {"", -1} +}; + +static allegro_list_t fdd_list[] = +{ + {"None", 0}, + {"5.25\" 360k", 1}, + {"5.25\" 1.2M", 2}, + {"5.25\" 1.2M Dual RPM", 3}, + {"3.5\" 720k", 4}, + {"3.5\" 1.44M", 5}, + {"3.5\" 1.44M 3-Mode", 6}, + {"3.5\" 2.88M", 7}, + {"", -1} +}; + +static void reset_list(); + +static char *list_proc_model(int index, int *list_size) +{ + if (index < 0) + { + int c = 0; + + while (model_list[c].name[0]) + c++; + + *list_size = c; + return NULL; + } + + return model_list[index].name; +} + +static char *list_proc_video(int index, int *list_size) +{ + if (index < 0) + { + int c = 0; + + while (video_list[c].name[0]) + c++; + + *list_size = c; + return NULL; + } + + return video_list[index].name; +} + +static char *list_proc_cache(int index, int *list_size) +{ + if (index < 0) + { + int c = 0; + + while (cache_list[c].name[0]) + c++; + + *list_size = c; + return NULL; + } + + return cache_list[index].name; +} + +static char *list_proc_vidspeed(int index, int *list_size) +{ + if (index < 0) + { + int c = 0; + + while (vidspeed_list[c].name[0]) + c++; + + *list_size = c; + return NULL; + } + + return vidspeed_list[index].name; +} + +static char *list_proc_sound(int index, int *list_size) +{ + if (index < 0) + { + int c = 0; + + while (sound_list[c].name[0]) + c++; + + *list_size = c; + return NULL; + } + + return sound_list[index].name; +} + +static char *list_proc_cpumanu(int index, int *list_size) +{ + if (index < 0) + { + int c = 0; + + while (cpumanu_list[c].name[0]) + c++; + + *list_size = c; + return NULL; + } + + return cpumanu_list[index].name; +} + +static char *list_proc_cpu(int index, int *list_size) +{ + if (index < 0) + { + int c = 0; + + while (cpu_list[c].name[0]) + c++; + + *list_size = c; + return NULL; + } + + return cpu_list[index].name; +} + +static char *list_proc_fdd(int index, int *list_size) +{ + if (index < 0) + { + int c = 0; + + while (fdd_list[c].name[0]) + c++; + + *list_size = c; + return NULL; + } + + return fdd_list[index].name; +} + +static char *list_proc_joystick(int index, int *list_size) +{ + if (index < 0) + { + int c = 0; + + while (joystick_list[c].name[0]) + c++; + + *list_size = c; + return NULL; + } + + return joystick_list[index].name; +} + +static int voodoo_config_proc(int msg, DIALOG *d, int c) +{ + int ret = d_button_proc(msg, d, c); + + if (ret == D_CLOSE) + { + deviceconfig_open(&voodoo_device); + return D_O_K; + } + + return ret; +} + + +static int video_config_proc(int msg, DIALOG *d, int c); +static int sound_config_proc(int msg, DIALOG *d, int c); +static int list_proc(int msg, DIALOG *d, int c); + +static DIALOG configure_dialog[] = +{ + {d_shadow_box_proc, 0, 0, 568,352,0,0xffffff,0,0, 0,0,0,0,0}, // 0 + + {d_button_proc, 226, 328, 50, 16, 0, 0xffffff, 0, D_EXIT, 0, 0, "OK", 0, 0}, // 1 + {d_button_proc, 296, 328, 50, 16, 0, 0xffffff, 0, D_EXIT, 0, 0, "Cancel", 0, 0}, // 2 + + {list_proc, 70*2, 12, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_model, 0, 0}, + + {list_proc, 70*2, 32, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_video, 0, 0}, + + {list_proc, 70*2, 52, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_cpumanu, 0, 0}, //5 + {list_proc, 70*2, 72, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_cpu, 0, 0}, + {d_list_proc, 70*2, 112, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_cache, 0, 0}, + {d_list_proc, 70*2, 132, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_vidspeed, 0, 0}, + {list_proc, 70*2, 152, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_sound, 0, 0}, //9 + + {d_edit_proc, 70*2, 236, 32, 14, 0, 0xffffff, 0, 0, 3, 0, mem_size_str, 0, 0}, + + {d_text_proc, 98*2, 236, 40, 10, 0, 0xffffff, 0, 0, 0, 0, mem_size_units, 0, 0}, + + {d_check_proc, 14*2, 252, 118*2, 10, 0, 0xffffff, 0, 0, 0, 0, "CMS / Game Blaster", 0, 0}, + {d_check_proc, 14*2, 268, 118*2, 10, 0, 0xffffff, 0, 0, 0, 0, "Gravis Ultrasound", 0, 0}, + {d_check_proc, 14*2, 284, 118*2, 10, 0, 0xffffff, 0, 0, 0, 0, "Innovation SSI-2001", 0, 0}, + {d_check_proc, 14*2, 300, 118*2, 10, 0, 0xffffff, 0, 0, 0, 0, "Composite CGA", 0, 0}, + {d_check_proc, 14*2, 316, 118*2, 10, 0, 0xffffff, 0, 0, 0, 0, "Voodoo Graphics", 0, 0}, + + {d_text_proc, 16*2, 16, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "Machine :", 0, 0}, + {d_text_proc, 16*2, 36, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "Video :", 0, 0}, + {d_text_proc, 16*2, 56, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "CPU type :", 0, 0}, + {d_text_proc, 16*2, 76, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "CPU :", 0, 0}, + {d_text_proc, 16*2, 116, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "Cache :", 0, 0}, + {d_text_proc, 16*2, 136, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "Video speed :", 0, 0}, + {d_text_proc, 16*2, 156, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "Soundcard :", 0, 0}, + {d_text_proc, 16*2, 236, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "Memory :", 0, 0}, + + {d_check_proc, 14*2, 92, 118*2, 10, 0, 0xffffff, 0, 0, 0, 0, "Dynamic Recompiler", 0, 0}, + + {d_text_proc, 16*2, 176, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "Drive A: :", 0, 0}, + {d_text_proc, 16*2, 196, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "Drive B: :", 0, 0}, + {d_list_proc, 70*2, 172, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_fdd, 0, 0}, + {d_list_proc, 70*2, 192, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_fdd, 0, 0}, + + {video_config_proc, 452, 32+4, 100, 14, 0, 0xffffff, 0, D_EXIT, 0, 0, "Configure...", 0, 0}, //30 + {sound_config_proc, 452, 152+4, 100, 14, 0, 0xffffff, 0, D_EXIT, 0, 0, "Configure...", 0, 0}, + {voodoo_config_proc, 452, 316, 100, 14, 0, 0xffffff, 0, D_EXIT, 0, 0, "Configure...", 0, 0}, + + {d_text_proc, 16*2, 216, 40, 10, 0, 0xffffff, 0, 0, 0, 0, "Joystick :", 0, 0}, + {d_list_proc, 70*2, 212, 152*2, 20, 0, 0xffffff, 0, 0, 0, 0, list_proc_joystick, 0, 0}, //34 + + {0,0,0,0,0,0,0,0,0,0,0,NULL,NULL,NULL} +}; + +static int list_proc(int msg, DIALOG *d, int c) +{ + int old = d->d1; + int ret = d_list_proc(msg, d, c); + + if (d->d1 != old) + { + int new_model = model_list[configure_dialog[3].d1].num; + int new_cpu_m = configure_dialog[5].d1; + int new_cpu = configure_dialog[6].d1; + int new_dynarec = configure_dialog[25].flags & D_SELECTED; + int new_gfxcard = video_old_to_new(video_list[configure_dialog[4].d1].num); + int new_mem_size; + int cpu_flags; + + reset_list(); + + if (models[new_model].fixed_gfxcard) + configure_dialog[4].flags |= D_DISABLED; + else + configure_dialog[4].flags &= ~D_DISABLED; + + cpu_flags = models[new_model].cpu[new_cpu_m].cpus[new_cpu].cpu_flags; + configure_dialog[25].flags = (((cpu_flags & CPU_SUPPORTS_DYNAREC) && new_dynarec) || (cpu_flags & CPU_REQUIRES_DYNAREC)) ? D_SELECTED : 0; + if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC)) + configure_dialog[25].flags |= D_DISABLED; + + sscanf(mem_size_str, "%i", &new_mem_size); + new_mem_size &= ~(models[new_model].ram_granularity - 1); + if (new_mem_size < models[new_model].min_ram) + new_mem_size = models[new_model].min_ram; + else if (new_mem_size > models[new_model].max_ram) + new_mem_size = models[new_model].max_ram; + sprintf(mem_size_str, "%i", new_mem_size); + + if (models[new_model].is_at) + sprintf(mem_size_units, "MB"); + else + sprintf(mem_size_units, "kB"); + + if (!video_card_has_config(new_gfxcard)) + configure_dialog[30].flags |= D_DISABLED; + else + configure_dialog[30].flags &= ~D_DISABLED; + + if (!sound_card_has_config(configure_dialog[9].d1)) + configure_dialog[31].flags |= D_DISABLED; + else + configure_dialog[31].flags &= ~D_DISABLED; + + return D_REDRAW; + } + + return ret; +} + +static int video_config_proc(int msg, DIALOG *d, int c) +{ + int ret = d_button_proc(msg, d, c); + + if (ret == D_CLOSE) + { + int new_gfxcard = video_old_to_new(video_list[configure_dialog[4].d1].num); + + deviceconfig_open(video_card_getdevice(new_gfxcard)); + return D_O_K; + } + + return ret; +} +static int sound_config_proc(int msg, DIALOG *d, int c) +{ + int ret = d_button_proc(msg, d, c); + + if (ret == D_CLOSE) + { + int new_sndcard = sound_list[configure_dialog[9].d1].num; + + deviceconfig_open(sound_card_getdevice(new_sndcard)); + return D_O_K; + } + + return ret; +} + +static void reset_list() +{ + int model = model_list[configure_dialog[3].d1].num; + int cpumanu = configure_dialog[5].d1; + int cpu = configure_dialog[6].d1; + int c; + + memset(cpumanu_list, 0, sizeof(cpumanu_list)); + memset(cpu_list, 0, sizeof(cpu_list)); + + c = 0; + while (models[model].cpu[c].cpus != NULL && c < 3) + { + strcpy(cpumanu_list[c].name, models[model].cpu[c].name); + cpumanu_list[c].num = c; + c++; + } + + if (cpumanu >= c) + cpumanu = configure_dialog[6].d1 = c-1; + + c = 0; + while (models[model].cpu[cpumanu].cpus[c].cpu_type != -1) + { + strcpy(cpu_list[c].name, models[model].cpu[cpumanu].cpus[c].name); + cpu_list[c].num = c; + c++; + } + + if (cpu >= c) + cpu = configure_dialog[7].d1 = c-1; +} + +int settings_configure() +{ + int c, d; + int cpu_flags; + + memset(model_list, 0, sizeof(model_list)); + memset(video_list, 0, sizeof(video_list)); + memset(sound_list, 0, sizeof(sound_list)); + + for (c = 0; c < ROM_MAX; c++) + romstolist[c] = 0; + c = d = 0; + while (models[c].id != -1) + { + pclog("INITDIALOG : %i %i %i\n",c,models[c].id,romspresent[models[c].id]); + if (romspresent[models[c].id]) + { + strcpy(model_list[d].name, models[c].name); + model_list[d].num = c; + if (c == model) + configure_dialog[3].d1 = d; + d++; + } + c++; + } + + if (models[model].fixed_gfxcard) + configure_dialog[4].flags |= D_DISABLED; + else + configure_dialog[4].flags &= ~D_DISABLED; + + c = d = 0; + while (1) + { + char *s = video_card_getname(c); + + if (!s[0]) + break; +pclog("video_card_available : %i\n", c); + if (video_card_available(c)) + { + strcpy(video_list[d].name, video_card_getname(c)); + video_list[d].num = video_new_to_old(c); + if (video_new_to_old(c) == gfxcard) + configure_dialog[4].d1 = d; + d++; + } + + c++; + } + + if (!video_card_has_config(video_old_to_new(gfxcard))) + configure_dialog[30].flags |= D_DISABLED; + else + configure_dialog[30].flags &= ~D_DISABLED; + + c = d = 0; + while (1) + { + char *s = sound_card_getname(c); + + if (!s[0]) + break; + + if (sound_card_available(c)) + { + strcpy(sound_list[d].name, sound_card_getname(c)); + sound_list[d].num = c; + if (c == sound_card_current) + configure_dialog[9].d1 = d; + d++; + } + + c++; + } + + c = 0; + while (joystick_get_name(c)) + { + strcpy(joystick_list[c].name, joystick_get_name(c)); + if (c == joystick_type) + configure_dialog[34].d1 = c; + + c++; + } + + if (!sound_card_has_config(configure_dialog[9].d1)) + configure_dialog[31].flags |= D_DISABLED; + else + configure_dialog[31].flags &= ~D_DISABLED; + + configure_dialog[5].d1 = cpu_manufacturer; + configure_dialog[6].d1 = cpu; + configure_dialog[7].d1 = cache; + configure_dialog[8].d1 = video_speed; + reset_list(); +// strcpy(cpumanu_str, models[romstomodel[romset]].cpu[cpu_manufacturer].name); +// strcpy(cpu_str, models[romstomodel[romset]].cpu[cpu_manufacturer].cpus[cpu].name); +// strcpy(cache_str, cache_str_list[cache]); +// strcpy(vidspeed_str, vidspeed_str_list[video_speed]); + +// strcpy(soundcard_str, sound_card_getname(sound_card_current)); + + if (GAMEBLASTER) + configure_dialog[12].flags |= D_SELECTED; + else + configure_dialog[12].flags &= ~D_SELECTED; + + if (GUS) + configure_dialog[13].flags |= D_SELECTED; + else + configure_dialog[13].flags &= ~D_SELECTED; + + if (SSI2001) + configure_dialog[14].flags |= D_SELECTED; + else + configure_dialog[14].flags &= ~D_SELECTED; + + if (cga_comp) + configure_dialog[15].flags |= D_SELECTED; + else + configure_dialog[15].flags &= ~D_SELECTED; + + if (voodoo_enabled) + configure_dialog[16].flags |= D_SELECTED; + else + configure_dialog[16].flags &= ~D_SELECTED; + + if (models[model].is_at) + sprintf(mem_size_str, "%i", mem_size / 1024); + else + sprintf(mem_size_str, "%i", mem_size); + + if (models[model].is_at) + sprintf(mem_size_units, "MB"); + else + sprintf(mem_size_units, "kB"); + + cpu_flags = models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_flags; + configure_dialog[25].flags = (((cpu_flags & CPU_SUPPORTS_DYNAREC) && cpu_use_dynarec) || (cpu_flags & CPU_REQUIRES_DYNAREC)) ? D_SELECTED : 0; + if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC)) + configure_dialog[25].flags |= D_DISABLED; + + configure_dialog[28].d1 = fdd_get_type(0); + configure_dialog[29].d1 = fdd_get_type(1); + + while (1) + { + position_dialog(configure_dialog, SCREEN_W/2 - configure_dialog[0].w/2, SCREEN_H/2 - configure_dialog[0].h/2); + + c = popup_dialog(configure_dialog, 1); + + position_dialog(configure_dialog, -(SCREEN_W/2 - configure_dialog[0].w/2), -(SCREEN_H/2 - configure_dialog[0].h/2)); + + if (c == 1) + { + int new_model = model_list[configure_dialog[3].d1].num; + int new_gfxcard = video_list[configure_dialog[4].d1].num; + int new_sndcard = sound_list[configure_dialog[9].d1].num; + int new_cpu_m = configure_dialog[5].d1; + int new_cpu = configure_dialog[6].d1; + int new_mem_size; + int new_has_fpu = (models[new_model].cpu[new_cpu_m].cpus[new_cpu].cpu_type >= CPU_i486DX) ? 1 : 0; + int new_GAMEBLASTER = (configure_dialog[12].flags & D_SELECTED) ? 1 : 0; + int new_GUS = (configure_dialog[13].flags & D_SELECTED) ? 1 : 0; + int new_SSI2001 = (configure_dialog[14].flags & D_SELECTED) ? 1 : 0; + int new_voodoo = (configure_dialog[16].flags & D_SELECTED) ? 1 : 0; + int new_dynarec = (configure_dialog[25].flags & D_SELECTED) ? 1 : 0; + int new_fda = configure_dialog[28].d1; + int new_fdb = configure_dialog[29].d1; + + sscanf(mem_size_str, "%i", &new_mem_size); + new_mem_size &= ~(models[new_model].ram_granularity - 1); + if (new_mem_size < models[new_model].min_ram) + new_mem_size = models[new_model].min_ram; + else if (new_mem_size > models[new_model].max_ram) + new_mem_size = models[new_model].max_ram; + if (models[new_model].is_at) + new_mem_size *= 1024; + + if (new_model != model || new_gfxcard != gfxcard || new_mem_size != mem_size || + new_has_fpu != hasfpu || new_GAMEBLASTER != GAMEBLASTER || new_GUS != GUS || + new_SSI2001 != SSI2001 || new_sndcard != sound_card_current || new_voodoo != voodoo_enabled || + new_dynarec != cpu_use_dynarec || new_fda != fdd_get_type(0) || new_fdb != fdd_get_type(1)) + { + if (alert("This will reset PCem!", "Okay to continue?", NULL, "OK", "Cancel", 0, 0) != 1) + continue; + + model = new_model; + romset = model_getromset(); + gfxcard = new_gfxcard; + mem_size = new_mem_size; + cpu_manufacturer = new_cpu_m; + cpu = new_cpu; + GAMEBLASTER = new_GAMEBLASTER; + GUS = new_GUS; + SSI2001 = new_SSI2001; + sound_card_current = new_sndcard; + voodoo_enabled = new_voodoo; + cpu_use_dynarec = new_dynarec; + + mem_resize(); + loadbios(); + resetpchard(); + + fdd_set_type(0, new_fda); + fdd_set_type(1, new_fdb); + } + + video_speed = configure_dialog[8].d1; + + cga_comp = (configure_dialog[15].flags & D_SELECTED) ? 1 : 0; + + cpu_manufacturer = new_cpu_m; + cpu = new_cpu; + cpu_set(); + + cache = configure_dialog[7].d1; + mem_updatecache(); + + joystick_type = configure_dialog[34].d1; + gameport_update_joystick_type(); + + saveconfig(); + + speedchanged(); + + return D_O_K; + } + + if (c == 2) + return D_O_K; + } + + return D_O_K; +} + diff --git a/src/allegro-gui-deviceconfig.c b/src/allegro-gui-deviceconfig.c new file mode 100644 index 000000000..cc87058db --- /dev/null +++ b/src/allegro-gui-deviceconfig.c @@ -0,0 +1,303 @@ +#include "ibm.h" +#include "device.h" +#include "allegro-main.h" +#include "allegro-gui.h" +#include "config.h" + +static device_t *config_device; + +#define MAX_CONFIG_SIZE 64 +#define MAX_CONFIG_SELECTIONS 8 + +static device_config_selection_t *config_selections[MAX_CONFIG_SELECTIONS]; + +#define list_proc_device_func(i) \ + static char *list_proc_device_ ## i(int index, int *list_size) \ + { \ + device_config_selection_t *config = config_selections[i]; \ + \ + if (index < 0) \ + { \ + int c = 0; \ + \ + while (config[c].description[0]) \ + c++; \ + \ + *list_size = c; \ + return NULL; \ + } \ + \ + return config[index].description; \ + } + +list_proc_device_func(0) +list_proc_device_func(1) +list_proc_device_func(2) +list_proc_device_func(3) +list_proc_device_func(4) +list_proc_device_func(5) +list_proc_device_func(6) +list_proc_device_func(7) + +static DIALOG deviceconfig_dialog[MAX_CONFIG_SIZE] = +{ + {d_shadow_box_proc, 0, 0, 568,332,0,0xffffff,0,0, 0,0,0,0,0} // 0 +}; + +void deviceconfig_open(device_t *device) +{ + DIALOG *d; + device_config_t *config = device->config; + int y = 10; + int dialog_pos = 1; + int list_pos = 0; + int c; + int id_ok, id_cancel; + + memset((void *)((uintptr_t)deviceconfig_dialog) + sizeof(DIALOG), 0, sizeof(deviceconfig_dialog) - sizeof(DIALOG)); + deviceconfig_dialog[0].x = deviceconfig_dialog[0].y = 0; + + while (config->type != -1) + { + d = &deviceconfig_dialog[dialog_pos]; + + switch (config->type) + { + case CONFIG_BINARY: + d->x = 32; + d->y = y; + + d->w = 118*2; + d->h = 15; + + d->dp = config->description; + d->proc = d_check_proc; + + d->flags = config_get_int(device->name, config->name, config->default_int) ? D_SELECTED : 0; + d->bg = 0xffffff; + d->fg = 0; + + dialog_pos++; + + y += 20; + break; + + case CONFIG_SELECTION: + if (list_pos >= MAX_CONFIG_SELECTIONS) + break; + + d->x = 32; + d->y = y; + + d->w = 80; + d->h = 15; + + d->dp = config->description; + d->proc = d_text_proc; + + d->flags = 0; + d->bg = 0xffffff; + d->fg = 0; + + d++; + + d->x = 250; + d->y = y; + + d->w = 304; + d->h = 20; + + switch (list_pos) + { + case 0 : d->dp = list_proc_device_0; break; + case 1 : d->dp = list_proc_device_1; break; + case 2 : d->dp = list_proc_device_2; break; + case 3 : d->dp = list_proc_device_3; break; + case 4 : d->dp = list_proc_device_4; break; + case 5 : d->dp = list_proc_device_5; break; + case 6 : d->dp = list_proc_device_6; break; + case 7 : d->dp = list_proc_device_7; break; + } + d->proc = d_list_proc; + + d->flags = 0; + d->bg = 0xffffff; + d->fg = 0; + + config_selections[list_pos++] = config->selection; + + c = 0; + while (config->selection[c].description[0]) + { + if (config_get_int(device->name, config->name, config->default_int) == config->selection[c].value) + d->d1 = c; + c++; + } + + dialog_pos += 2; + + y += 20; + break; + + case CONFIG_MIDI: + break; + } + + config++; + + if (dialog_pos >= MAX_CONFIG_SIZE-3) + break; + } + + d = &deviceconfig_dialog[dialog_pos]; + + id_ok = dialog_pos; + id_cancel = dialog_pos + 1; + + d->x = 226; + d->y = y+8; + + d->w = 50; + d->h = 16; + + d->dp = "OK"; + d->proc = d_button_proc; + + d->flags = D_EXIT; + d->bg = 0xffffff; + d->fg = 0; + + d++; + + d->x = 296; + d->y = y+8; + + d->w = 50; + d->h = 16; + + d->dp = "Cancel"; + d->proc = d_button_proc; + + d->flags = D_EXIT; + d->bg = 0xffffff; + d->fg = 0; + + deviceconfig_dialog[0].h = y + 28; + + config_device = device; + + while (1) + { + position_dialog(deviceconfig_dialog, SCREEN_W/2 - deviceconfig_dialog[0].w/2, SCREEN_H/2 - deviceconfig_dialog[0].h/2); + + c = popup_dialog(deviceconfig_dialog, 1); + + position_dialog(deviceconfig_dialog, -(SCREEN_W/2 - deviceconfig_dialog[0].w/2), -(SCREEN_H/2 - deviceconfig_dialog[0].h/2)); + + if (c == id_ok) + { + int changed = 0; + + dialog_pos = 1; + config = device->config; + + while (config->type != -1) + { + int val; + + d = &deviceconfig_dialog[dialog_pos]; + + switch (config->type) + { + case CONFIG_BINARY: + val = (d->flags & D_SELECTED) ? 1 : 0; + + if (val != config_get_int(device->name, config->name, config->default_int)) + changed = 1; + + dialog_pos++; + break; + + case CONFIG_SELECTION: + if (list_pos >= MAX_CONFIG_SELECTIONS) + break; + + d++; + + val = config->selection[d->d1].value; + + if (val != config_get_int(device->name, config->name, config->default_int)) + changed = 1; + + dialog_pos += 2; + break; + + case CONFIG_MIDI: + break; + } + + config++; + + if (dialog_pos >= MAX_CONFIG_SIZE-3) + break; + } + + if (!changed) + return; + + if (alert("This will reset PCem!", "Okay to continue?", NULL, "OK", "Cancel", 0, 0) != 1) + continue; + + dialog_pos = 1; + config = device->config; + + while (config->type != -1) + { + int val; + + d = &deviceconfig_dialog[dialog_pos]; + + switch (config->type) + { + case CONFIG_BINARY: + val = (d->flags & D_SELECTED) ? 1 : 0; + + config_set_int(config_device->name, config->name, val); + + dialog_pos++; + break; + + case CONFIG_SELECTION: + if (list_pos >= MAX_CONFIG_SELECTIONS) + break; + + d++; + + val = config->selection[d->d1].value; + + config_set_int(config_device->name, config->name, val); + + dialog_pos += 2; + break; + + case CONFIG_MIDI: + break; + } + + config++; + + if (dialog_pos >= MAX_CONFIG_SIZE-3) + break; + } + + saveconfig(); + + resetpchard(); + + return; + } + + if (c == id_cancel) + break; + } +} diff --git a/src/allegro-gui-hdconf.c b/src/allegro-gui-hdconf.c new file mode 100644 index 000000000..1dcf2aa1f --- /dev/null +++ b/src/allegro-gui-hdconf.c @@ -0,0 +1,513 @@ +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#define _GNU_SOURCE + +#include +#include "ibm.h" +#include "device.h" +#include "ide.h" +#include "allegro-main.h" +#include "allegro-gui.h" + +static char hd_path[4][260]; +static char hd_sectors[4][10]; +static char hd_heads[4][10]; +static char hd_cylinders[4][10]; +static char hd_size[4][20]; + +static char hd_path_new[260]; +static char hd_sectors_new[10]; +static char hd_heads_new[10]; +static char hd_cylinders_new[10]; +static char hd_size_new[20]; + +static int new_cdrom_channel; + +static PcemHDC hdc_new[4]; + +static DIALOG hdparams_dialog[]= +{ + {d_shadow_box_proc, 0, 0, 194*2,86,0,0xffffff,0,0, 0,0,0,0,0}, // 0 + + {d_button_proc, 126, 66, 50, 14, 0, 0xffffff, 0, D_EXIT, 0, 0, "OK", 0, 0}, // 1 + {d_button_proc, 196, 66, 50, 16, 0, 0xffffff, 0, D_EXIT, 0, 0, "Cancel", 0, 0}, // 2 + + {d_text_proc, 7*2, 6, 170, 10, 0, 0xffffff, 0, 0, 0, 0, "Initial settings are based on file size", 0, 0}, + + {d_text_proc, 7*2, 22, 27, 10, 0, 0xffffff, 0, 0, 0, 0, "Sectors:", 0, 0}, + {d_text_proc, 63*2, 22, 29, 8, 0, 0xffffff, 0, 0, 0, 0, "Heads:", 0, 0}, + {d_text_proc, 120*2, 22, 28, 12, 0, 0xffffff, 0, 0, 0, 0, "Cylinders:", 0, 0}, + {d_edit_proc, 44*2, 22, 16*2, 12, 0, 0xffffff, 0, 0, 2, 0, hd_sectors_new, 0, 0}, + {d_edit_proc, 92*2, 22, 16*2, 12, 0, 0xffffff, 0, 0, 3, 0, hd_heads_new, 0, 0}, + {d_edit_proc, 168*2, 22, 24*2, 12, 0, 0xffffff, 0, 0, 5, 0, hd_cylinders_new, 0, 0}, + {d_text_proc, 7*2, 54, 136, 12, 0, 0xffffff, 0, 0, 0, 0, hd_size_new, 0, 0}, + + {0,0,0,0,0,0,0,0,0,0,0,NULL,NULL,NULL} +}; + +static int hdconf_open(int msg, DIALOG *d, int c) +{ + int drv = d->d2; + int ret = d_button_proc(msg, d, c); + + if (ret == D_EXIT) + { + char fn[260]; + int xsize = SCREEN_W - 32, ysize = SCREEN_H - 64; + + strcpy(fn, hd_path[drv]); + ret = file_select_ex("Please choose a disc image", fn, "IMG", 260, xsize, ysize); + if (ret) + { + uint64_t sz; + FILE *f = fopen64(fn, "rb"); + if (!f) + { + return D_REDRAW; + } + fseeko64(f, -1, SEEK_END); + sz = ftello64(f) + 1; + fclose(f); + sprintf(hd_sectors_new, "63"); + sprintf(hd_heads_new, "16"); + sprintf(hd_cylinders_new, "%i", (int)((sz / 512) / 16) / 63); + + while (1) + { + position_dialog(hdparams_dialog, SCREEN_W/2 - 186, SCREEN_H/2 - 86/2); + + ret = popup_dialog(hdparams_dialog, 1); + + position_dialog(hdparams_dialog, -(SCREEN_W/2 - 186), -(SCREEN_H/2 - 86/2)); + + if (ret == 1) + { + int spt, hpc, cyl; + sscanf(hd_sectors_new, "%i", &spt); + sscanf(hd_heads_new, "%i", &hpc); + sscanf(hd_cylinders_new, "%i", &cyl); + + if (spt > 63) + { + alert("Drive has too many sectors (maximum is 63)", NULL, NULL, "OK", NULL, 0, 0); + continue; + } + if (hpc > 128) + { + alert("Drive has too many heads (maximum is 128)", NULL, NULL, "OK", NULL, 0, 0); + continue; + } + if (cyl > 16383) + { + alert("Drive has too many cylinders (maximum is 16383)", NULL, NULL, "OK", NULL, 0, 0); + continue; + } + + hdc_new[drv].spt = spt; + hdc_new[drv].hpc = hpc; + hdc_new[drv].tracks = cyl; + + strcpy(hd_path[drv], fn); + sprintf(hd_sectors[drv], "%i", hdc_new[drv].spt); + sprintf(hd_heads[drv], "%i", hdc_new[drv].hpc); + sprintf(hd_cylinders[drv], "%i", hdc_new[drv].tracks); + sprintf(hd_size[drv], "Size : %imb", (((((uint64_t)hdc_new[drv].tracks*(uint64_t)hdc_new[drv].hpc)*(uint64_t)hdc_new[drv].spt)*512)/1024)/1024); + + return D_REDRAW; + } + + if (ret == 2) + break; + } + } + + return D_REDRAW; + } + + return ret; +} + +static int hdconf_new_file(int msg, DIALOG *d, int c) +{ + int ret = d_button_proc(msg, d, c); + + if (ret == D_EXIT) + { + char fn[260]; + int xsize = SCREEN_W - 32, ysize = SCREEN_H - 64; + + strcpy(fn, hd_path_new); + ret = file_select_ex("Please choose a disc image", fn, "IMG", 260, xsize, ysize); + if (ret) + strcpy(hd_path_new, fn); + + return D_REDRAW; + } + + return ret; +} + +static DIALOG hdnew_dialog[]= +{ + {d_shadow_box_proc, 0, 0, 194*2,86,0,0xffffff,0,0, 0,0,0,0,0}, // 0 + + {d_button_proc, 126, 66, 50, 14, 0, 0xffffff, 0, D_EXIT, 0, 0, "OK", 0, 0}, // 1 + {d_button_proc, 196, 66, 50, 16, 0, 0xffffff, 0, D_EXIT, 0, 0, "Cancel", 0, 0}, // 2 + + {d_edit_proc, 7*2, 6, 136*2, 10, 0, 0xffffff, 0, 0, 0, 0, hd_path_new, 0, 0}, + {hdconf_new_file, 143*2, 6, 16*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 0, "...", 0, 0}, + + {d_text_proc, 7*2, 22, 27, 10, 0, 0xffffff, 0, 0, 0, 0, "Sectors:", 0, 0}, + {d_text_proc, 63*2, 22, 29, 8, 0, 0xffffff, 0, 0, 0, 0, "Heads:", 0, 0}, + {d_text_proc, 120*2, 22, 28, 12, 0, 0xffffff, 0, 0, 0, 0, "Cylinders:", 0, 0}, + {d_edit_proc, 44*2, 22, 16*2, 12, 0, 0xffffff, 0, 0, 2, 0, hd_sectors_new, 0, 0}, + {d_edit_proc, 92*2, 22, 16*2, 12, 0, 0xffffff, 0, 0, 3, 0, hd_heads_new, 0, 0}, + {d_edit_proc, 168*2, 22, 24*2, 12, 0, 0xffffff, 0, 0, 5, 0, hd_cylinders_new, 0, 0}, +// {d_text_proc, 7*2, 54, 136, 12, 0, -1, 0, 0, 0, 0, hd_size_new, 0, 0}, + + {0,0,0,0,0,0,0,0,0,0,0,NULL,NULL,NULL} +}; + +static int create_hd(char *fn, int cyl, int hpc, int spt) +{ + int c; + int e; + uint8_t buf[512]; + FILE *f = fopen64(hd_path_new, "wb"); + e = errno; + if (!f) + { + alert("Can't open file for write", NULL, NULL, "OK", NULL, 0, 0); + return -1; + } + memset(buf, 0, 512); + for (c = 0; c < (cyl * hpc * spt); c++) + { + fwrite(buf, 512, 1, f); + } + fclose(f); +} + +static int hdconf_new(int msg, DIALOG *d, int c) +{ + int drv = d->d2; + int ret = d_button_proc(msg, d, c); + + if (ret == D_EXIT) + { + sprintf(hd_sectors_new, "63"); + sprintf(hd_heads_new, "16"); + sprintf(hd_cylinders_new, "511"); + strcpy(hd_path_new, ""); + + while (1) + { + position_dialog(hdnew_dialog, SCREEN_W/2 - 186, SCREEN_H/2 - 86/2); + + ret = popup_dialog(hdnew_dialog, 1); + + position_dialog(hdnew_dialog, -(SCREEN_W/2 - 186), -(SCREEN_H/2 - 86/2)); + + if (ret == 1) + { + int spt, hpc, cyl; + int c, d; + FILE *f; + uint8_t *buf; + + sscanf(hd_sectors_new, "%i", &spt); + sscanf(hd_heads_new, "%i", &hpc); + sscanf(hd_cylinders_new, "%i", &cyl); + + if (spt > 63) + { + alert("Drive has too many sectors (maximum is 63)", NULL, NULL, "OK", NULL, 0, 0); + continue; + } + if (hpc > 128) + { + alert("Drive has too many heads (maximum is 128)", NULL, NULL, "OK", NULL, 0, 0); + continue; + } + if (cyl > 16383) + { + alert("Drive has too many cylinders (maximum is 16383)", NULL, NULL, "OK", NULL, 0, 0); + continue; + } + if (create_hd(hd_path_new, cyl, hpc, spt)) + return D_REDRAW; + + alert("Remember to partition and format the new drive", NULL, NULL, "OK", NULL, 0, 0); + + hdc_new[drv].spt = spt; + hdc_new[drv].hpc = hpc; + hdc_new[drv].tracks = cyl; + + strcpy(hd_path[drv], hd_path_new); + sprintf(hd_sectors[drv], "%i", hdc_new[drv].spt); + sprintf(hd_heads[drv], "%i", hdc_new[drv].hpc); + sprintf(hd_cylinders[drv], "%i", hdc_new[drv].tracks); + sprintf(hd_size[drv], "Size : %imb", (((((uint64_t)hdc_new[drv].tracks*(uint64_t)hdc_new[drv].hpc)*(uint64_t)hdc_new[drv].spt)*512)/1024)/1024); + + return D_REDRAW; + } + + if (ret == 2) + break; + } + + return D_REDRAW; + } + + return ret; +} + +static int hdconf_eject(int msg, DIALOG *d, int c) +{ + int drv = d->d2; + int ret = d_button_proc(msg, d, c); + + if (ret == D_EXIT) + { + hdc_new[drv].spt = 0; + hdc_new[drv].hpc = 0; + hdc_new[drv].tracks = 0; + strcpy(hd_path[drv], ""); + sprintf(hd_sectors[drv], "%i", hdc_new[drv].spt); + sprintf(hd_heads[drv], "%i", hdc_new[drv].hpc); + sprintf(hd_cylinders[drv], "%i", hdc_new[drv].tracks); + sprintf(hd_size[drv], "Size : %imb", (((((uint64_t)hdc_new[drv].tracks*(uint64_t)hdc_new[drv].hpc)*(uint64_t)hdc_new[drv].spt)*512)/1024)/1024); + + return D_REDRAW; + } + + return ret; +} + +static int hdconf_radio_hd(int msg, DIALOG *d, int c); +static int hdconf_radio_cd(int msg, DIALOG *d, int c); + +static DIALOG hdconf_dialog[]= +{ + {d_shadow_box_proc, 0, 0, 210*2,354,0,0xffffff,0,0, 0,0,0,0,0}, // 0 + + {d_button_proc, 150, 334, 50, 16, 0, 0xffffff, 0, D_EXIT, 0, 0, "OK", 0, 0}, // 1 + {d_button_proc, 220, 334, 50, 16, 0, 0xffffff, 0, D_EXIT, 0, 0, "Cancel", 0, 0}, // 2 + + {d_text_proc, 7*2, 6, 27, 10, 0, 0xffffff, 0, 0, 0, 0, "C:", 0, 0}, + {hdconf_radio_hd, 7*2, 22, 96, 12, 0, 0xffffff, 0, D_EXIT, 0, 0, "Hard drive", 0, 0}, // 4 + {hdconf_radio_cd, 100*2, 22, 64, 12, 0, 0xffffff, 0, D_EXIT, 0, 0, "CD-ROM", 0, 0}, // 5 + {d_edit_proc, 7*2, 38, 136*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_path[0], 0, 0}, + {hdconf_open, 143*2, 38, 16*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 0, "...", 0, 0}, + {hdconf_new, 159*2, 38, 24*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 0, "New", 0, 0}, + {hdconf_eject, 183*2, 38, 24*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 0, "Eject", 0, 0}, + + {d_text_proc, 7*2, 54, 27, 10, 0, 0xffffff, 0, 0, 0, 0, "Sectors:", 0, 0}, + {d_text_proc, 63*2, 54, 29, 8, 0, 0xffffff, 0, 0, 0, 0, "Heads:", 0, 0}, + {d_text_proc, 120*2, 54, 28, 12, 0, 0xffffff, 0, 0, 0, 0, "Cylinders:", 0, 0}, + {d_edit_proc, 44*2, 54, 16*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_sectors[0], 0, 0}, + {d_edit_proc, 92*2, 54, 16*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_heads[0], 0, 0}, + {d_edit_proc, 168*2, 54, 24*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_cylinders[0], 0, 0}, + {d_text_proc, 7*2, 54, 136, 12, 0, 0xffffff, 0, 0, 0, 0, hd_size[0], 0, 0}, + + {d_text_proc, 7*2, 76, 27, 10, 0, 0xffffff, 0, 0, 0, 0, "D:", 0, 0}, + {hdconf_radio_hd, 7*2, 92, 96, 12, 0, 0xffffff, 0, D_EXIT, 1, 0, "Hard drive", 0, 0}, // 18 + {hdconf_radio_cd, 100*2, 92, 64, 12, 0, 0xffffff, 0, D_EXIT, 1, 0, "CD-ROM", 0, 0}, // 19 + {d_edit_proc, 7*2, 108, 136*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_path[1], 0, 0}, + {hdconf_open, 143*2, 108, 16*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 1, "...", 0, 0}, + {hdconf_new, 159*2, 108, 24*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 1, "New", 0, 0}, + {hdconf_eject, 183*2, 108, 24*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 1, "Eject", 0, 0}, + + {d_edit_proc, 44*2, 124, 16*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_sectors[1], 0, 0}, + {d_edit_proc, 92*2, 124, 16*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_heads[1], 0, 0}, + {d_edit_proc, 168*2, 124, 24*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_cylinders[1], 0, 0}, + {d_text_proc, 7*2, 124, 27, 10, 0, 0xffffff, 0, 0, 0, 0, "Sectors:", 0, 0}, + {d_text_proc, 63*2, 124, 29, 8, 0, 0xffffff, 0, 0, 0, 0, "Heads:", 0, 0}, + {d_text_proc, 120*2, 124, 32, 12, 0, 0xffffff, 0, 0, 0, 0, "Cylinders:", 0, 0}, + {d_text_proc, 7*2, 140, 136, 12, 0, 0xffffff, 0, 0, 0, 0, hd_size[1], 0, 0}, + + {d_text_proc, 7*2, 162, 27, 10, 0, 0xffffff, 0, 0, 0, 0, "E:", 0, 0}, + {hdconf_radio_hd, 7*2, 178, 96, 12, 0, 0xffffff, 0, D_EXIT, 2, 0, "Hard drive", 0, 0}, // 32 + {hdconf_radio_cd, 100*2, 178, 64, 12, 0, 0xffffff, 0, D_EXIT, 2, 0, "CD-ROM", 0, 0}, // 33 + {d_edit_proc, 7*2, 194, 136*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_path[2], 0, 0}, + {hdconf_open, 143*2, 194, 16*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 2, "...", 0, 0}, + {hdconf_new, 159*2, 194, 24*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 2, "New", 0, 0}, + {hdconf_eject, 183*2, 194, 24*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 2, "Eject", 0, 0}, + + {d_edit_proc, 44*2, 210, 16*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_sectors[2], 0, 0}, + {d_edit_proc, 92*2, 210, 16*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_heads[2], 0, 0}, + {d_edit_proc, 168*2, 210, 24*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_cylinders[2], 0, 0}, + {d_text_proc, 7*2, 210, 27, 10, 0, 0xffffff, 0, 0, 0, 0, "Sectors:", 0, 0}, + {d_text_proc, 63*2, 210, 29, 8, 0, 0xffffff, 0, 0, 0, 0, "Heads:", 0, 0}, + {d_text_proc, 120*2, 210, 32, 12, 0, 0xffffff, 0, 0, 0, 0, "Cylinders:", 0, 0}, + {d_text_proc, 7*2, 226, 136, 12, 0, 0xffffff, 0, 0, 0, 0, hd_size[2], 0, 0}, + + {d_text_proc, 7*2, 248, 27, 10, 0, 0xffffff, 0, 0, 0, 0, "F:", 0, 0}, + {hdconf_radio_hd, 7*2, 264, 96, 12, 0, 0xffffff, 0, D_EXIT, 3, 0, "Hard drive", 0, 0}, // 46 + {hdconf_radio_cd, 100*2, 264, 64, 12, 0, 0xffffff, 0, D_EXIT, 3, 0, "CD-ROM", 0, 0}, // 47 + {d_edit_proc, 7*2, 280, 136*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_path[3], 0, 0}, + {hdconf_open, 143*2, 280, 16*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 3, "...", 0, 0}, + {hdconf_new, 159*2, 280, 24*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 3, "New", 0, 0}, + {hdconf_eject, 183*2, 280, 24*2, 14, 0, 0xffffff, 0, D_EXIT, 0, 3, "Eject", 0, 0}, + + {d_edit_proc, 44*2, 296, 16*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_sectors[3], 0, 0}, + {d_edit_proc, 92*2, 296, 16*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_heads[3], 0, 0}, + {d_edit_proc, 168*2, 296, 24*2, 12, 0, 0xffffff, 0, D_DISABLED, 0, 0, hd_cylinders[3], 0, 0}, + {d_text_proc, 7*2, 296, 27, 10, 0, 0xffffff, 0, 0, 0, 0, "Sectors:", 0, 0}, + {d_text_proc, 63*2, 296, 29, 8, 0, 0xffffff, 0, 0, 0, 0, "Heads:", 0, 0}, + {d_text_proc, 120*2, 296, 32, 12, 0, 0xffffff, 0, 0, 0, 0, "Cylinders:", 0, 0}, + {d_text_proc, 7*2, 312, 136, 12, 0, 0xffffff, 0, 0, 0, 0, hd_size[3], 0, 0}, + + {0,0,0,0,0,0,0,0,0,0,0,NULL,NULL,NULL} +}; + +static void update_hdd_cdrom() +{ + if (new_cdrom_channel == 0) + { + hdconf_dialog[4].flags &= ~D_SELECTED; + hdconf_dialog[5].flags |= D_SELECTED; + } + else + { + hdconf_dialog[4].flags |= D_SELECTED; + hdconf_dialog[5].flags &= ~D_SELECTED; + } + if (new_cdrom_channel == 1) + { + hdconf_dialog[18].flags &= ~D_SELECTED; + hdconf_dialog[19].flags |= D_SELECTED; + } + else + { + hdconf_dialog[18].flags |= D_SELECTED; + hdconf_dialog[19].flags &= ~D_SELECTED; + } + if (new_cdrom_channel == 2) + { + hdconf_dialog[32].flags &= ~D_SELECTED; + hdconf_dialog[33].flags |= D_SELECTED; + } + else + { + hdconf_dialog[32].flags |= D_SELECTED; + hdconf_dialog[33].flags &= ~D_SELECTED; + } + if (new_cdrom_channel == 3) + { + hdconf_dialog[46].flags &= ~D_SELECTED; + hdconf_dialog[47].flags |= D_SELECTED; + } + else + { + hdconf_dialog[46].flags |= D_SELECTED; + hdconf_dialog[47].flags &= ~D_SELECTED; + } +} + +static int hdconf_radio_hd(int msg, DIALOG *d, int c) +{ + int ret = d_radio_proc(msg, d, c); + + if (ret == D_CLOSE) + { + if (new_cdrom_channel == d->d1) + { + new_cdrom_channel = -1; + update_hdd_cdrom(); + } + + return D_REDRAW; + } + + return ret; +} +static int hdconf_radio_cd(int msg, DIALOG *d, int c) +{ + int ret = d_radio_proc(msg, d, c); + + if (ret == D_CLOSE) + { + if (new_cdrom_channel != d->d1) + { + new_cdrom_channel = d->d1; + update_hdd_cdrom(); + } + + return D_REDRAW; + } + + return ret; +} + +int disc_hdconf() +{ + int c; + int changed=0; + + hdc_new[0] = hdc[0]; + hdc_new[1] = hdc[1]; + hdc_new[2] = hdc[2]; + hdc_new[3] = hdc[3]; + strcpy(hd_path[0], ide_fn[0]); + strcpy(hd_path[1], ide_fn[1]); + strcpy(hd_path[2], ide_fn[2]); + strcpy(hd_path[3], ide_fn[3]); + sprintf(hd_sectors[0], "%i", hdc[0].spt); + sprintf(hd_sectors[1], "%i", hdc[1].spt); + sprintf(hd_sectors[2], "%i", hdc[2].spt); + sprintf(hd_sectors[3], "%i", hdc[3].spt); + sprintf(hd_heads[0], "%i", hdc[0].hpc); + sprintf(hd_heads[1], "%i", hdc[1].hpc); + sprintf(hd_heads[2], "%i", hdc[2].hpc); + sprintf(hd_heads[3], "%i", hdc[3].hpc); + sprintf(hd_cylinders[0], "%i", hdc[0].tracks); + sprintf(hd_cylinders[1], "%i", hdc[1].tracks); + sprintf(hd_cylinders[2], "%i", hdc[2].tracks); + sprintf(hd_cylinders[3], "%i", hdc[3].tracks); + sprintf(hd_size[0], "Size : %imb", (((((uint64_t)hdc[0].tracks*(uint64_t)hdc[0].hpc)*(uint64_t)hdc[0].spt)*512)/1024)/1024); + sprintf(hd_size[1], "Size : %imb", (((((uint64_t)hdc[1].tracks*(uint64_t)hdc[1].hpc)*(uint64_t)hdc[1].spt)*512)/1024)/1024); + sprintf(hd_size[2], "Size : %imb", (((((uint64_t)hdc[2].tracks*(uint64_t)hdc[2].hpc)*(uint64_t)hdc[2].spt)*512)/1024)/1024); + sprintf(hd_size[3], "Size : %imb", (((((uint64_t)hdc[3].tracks*(uint64_t)hdc[3].hpc)*(uint64_t)hdc[3].spt)*512)/1024)/1024); + + new_cdrom_channel = cdrom_channel; + + update_hdd_cdrom(); + + while (1) + { + position_dialog(hdconf_dialog, SCREEN_W/2 - hdconf_dialog[0].w/2, SCREEN_H/2 - hdconf_dialog[0].h/2); + + c = popup_dialog(hdconf_dialog, 1); + + position_dialog(hdconf_dialog, -(SCREEN_W/2 - hdconf_dialog[0].w/2), -(SCREEN_H/2 - hdconf_dialog[0].h/2)); + + if (c == 1) + { + if (alert("This will reset PCem!", "Okay to continue?", NULL, "OK", "Cancel", 0, 0) == 1) + { + hdc[0] = hdc_new[0]; + hdc[1] = hdc_new[1]; + hdc[2] = hdc_new[2]; + hdc[3] = hdc_new[3]; + + strcpy(ide_fn[0], hd_path[0]); + strcpy(ide_fn[1], hd_path[1]); + strcpy(ide_fn[2], hd_path[2]); + strcpy(ide_fn[3], hd_path[3]); + + cdrom_channel = new_cdrom_channel; + + saveconfig(); + + resetpchard(); + + return D_O_K; + } + } + if (c == 2) + return D_O_K; + } + + return D_O_K; +} diff --git a/src/allegro-gui.c b/src/allegro-gui.c new file mode 100644 index 000000000..e29f8d1f9 --- /dev/null +++ b/src/allegro-gui.c @@ -0,0 +1,226 @@ +#include "ibm.h" +#include "device.h" +#include "allegro-main.h" +#include "allegro-gui.h" +#include "disc.h" +#include "ide.h" + +static int file_return(void) +{ + return D_CLOSE; +} + +static int file_exit(void) +{ + quited = 1; + return D_CLOSE; +} + +static int file_reset(void) +{ + resetpchard(); + return D_CLOSE; +} + +static int file_cad(void) +{ + resetpc_cad(); + return D_CLOSE; +} + + +static MENU file_menu[]= +{ + {"&Return", file_return, NULL, 0, NULL}, + {"&Hard Reset", file_reset, NULL, 0, NULL}, + {"&Ctrl+Alt+Del", file_cad, NULL, 0, NULL}, + {"E&xit", file_exit, NULL, 0, NULL}, + {NULL,NULL,NULL,0,NULL} +}; + +static int disc_load_a() +{ + char fn[260]; + int ret; + int xsize = SCREEN_W - 32, ysize = SCREEN_H - 64; + strcpy(fn, discfns[0]); + ret = file_select_ex("Please choose a disc image", fn, "IMG;IMA;FDI", 260, xsize, ysize); + if (ret) + { + disc_close(0); + disc_load(0, fn); + saveconfig(); + } + return D_O_K; +} + +static int disc_load_b() +{ + char fn[260]; + int ret; + int xsize = SCREEN_W - 32, ysize = SCREEN_H - 64; + strcpy(fn, discfns[1]); + ret = file_select_ex("Please choose a disc image", fn, "IMG;IMA;FDI", 260, xsize, ysize); + if (ret) + { + disc_close(1); + disc_load(1, fn); + saveconfig(); + } + return D_O_K; +} + +static int disc_eject_a() +{ + disc_close(0); + saveconfig(); + + return D_O_K; +} + +static int disc_eject_b() +{ + disc_close(1); + saveconfig(); + + return D_O_K; +} + +static MENU disc_menu[]= +{ + {"Load drive &A:...", disc_load_a, NULL, 0, NULL}, + {"Load drive &B:...", disc_load_b, NULL, 0, NULL}, + {"&Eject drive &A:", disc_eject_a, NULL, 0, NULL}, + {"Eject drive &B:", disc_eject_b, NULL, 0, NULL}, + {"&Configure hard discs...", disc_hdconf, NULL, 0, NULL}, + {NULL,NULL,NULL,0,NULL} +}; + +static MENU cdrom_menu[]; + +static void cdrom_update() +{ + int c; + + for (c = 0; cdrom_menu[c].text; c++) + cdrom_menu[c].flags = 0; + + if (!cdrom_enabled) + cdrom_menu[0].flags = D_SELECTED; + else + cdrom_menu[1].flags = D_SELECTED; + + return D_O_K; +} + +static int cdrom_disabled() +{ + if (!cdrom_enabled) + return D_O_K; + + if (alert("This will reset PCem!", "Okay to continue?", NULL, "OK", "Cancel", 0, 0) == 1) + { + atapi->exit(); + cdrom_enabled = 0; + saveconfig(); + resetpchard(); + cdrom_update(); + } + + return D_O_K; +} + +static int cdrom_empty() +{ + if (cdrom_enabled) + { + atapi->exit(); + cdrom_drive = -1; + cdrom_null_open(cdrom_drive); + return D_O_K; + } + + if (alert("This will reset PCem!", "Okay to continue?", NULL, "OK", "Cancel", 0, 0) == 1) + { + cdrom_drive = -1; + cdrom_enabled = 1; + cdrom_null_open(cdrom_drive); + saveconfig(); + resetpchard(); + cdrom_update(); + } +} + +static int cdrom_dev() +{ + if (cdrom_enabled) + { + atapi->exit(); + cdrom_drive = 1; + ioctl_open(cdrom_drive); + return D_O_K; + } + + if (alert("This will reset PCem!", "Okay to continue?", NULL, "OK", "Cancel", 0, 0) == 1) + { + cdrom_drive = 1; + cdrom_enabled = 1; + ioctl_open(cdrom_drive); + saveconfig(); + resetpchard(); + cdrom_update(); + } +} + +static MENU cdrom_menu[] = +{ + {"&Disabled", cdrom_disabled, NULL, 0, NULL}, + {"&Empty", cdrom_empty, NULL, 0, NULL}, + {"/dev/cdrom", cdrom_dev, NULL, 0, NULL}, + {NULL,NULL,NULL,0,NULL} +}; + +static MENU settings_menu[]= +{ + {"&Configure...", settings_configure, NULL, 0, NULL}, + {"CD-ROM", NULL, cdrom_menu, 0, NULL}, + {NULL,NULL,NULL,0,NULL} +}; + +static MENU main_menu[]= +{ + {"&File", NULL, file_menu, 0, NULL}, + {"&Disc", NULL, disc_menu, 0, NULL}, + {"&Settings", NULL, settings_menu, 0, NULL}, + {NULL,NULL,NULL,0,NULL} +}; + +static DIALOG pcem_gui[]= +{ + {d_menu_proc, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, main_menu, NULL, NULL}, + {d_yield_proc, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, NULL, NULL, NULL}, + {0,0,0,0,0,0,0,0,0,0,0,NULL,NULL,NULL} +}; + +void gui_enter() +{ + DIALOG_PLAYER *dp; + int x = 1; + infocus = 0; + + dp = init_dialog(pcem_gui, 0); + show_mouse(screen); + while (x && !(mouse_b & 2) && !key[KEY_ESC]) + { + x = update_dialog(dp); + } + show_mouse(NULL); + shutdown_dialog(dp); + + clear(screen); + clear_keybuf(); + + infocus = 1; + + device_force_redraw(); +} diff --git a/src/allegro-gui.h b/src/allegro-gui.h new file mode 100644 index 000000000..acfa50c00 --- /dev/null +++ b/src/allegro-gui.h @@ -0,0 +1,12 @@ +void gui_enter(); + +extern int quited; + +extern int romspresent[ROM_MAX]; +extern int gfx_present[GFX_MAX]; + +int disc_hdconf(); + +int settings_configure(); + +void deviceconfig_open(device_t *device); diff --git a/src/allegro-joystick.c b/src/allegro-joystick.c new file mode 100644 index 000000000..f759aeedb --- /dev/null +++ b/src/allegro-joystick.c @@ -0,0 +1,49 @@ +#include "allegro-main.h" +#include "plat-joystick.h" +#include "device.h" +#include "gameport.h" + +plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS]; +joystick_t joystick_state[MAX_JOYSTICKS]; + +int joysticks_present; + +void joystick_init() +{ + install_joystick(JOY_TYPE_AUTODETECT); + joysticks_present = num_joysticks; +} +void joystick_close() +{ +} +void joystick_poll() +{ + int c, d; + + poll_joystick(); + + for (c = 0; c < num_joysticks; c++) + { + plat_joystick_state[c].a[0] = joy[c].stick[0].axis[0].pos * 256; + plat_joystick_state[c].a[1] = joy[c].stick[0].axis[1].pos * 256; + for (d = 0; d < MAX_JOYSTICK_BUTTONS; d++) + plat_joystick_state[c].b[d] = joy[c].button[d].b; + } + for (c = 0; c < joystick_get_max_joysticks(joystick_type); c++) + { + if (c < num_joysticks) + { + for (d = 0; d < joystick_get_axis_count(joystick_type); d++) + joystick_state[c].axis[d] = plat_joystick_state[c].a[d]; + for (d = 0; d < joystick_get_button_count(joystick_type); d++) + joystick_state[c].button[d] = plat_joystick_state[c].b[d]; + } + else + { + for (d = 0; d < joystick_get_axis_count(joystick_type); d++) + joystick_state[c].axis[d] = 0; + for (d = 0; d < joystick_get_button_count(joystick_type); d++) + joystick_state[c].button[d] = 0; + } + } +} diff --git a/src/allegro-keyboard.c b/src/allegro-keyboard.c new file mode 100644 index 000000000..04c36c39d --- /dev/null +++ b/src/allegro-keyboard.c @@ -0,0 +1,49 @@ +#include "allegro-main.h" +#include "plat-keyboard.h" + +int pcem_key[272]; +int rawinputkey[272]; + +static int key_convert[128] = +{ + -1, 0x1e, 0x30, 0x2e, 0x20, 0x12, 0x21, 0x22, /* , A, B, C, D, E, F, G*/ + 0x23, 0x17, 0x24, 0x25, 0x26, 0x32, 0x31, 0x18, /* H, I, J, K, L, M, N, O*/ + 0x19, 0x10, 0x13, 0x1f, 0x14, 0x16, 0x2f, 0x11, /* P, Q, R, S, T, U, V, W*/ + 0x2d, 0x15, 0x2c, 0x0b, 0x02, 0x03, 0x04, 0x05, /* X, Y, Z, 0, 1, 2, 3, 4*/ + 0x06, 0x07, 0x08, 0x09, 0x0a, 0x52, 0x4f, 0x50, /* 5, 6, 7, 8, 9, p0, p1, p2*/ + 0x51, 0x4b, 0x4c, 0x4d, 0x47, 0x48, 0x49, 0x3b, /* p3, p4, p5, p6, p7, p8, p9, F1*/ + 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, /* F2, F3, F4, F5, F6, F7, F8, F9*/ + 0x44, 0x57, 0x58, 0x01, 0x29, 0x0c, 0x0d, 0x0e, /*F10, F11, F12, ESC, `ª, -_, =+, backspace*/ + 0x0f, 0x1a, 0x1b, 0x1c, 0x27, 0x28, 0x2b, 0x56, /*TAB, [{, ]}, ENT, ;:, '@, \|, #~*/ + 0x33, 0x34, 0x35, 0x39, 0xd2, 0xd3, 0xc7, 0xcf, /* ,<, .>, /?, SPC, INS, DEL, HOME, END*/ + 0xc9, 0xd1, 0xcb, 0xcd, 0xc8, 0xd0, 0xb5, 0x37, /*PGU, PGD, LFT, RHT, UP, DN, /, * */ + 0x4a, 0x4e, 0x53, 0x9c, 0xff, -1, -1, -1, /* p-, p+, pDL, pEN, psc, pse, abnt, yen*/ + -1, -1, -1, -1, -1, -1, -1, -1, /*kana, convert, noconvert, at, circumflex, colon2, kanji, pad equals*/ + -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, 0x2a, 0x36, 0x1d, 0x9d, 0x38, /*, , lshift, rshift, lctrl, rctrl, alt*/ + 0xb8, 0xdb, 0xdc, 0xdd, 0x46, 0x45, 0x3a, -1 /*altgr, lwin, rwin, menu, scrlock, numlock, capslock*/ +}; + +void keyboard_init() +{ + install_keyboard(); +} + +void keyboard_close() +{ +} + +void keyboard_poll_host() +{ + int c; + + for (c = 0; c < 128; c++) + { + int key_idx = key_convert[c]; + if (key_idx == -1) + continue; + + if (key[c] != pcem_key[key_idx]) + pcem_key[key_idx] = key[c]; + } +} diff --git a/src/allegro-main.c b/src/allegro-main.c new file mode 100644 index 000000000..cf8407925 --- /dev/null +++ b/src/allegro-main.c @@ -0,0 +1,169 @@ +#include "allegro-main.h" +#include "ibm.h" +#include "cpu.h" +#include "model.h" +#include "nvr.h" +#include "video.h" + +#undef printf + +int mousecapture = 0; +int quited = 0; +int winsizex = -1, winsizey = -1; + +int romspresent[ROM_MAX]; +int gfx_present[GFX_MAX]; + +void updatewindowsize(int x, int y) +{ + if (x < 128) + x = 128; + if (y < 128) + y = 128; + if (winsizex != x || winsizey != y) + { + winsizex = x; + winsizey = y; + allegro_video_update_size(x, y); + } +} + +void startblit() +{ +} + +void endblit() +{ +} + +static int ticks = 0; +static void timer_rout() +{ + ticks++; +} + +uint64_t timer_freq; +uint64_t timer_read() +{ + return 0; +} + +int main(int argc, char *argv[]) +{ + int frames = 0; + int c, d; + allegro_init(); + allegro_video_init(); + install_timer(); + install_int_ex(timer_rout, BPS_TO_TIMER(100)); + install_int_ex(onesec, BPS_TO_TIMER(1)); + midi_init(); + + initpc(argc, argv); + + d = romset; + for (c = 0; c < ROM_MAX; c++) + { + romset = c; + romspresent[c] = loadbios(); + pclog("romset %i - %i\n", c, romspresent[c]); + } + + for (c = 0; c < ROM_MAX; c++) + { + if (romspresent[c]) + break; + } + if (c == ROM_MAX) + { + printf("No ROMs present!\nYou must have at least one romset to use PCem."); + return 0; + } + + romset=d; + c=loadbios(); + + if (!c) + { + if (romset != -1) + printf("Configured romset not available.\nDefaulting to available romset."); + for (c = 0; c < ROM_MAX; c++) + { + if (romspresent[c]) + { + romset = c; + model = model_getmodel(romset); + saveconfig(); + resetpchard(); + break; + } + } + } + + for (c = 0; c < GFX_MAX; c++) + gfx_present[c] = video_card_available(video_old_to_new(c)); + + if (!video_card_available(video_old_to_new(gfxcard))) + { + if (gfxcard) printf("Configured video BIOS not available.\nDefaulting to available romset."); + for (c = GFX_MAX-1; c >= 0; c--) + { + if (gfx_present[c]) + { + gfxcard = c; + saveconfig(); + resetpchard(); + break; + } + } + } + + resetpchard(); + + ticks = 0; + while (!quited) + { + if (ticks) + { + ticks--; + runpc(); + frames++; + if (frames >= 200 && nvr_dosave) + { + frames = 0; + nvr_dosave = 0; + savenvr(); + } + } + else + rest(1); + + if (ticks > 10) + ticks = 0; + + if ((mouse_b & 1) && !mousecapture) + mousecapture = 1; + + if (((key[KEY_LCONTROL] || key[KEY_RCONTROL]) && key[KEY_END]) || (mouse_b & 4)) + mousecapture = 0; + + if ((key[KEY_LCONTROL] || key[KEY_RCONTROL]) && key[KEY_ALT] && key[KEY_PGDN]) + { + int old_winsizex = winsizex, old_winsizey = winsizey; + if (winsizex < 512 || winsizey < 350) + updatewindowsize(512, 350); + gui_enter(); + if (old_winsizex < 512 || old_winsizey < 350) + updatewindowsize(old_winsizex, old_winsizey); + ticks = 0; + } + } + + closepc(); + + midi_close(); + + return 0; +} + +END_OF_MAIN(); diff --git a/src/allegro-main.h b/src/allegro-main.h new file mode 100644 index 000000000..d5889a90d --- /dev/null +++ b/src/allegro-main.h @@ -0,0 +1,19 @@ +#define getr8 allegro_getr8 +#define setr8 allegro_setr8 +#define get_filename allegro_get_filename +#define append_filename allegro_append_filename +#define put_backslash allegro_put_backslash +#define get_extension allegro_get_extension +#define GFX_VGA allegro_GFX_VGA +#define MAX_JOYSTICKS allegro_MAX_JOYSTICKS + +#include + +#undef MAX_JOYSTICKS +#undef GFX_VGA +#undef getr8 +#undef setr8 +#undef get_filename +#undef append_filename +#undef put_backslash +#undef get_extension diff --git a/src/allegro-midi.c b/src/allegro-midi.c new file mode 100644 index 000000000..361e491d6 --- /dev/null +++ b/src/allegro-midi.c @@ -0,0 +1,45 @@ +#include "allegro-main.h" +#include "ibm.h" +#include "plat-midi.h" + +//#define USE_ALLEGRO_MIDI + +void midi_init() +{ +#ifdef USE_ALLEGRO_MIDI + install_sound(DIGI_NONE, MIDI_AUTODETECT, NULL); +#endif +} + +void midi_close() +{ +#ifdef USE_ALLEGRO_MIDI + remove_sound(); +#endif +} + +static int midi_cmd_pos, midi_len; +static uint8_t midi_command[3]; +static int midi_lengths[8] = {3, 3, 3, 3, 2, 2, 3, 0}; + +void midi_write(uint8_t val) +{ + if (val & 0x80) + { + midi_cmd_pos = 0; + midi_len = midi_lengths[(val >> 4) & 7]; + midi_command[0] = midi_command[1] = midi_command[2] = 0; + } + + if (midi_len && midi_cmd_pos < 3) + { + midi_command[midi_cmd_pos] = val; + + midi_cmd_pos++; + +#ifdef USE_ALLEGRO_MIDI + if (midi_cmd_pos == midi_len) + midi_out(midi_command, midi_len); +#endif + } +} diff --git a/src/allegro-mouse.c b/src/allegro-mouse.c new file mode 100644 index 000000000..214a802a6 --- /dev/null +++ b/src/allegro-mouse.c @@ -0,0 +1,31 @@ +#include "allegro-main.h" +#include "plat-mouse.h" + +int mouse_buttons; + +void mouse_init() +{ + install_mouse(); +} + +void mouse_close() +{ +} + +void mouse_poll_host() +{ + //poll_mouse(); + mouse_buttons = mouse_b; +} + +void mouse_get_mickeys(int *x, int *y) +{ + if (mousecapture) + { + get_mouse_mickeys(x, y); +// position_mouse(64, 64); + } + else + *x = *y = 0; +} + diff --git a/src/allegro-video.c b/src/allegro-video.c new file mode 100644 index 000000000..b7612f0b8 --- /dev/null +++ b/src/allegro-video.c @@ -0,0 +1,127 @@ +#include "allegro-main.h" +#include "ibm.h" +#include "video.h" + +#include "allegro-video.h" + +static PALETTE cgapal= +{ + {0,0,0},{0,42,0},{42,0,0},{42,21,0}, + {0,0,0},{0,42,42},{42,0,42},{42,42,42}, + {0,0,0},{21,63,21},{63,21,21},{63,63,21}, + {0,0,0},{21,63,63},{63,21,63},{63,63,63}, + + {0,0,0},{0,0,42},{0,42,0},{0,42,42}, + {42,0,0},{42,0,42},{42,21,00},{42,42,42}, + {21,21,21},{21,21,63},{21,63,21},{21,63,63}, + {63,21,21},{63,21,63},{63,63,21},{63,63,63}, + + {0,0,0},{0,21,0},{0,0,42},{0,42,42}, + {42,0,21},{21,10,21},{42,0,42},{42,0,63}, + {21,21,21},{21,63,21},{42,21,42},{21,63,63}, + {63,0,0},{42,42,0},{63,21,42},{41,41,41}, + + {0,0,0},{0,42,42},{42,0,0},{42,42,42}, + {0,0,0},{0,42,42},{42,0,0},{42,42,42}, + {0,0,0},{0,63,63},{63,0,0},{63,63,63}, + {0,0,0},{0,63,63},{63,0,0},{63,63,63}, +}; + +static uint32_t pal_lookup[256]; + +static void allegro_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h); +static void allegro_blit_memtoscreen_8(int x, int y, int w, int h); +static BITMAP *buffer32_vscale; +void allegro_video_init() +{ + int c; + + set_color_depth(32); + set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0); + video_blit_memtoscreen = allegro_blit_memtoscreen; + video_blit_memtoscreen_8 = allegro_blit_memtoscreen_8; + + for (c = 0; c < 256; c++) + pal_lookup[c] = makecol(cgapal[c].r << 2, cgapal[c].g << 2, cgapal[c].b << 2); + + buffer32_vscale = create_bitmap(2048, 2048); +} + +void allegro_video_close() +{ + destroy_bitmap(buffer32_vscale); +} + +void allegro_video_update_size(int x, int y) +{ + if (set_gfx_mode(GFX_AUTODETECT_WINDOWED, x, y, 0, 0)) + fatal("Failed to set gfx mode %i,%i : %s\n", x, y, allegro_error); +} + +static void allegro_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) +{ + if (h < winsizey) + { + int yy; + + for (yy = y+y1; yy < y+y2; yy++) + { + if (yy >= 0) + { + memcpy(&((uint32_t *)buffer32_vscale->line[yy*2])[x], &((uint32_t *)buffer32->line[yy])[x], w*4); + memcpy(&((uint32_t *)buffer32_vscale->line[(yy*2)+1])[x], &((uint32_t *)buffer32->line[yy])[x], w*4); + } + } + + blit(buffer32_vscale, screen, x, (y+y1)*2, 0, y1, w, (y2-y1)*2); + } + else + blit(buffer32, screen, x, y+y1, 0, y1, w, y2-y1); +} + +static void allegro_blit_memtoscreen_8(int x, int y, int w, int h) +{ + int xx, yy; + int line_double = (winsizey > h) ? 1 : 0; + + if (y < 0) + { + h += y; + y = 0; + } + + for (yy = y; yy < y+h; yy++) + { + int dy = line_double ? yy*2 : yy; + if (dy < buffer->h) + { + if (line_double) + { + for (xx = x; xx < x+w; xx++) + { + ((uint32_t *)buffer32->line[dy])[xx] = + ((uint32_t *)buffer32->line[dy + 1])[xx] = pal_lookup[buffer->line[yy][xx]]; + } + } + else + { + for (xx = x; xx < x+w; xx++) + ((uint32_t *)buffer32->line[dy])[xx] = pal_lookup[buffer->line[yy][xx]]; + } + } + } + + if (readflash) + { + if (line_double) + rectfill(buffer32, x+SCREEN_W-40, y*2+8, SCREEN_W-8, y*2+14, makecol(255, 255, 255)); + else + rectfill(buffer32, x+SCREEN_W-40, y+8, SCREEN_W-8, y+14, makecol(255, 255, 255)); + readflash = 0; + } + + if (line_double) + blit(buffer32, screen, x, y*2, 0, 0, w, h*2); + else + blit(buffer32, screen, x, y, 0, 0, w, h); +} diff --git a/src/allegro-video.h b/src/allegro-video.h new file mode 100644 index 000000000..76ce4eabc --- /dev/null +++ b/src/allegro-video.h @@ -0,0 +1,3 @@ +void allegro_video_init(); +void allegro_video_close(); +void allegro_video_update_size(int x, int y); diff --git a/src/amstrad.c b/src/amstrad.c new file mode 100644 index 000000000..505eb07c2 --- /dev/null +++ b/src/amstrad.c @@ -0,0 +1,83 @@ +#include "ibm.h" +#include "io.h" +#include "keyboard.h" +#include "lpt.h" +#include "mouse.h" + +#include "amstrad.h" + +static uint8_t amstrad_dead; + +uint8_t amstrad_read(uint16_t port, void *priv) +{ + pclog("amstrad_read : %04X\n",port); + switch (port) + { + case 0x379: + return 7 | readdacfifo(); + case 0x37a: + if (romset == ROM_PC1512) return 0x20; + if (romset == ROM_PC200) return 0x80; + return 0; + case 0xdead: + return amstrad_dead; + } + return 0xff; +} + +void amstrad_write(uint16_t port, uint8_t val, void *priv) +{ + switch (port) + { + case 0xdead: + amstrad_dead = val; + break; + } +} + +static uint8_t mousex,mousey; + +void amstrad_mouse_write(uint16_t addr, uint8_t val, void *priv) +{ +// pclog("Write mouse %04X %02X %04X:%04X\n", addr, val, CS, pc); + if (addr==0x78) mousex=0; + else mousey=0; +} + +uint8_t amstrad_mouse_read(uint16_t addr, void *priv) +{ +// printf("Read mouse %04X %04X:%04X %02X\n", addr, CS, pc, (addr == 0x78) ? mousex : mousey); + if (addr==0x78) return mousex; + return mousey; +} + +static int oldb = 0; + +void amstrad_mouse_poll(int x, int y, int b) +{ + mousex += x; + mousey -= y; + + if ((b & 1) && !(oldb & 1)) + keyboard_send(0x7e); + if ((b & 2) && !(oldb & 2)) + keyboard_send(0x7d); + if (!(b & 1) && (oldb & 1)) + keyboard_send(0xfe); + if (!(b & 2) && (oldb & 2)) + keyboard_send(0xfd); + + oldb = b; +} + +void amstrad_init() +{ + lpt2_remove_ams(); + + io_sethandler(0x0078, 0x0001, amstrad_mouse_read, NULL, NULL, amstrad_mouse_write, NULL, NULL, NULL); + io_sethandler(0x007a, 0x0001, amstrad_mouse_read, NULL, NULL, amstrad_mouse_write, NULL, NULL, NULL); + io_sethandler(0x0379, 0x0002, amstrad_read, NULL, NULL, NULL, NULL, NULL, NULL); + io_sethandler(0xdead, 0x0001, amstrad_read, NULL, NULL, amstrad_write, NULL, NULL, NULL); + + mouse_poll = amstrad_mouse_poll; +} diff --git a/src/amstrad.h b/src/amstrad.h new file mode 100644 index 000000000..5fac1a524 --- /dev/null +++ b/src/amstrad.h @@ -0,0 +1,2 @@ +void amstrad_init(); + diff --git a/src/bswap.h b/src/bswap.h new file mode 100644 index 000000000..070a40a89 --- /dev/null +++ b/src/bswap.h @@ -0,0 +1,202 @@ +#ifndef BSWAP_H +#define BSWAP_H + +//#include "config-host.h" + +#include + +#ifdef HAVE_BYTESWAP_H +#include +#else + +#define bswap_16(x) \ +({ \ + uint16_t __x = (x); \ + ((uint16_t)( \ + (((uint16_t)(__x) & (uint16_t)0x00ffU) << 8) | \ + (((uint16_t)(__x) & (uint16_t)0xff00U) >> 8) )); \ +}) + +#define bswap_32(x) \ +({ \ + uint32_t __x = (x); \ + ((uint32_t)( \ + (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \ + (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \ + (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \ + (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )); \ +}) + +#define bswap_64(x) \ +({ \ + uint64_t __x = (x); \ + ((uint64_t)( \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000000000ffULL) << 56) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000000000ff00ULL) << 40) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000000000ff0000ULL) << 24) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00000000ff000000ULL) << 8) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x000000ff00000000ULL) >> 8) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x0000ff0000000000ULL) >> 24) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0x00ff000000000000ULL) >> 40) | \ + (uint64_t)(((uint64_t)(__x) & (uint64_t)0xff00000000000000ULL) >> 56) )); \ +}) + +#endif /* !HAVE_BYTESWAP_H */ + +static inline uint16_t bswap16(uint16_t x) +{ + return bswap_16(x); +} + +static inline uint32_t bswap32(uint32_t x) +{ + return bswap_32(x); +} + +static inline uint64_t bswap64(uint64_t x) +{ + return bswap_64(x); +} + +static inline void bswap16s(uint16_t *s) +{ + *s = bswap16(*s); +} + +static inline void bswap32s(uint32_t *s) +{ + *s = bswap32(*s); +} + +static inline void bswap64s(uint64_t *s) +{ + *s = bswap64(*s); +} + +#if defined(WORDS_BIGENDIAN) +#define be_bswap(v, size) (v) +#define le_bswap(v, size) bswap ## size(v) +#define be_bswaps(v, size) +#define le_bswaps(p, size) *p = bswap ## size(*p); +#else +#define le_bswap(v, size) (v) +#define be_bswap(v, size) bswap ## size(v) +#define le_bswaps(v, size) +#define be_bswaps(p, size) *p = bswap ## size(*p); +#endif + +#define CPU_CONVERT(endian, size, type)\ +static inline type endian ## size ## _to_cpu(type v)\ +{\ + return endian ## _bswap(v, size);\ +}\ +\ +static inline type cpu_to_ ## endian ## size(type v)\ +{\ + return endian ## _bswap(v, size);\ +}\ +\ +static inline void endian ## size ## _to_cpus(type *p)\ +{\ + endian ## _bswaps(p, size)\ +}\ +\ +static inline void cpu_to_ ## endian ## size ## s(type *p)\ +{\ + endian ## _bswaps(p, size)\ +}\ +\ +static inline type endian ## size ## _to_cpup(const type *p)\ +{\ + return endian ## size ## _to_cpu(*p);\ +}\ +\ +static inline void cpu_to_ ## endian ## size ## w(type *p, type v)\ +{\ + *p = cpu_to_ ## endian ## size(v);\ +} + +CPU_CONVERT(be, 16, uint16_t) +CPU_CONVERT(be, 32, uint32_t) +CPU_CONVERT(be, 64, uint64_t) + +CPU_CONVERT(le, 16, uint16_t) +CPU_CONVERT(le, 32, uint32_t) +CPU_CONVERT(le, 64, uint64_t) + +/* unaligned versions (optimized for frequent unaligned accesses)*/ + +#if defined(__i386__) || defined(__powerpc__) + +#define cpu_to_le16wu(p, v) cpu_to_le16w(p, v) +#define cpu_to_le32wu(p, v) cpu_to_le32w(p, v) +#define le16_to_cpupu(p) le16_to_cpup(p) +#define le32_to_cpupu(p) le32_to_cpup(p) + +#define cpu_to_be16wu(p, v) cpu_to_be16w(p, v) +#define cpu_to_be32wu(p, v) cpu_to_be32w(p, v) + +#else + +static inline void cpu_to_le16wu(uint16_t *p, uint16_t v) +{ + uint8_t *p1 = (uint8_t *)p; + + p1[0] = v; + p1[1] = v >> 8; +} + +static inline void cpu_to_le32wu(uint32_t *p, uint32_t v) +{ + uint8_t *p1 = (uint8_t *)p; + + p1[0] = v; + p1[1] = v >> 8; + p1[2] = v >> 16; + p1[3] = v >> 24; +} + +static inline uint16_t le16_to_cpupu(const uint16_t *p) +{ + const uint8_t *p1 = (const uint8_t *)p; + return p1[0] | (p1[1] << 8); +} + +static inline uint32_t le32_to_cpupu(const uint32_t *p) +{ + const uint8_t *p1 = (const uint8_t *)p; + return p1[0] | (p1[1] << 8) | (p1[2] << 16) | (p1[3] << 24); +} + +static inline void cpu_to_be16wu(uint16_t *p, uint16_t v) +{ + uint8_t *p1 = (uint8_t *)p; + + p1[0] = v >> 8; + p1[1] = v; +} + +static inline void cpu_to_be32wu(uint32_t *p, uint32_t v) +{ + uint8_t *p1 = (uint8_t *)p; + + p1[0] = v >> 24; + p1[1] = v >> 16; + p1[2] = v >> 8; + p1[3] = v; +} + +#endif + +#ifdef WORDS_BIGENDIAN +#define cpu_to_32wu cpu_to_be32wu +#else +#define cpu_to_32wu cpu_to_le32wu +#endif + +#undef le_bswap +#undef be_bswap +#undef le_bswaps +#undef be_bswaps + +#endif /* BSWAP_H */ diff --git a/src/cdrom-ioctl-linux.c b/src/cdrom-ioctl-linux.c new file mode 100644 index 000000000..60d3ae42d --- /dev/null +++ b/src/cdrom-ioctl-linux.c @@ -0,0 +1,724 @@ +/*Linux CD-ROM support via IOCTL*/ + +#include +#include +#include +#include +#include "ibm.h" +#include "ide.h" +#include "cdrom-ioctl.h" + +static ATAPI ioctl_atapi; + +static uint32_t last_block = 0; +static uint32_t cdrom_capacity = 0; +static int ioctl_inited = 0; +static char ioctl_path[8]; +static int tocvalid = 0; +static struct cdrom_tocentry toc[100]; +static int first_track, last_track; + +int old_cdrom_drive; + +#define MSFtoLBA(m,s,f) (((((m*60)+s)*75)+f)-150) + +enum +{ + CD_STOPPED = 0, + CD_PLAYING, + CD_PAUSED +}; + +static int ioctl_cd_state = CD_STOPPED; +static uint32_t ioctl_cd_pos = 0, ioctl_cd_end = 0; +#define BUF_SIZE 32768 +static int16_t cd_buffer[BUF_SIZE]; +static int cd_buflen = 0; +void ioctl_audio_callback(int16_t *output, int len) +{ + int fd; + struct cdrom_read_audio read_audio; + +// pclog("Audio callback %08X %08X %i %i %i %04X %i\n", ioctl_cd_pos, ioctl_cd_end, ioctl_cd_state, cd_buflen, len, cd_buffer[4], GetTickCount()); + if (ioctl_cd_state != CD_PLAYING) + { + memset(output, 0, len * 2); + return; + } + fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); + + if (fd <= 0) + { + memset(output, 0, len * 2); + return; + } + + while (cd_buflen < len) + { + if (ioctl_cd_pos < ioctl_cd_end) + { + read_audio.addr.lba = ioctl_cd_pos - 150; + read_audio.addr_format = CDROM_LBA; + read_audio.nframes = 1; + read_audio.buf = (__u8 *)&cd_buffer[cd_buflen]; + + if (ioctl(fd, CDROMREADAUDIO, &read_audio) < 0) + { +// pclog("DeviceIoControl returned false\n"); + memset(&cd_buffer[cd_buflen], 0, (BUF_SIZE - cd_buflen) * 2); + ioctl_cd_state = CD_STOPPED; + cd_buflen = len; + } + else + { +// pclog("DeviceIoControl returned true\n"); + ioctl_cd_pos++; + cd_buflen += (2352 / 2); + } + } + else + { + memset(&cd_buffer[cd_buflen], 0, (BUF_SIZE - cd_buflen) * 2); + ioctl_cd_state = CD_STOPPED; + cd_buflen = len; + } + } + close(fd); + memcpy(output, cd_buffer, len * 2); +// for (c = 0; c < BUF_SIZE - len; c++) +// cd_buffer[c] = cd_buffer[c + cd_buflen]; + memcpy(&cd_buffer[0], &cd_buffer[len], (BUF_SIZE - len) * 2); + cd_buflen -= len; +// pclog("Done %i\n", GetTickCount()); +} + +void ioctl_audio_stop() +{ + ioctl_cd_state = CD_STOPPED; +} + +static int get_track_nr(uint32_t pos) +{ + int c; + int track = 0; + + if (!tocvalid) + return 0; + + for (c = first_track; c < last_track; c++) + { + uint32_t track_address = toc[c].cdte_addr.msf.frame + + (toc[c].cdte_addr.msf.second * 75) + + (toc[c].cdte_addr.msf.minute * 75 * 60); +//pclog("get_track_nr: track=%i pos=%x track_address=%x\n", c, pos, track_address); + if (track_address <= pos) + track = c; + } + return track; +} + +static int is_track_audio(uint32_t pos) +{ + int c; + int control = 0; + + if (!tocvalid) + return 0; + + for (c = first_track; c < last_track; c++) + { + uint32_t track_address = toc[c].cdte_addr.msf.frame + + (toc[c].cdte_addr.msf.second * 75) + + (toc[c].cdte_addr.msf.minute * 75 * 60); +//pclog("get_track_nr: track=%i pos=%x track_address=%x\n", c, pos, track_address); + if (track_address <= pos) + control = toc[c].cdte_ctrl; + } + return (control & 4) ? 0 : 1; +} + +static int ioctl_is_track_audio(uint32_t pos, int ismsf) +{ + if (ismsf) + { + int m = (pos >> 16) & 0xff; + int s = (pos >> 8) & 0xff; + int f = pos & 0xff; + pos = MSFtoLBA(m, s, f); + } + return is_track_audio(pos); +} + +static void ioctl_playaudio(uint32_t pos, uint32_t len, int ismsf) +{ +// pclog("Play audio - %08X %08X %i\n", pos, len, ismsf); + if (ismsf) + { + pos = (pos & 0xff) + (((pos >> 8) & 0xff) * 75) + (((pos >> 16) & 0xff) * 75 * 60); + len = (len & 0xff) + (((len >> 8) & 0xff) * 75) + (((len >> 16) & 0xff) * 75 * 60); +// pclog("MSF - pos = %08X len = %08X\n", pos, len); + } + else + len += pos; + ioctl_cd_pos = pos;// + 150; + ioctl_cd_end = pos+len;// + 150; + ioctl_cd_state = CD_PLAYING; + if (ioctl_cd_pos < 150) + ioctl_cd_pos = 150; +// pclog("Audio start %08X %08X %i %i %i\n", ioctl_cd_pos, ioctl_cd_end, ioctl_cd_state, 0, len); +} + +static void ioctl_pause(void) +{ + if (ioctl_cd_state == CD_PLAYING) + ioctl_cd_state = CD_PAUSED; +} + +static void ioctl_resume(void) +{ + if (ioctl_cd_state == CD_PAUSED) + ioctl_cd_state = CD_PLAYING; +} + +static void ioctl_stop(void) +{ + ioctl_cd_state = CD_STOPPED; +} + +static void ioctl_seek(uint32_t pos) +{ +// pclog("Seek %08X\n", pos); + ioctl_cd_pos = pos; + ioctl_cd_state = CD_STOPPED; +} + +static int read_toc(int fd, struct cdrom_tocentry *btoc) +{ + struct cdrom_tochdr toc_hdr; + int track, err; +//pclog("read_toc\n"); + err = ioctl(fd, CDROMREADTOCHDR, &toc_hdr); + if (err == -1) + { + pclog("read_toc: CDROMREADTOCHDR failed\n"); + return 0; + } + + first_track = toc_hdr.cdth_trk0; + last_track = toc_hdr.cdth_trk1; +//pclog("read_toc: first_track=%i last_track=%i\n", first_track, last_track); + memset(btoc, 0, sizeof(btoc)); + + for (track = toc_hdr.cdth_trk0; track <= toc_hdr.cdth_trk1; track++) + { + btoc[track].cdte_track = track; + btoc[track].cdte_format = CDROM_MSF; + err = ioctl(fd, CDROMREADTOCENTRY, &btoc[track]); + if (err == -1) + { +// pclog("read_toc: CDROMREADTOCENTRY failed on track %i\n", track); + return 0; + } +// pclog("read_toc: Track %02X - number %02X control %02X adr %02X address %02X %02X %02X %02X\n", track, toc[track].cdte_track, toc[track].cdte_ctrl, toc[track].cdte_adr, 0, toc[track].cdte_addr.msf.minute, toc[track].cdte_addr.msf.second, toc[track].cdte_addr.msf.frame); + } + return 1; +} + +static int ioctl_ready(void) +{ + long size; + int temp; + struct cdrom_tochdr toc_hdr; + struct cdrom_tocentry toc_entry; + int err; + int fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); + + if (fd <= 0) + return 0; + + err = ioctl(fd, CDROMREADTOCHDR, &toc_hdr); + if (err == -1) + { + close(fd); + return 0; + } +// pclog("CDROMREADTOCHDR: start track=%i end track=%i\n", toc_hdr.cdth_trk0, toc_hdr.cdth_trk1); + toc_entry.cdte_track = toc_hdr.cdth_trk1; + toc_entry.cdte_format = CDROM_MSF; + err = ioctl(fd, CDROMREADTOCENTRY, &toc_entry); + if (err == -1) + { + close(fd); + return 0; + } +// pclog("CDROMREADTOCENTRY: addr=%02i:%02i:%02i\n", toc_entry.cdte_addr.msf.minute, toc_entry.cdte_addr.msf.second, toc_entry.cdte_addr.msf.frame); + if ((toc_entry.cdte_addr.msf.minute != toc[toc_hdr.cdth_trk1].cdte_addr.msf.minute) || + (toc_entry.cdte_addr.msf.second != toc[toc_hdr.cdth_trk1].cdte_addr.msf.second) || + (toc_entry.cdte_addr.msf.frame != toc[toc_hdr.cdth_trk1].cdte_addr.msf.frame ) || + !tocvalid) + { + int track; + ioctl_cd_state = CD_STOPPED; + + tocvalid = read_toc(fd, toc); + close(fd); + return 1; + } + close(fd); + return 1; +} + +static int ioctl_get_last_block(unsigned char starttrack, int msf, int maxlen, int single) +{ + int c; + int lb = 0; + int tv = 0; + struct cdrom_tocentry lbtoc[100]; + int fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); + + if (fd <= 0) + return 0; + + ioctl_cd_state = CD_STOPPED; + + tv = read_toc(fd, lbtoc); + + close(fd); + + if (!tv) + return 0; + + last_block = 0; + for (c = 0; c <= last_track; c++) + { + uint32_t address; + address = MSFtoLBA(toc[c].cdte_addr.msf.minute, toc[c].cdte_addr.msf.second, toc[c].cdte_addr.msf.frame); + if (address > last_block) + lb = address; + } + return lb; +} + +static int ioctl_medium_changed(void) +{ + long size; + int temp; + struct cdrom_tochdr toc_hdr; + struct cdrom_tocentry toc_entry; + int err; + int fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); + + if (fd <= 0) + return 0; + + err = ioctl(fd, CDROMREADTOCHDR, &toc_hdr); + if (err == -1) + { + close(fd); + return 0; + } + toc_entry.cdte_track = toc_hdr.cdth_trk1; + toc_entry.cdte_format = CDROM_MSF; + err = ioctl(fd, CDROMREADTOCENTRY, &toc_entry); + if (err == -1) + { + close(fd); + return 0; + } +// pclog("CDROMREADTOCENTRY: addr=%02i:%02i:%02i\n", toc_entry.cdte_addr.msf.minute, toc_entry.cdte_addr.msf.second, toc_entry.cdte_addr.msf.frame); + if ((toc_entry.cdte_addr.msf.minute != toc[toc_hdr.cdth_trk1].cdte_addr.msf.minute) || + (toc_entry.cdte_addr.msf.second != toc[toc_hdr.cdth_trk1].cdte_addr.msf.second) || + (toc_entry.cdte_addr.msf.frame != toc[toc_hdr.cdth_trk1].cdte_addr.msf.frame )) + { + cdrom_capacity = ioctl_get_last_block(0, 0, 4096, 0); + return 1; + } + return 0; +} + +static uint8_t ioctl_getcurrentsubchannel(uint8_t *b, int msf) +{ + struct cdrom_subchnl sub; + uint32_t cdpos = ioctl_cd_pos; + int track = get_track_nr(cdpos); + uint32_t track_address = toc[track].cdte_addr.msf.frame + + (toc[track].cdte_addr.msf.second * 75) + + (toc[track].cdte_addr.msf.minute * 75 * 60); + long size; + int pos=0; + int err; + uint8_t ret; +//pclog("ioctl_getsubchannel: cdpos=%x track_address=%x track=%i\n", cdpos, track_address, track); + if (ioctl_cd_state == CD_PLAYING) + ret = 0x11; + else if (ioctl_cd_state == CD_PAUSED) + ret = 0x12; + else + ret = 0x13; + + b[pos++] = (toc[track].cdte_adr << 4) | toc[track].cdte_ctrl; + b[pos++] = track; + b[pos++] = 0; + + if (msf) + { + uint32_t dat = cdpos; + b[pos + 3] = (uint8_t)(dat % 75); dat /= 75; + b[pos + 2] = (uint8_t)(dat % 60); dat /= 60; + b[pos + 1] = (uint8_t)dat; + b[pos] = 0; + pos += 4; + dat = cdpos - track_address; + b[pos + 3] = (uint8_t)(dat % 75); dat /= 75; + b[pos + 2] = (uint8_t)(dat % 60); dat /= 60; + b[pos + 1] = (uint8_t)dat; + b[pos] = 0; + pos += 4; + } + else + { + b[pos++] = (cdpos >> 24) & 0xff; + b[pos++] = (cdpos >> 16) & 0xff; + b[pos++] = (cdpos >> 8) & 0xff; + b[pos++] = cdpos & 0xff; + cdpos -= track_address; + b[pos++] = (cdpos >> 24) & 0xff; + b[pos++] = (cdpos >> 16) & 0xff; + b[pos++] = (cdpos >> 8) & 0xff; + b[pos++] = cdpos & 0xff; + } + + return ret; +} + +static void ioctl_eject(void) +{ + int fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); + + if (fd <= 0) + return; + + ioctl(fd, CDROMEJECT); + + close(fd); +} + +static void ioctl_load(void) +{ + int fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); + + if (fd <= 0) + return; + + ioctl(fd, CDROMEJECT); + + close(fd); + + cdrom_capacity = ioctl_get_last_block(0, 0, 4096, 0); +} + +static void ioctl_readsector(uint8_t *b, int sector) +{ + int cdrom = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); + if (cdrom <= 0) + return; + lseek(cdrom, sector*2048, SEEK_SET); + read(cdrom, b, 2048); + close(cdrom); +} + +union +{ + struct cdrom_msf *msf; + char b[CD_FRAMESIZE_RAW]; +} raw_read_params; + +static int lba_to_msf(int lba) +{ + return (((lba / 75) / 60) << 16) + (((lba / 75) % 60) << 8) + (lba % 75); +} + +static void ioctl_readsector_raw(uint8_t *b, int sector) +{ + int err; + int imsf = lba_to_msf(sector); + int cdrom = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); + + if (cdrom <= 0) + return; + + raw_read_params.msf = malloc(sizeof(struct cdrom_msf)); + raw_read_params.msf->cdmsf_frame0 = imsf & 0xff; + raw_read_params.msf->cdmsf_sec0 = (imsf >> 8) & 0xff; + raw_read_params.msf->cdmsf_min0 = (imsf >> 16) & 0xff; + + /* This will read the actual raw sectors from the disc. */ + err = ioctl(cdrom, CDROMREADRAW, (void *) &raw_read_params); + if (err == -1) + { + pclog("read_toc: CDROMREADTOCHDR failed\n"); + return; + } + + memcpy(b, raw_read_params.b, 2352); + + close(cdrom); + + free(raw_read_params.msf); +} + +static int ioctl_readtoc(unsigned char *b, unsigned char starttrack, int msf, int maxlen, int single) +{ + int len=4; + long size; + int c,d; + uint32_t temp; + int fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); + + if (fd <= 0) + return 0; + + ioctl_cd_state = CD_STOPPED; + + tocvalid = read_toc(fd, toc); + + close(fd); + + if (!tocvalid) + return 4; + +// pclog("Read TOC done! %i\n",single); + b[2] = first_track; + b[3] = last_track; + d = 0; +//pclog("Read TOC starttrack=%i\n", starttrack); + for (c = 1; c <= last_track; c++) + { + if (toc[c].cdte_track >= starttrack) + { + d = c; + break; + } + } + b[2] = toc[c].cdte_track; + last_block = 0; + for (c = d; c <= last_track; c++) + { + uint32_t address; + if ((len + 8) > maxlen) + break; +// pclog("Len %i max %i Track %02X - %02X %02X %02i:%02i:%02i %08X\n",len,maxlen,toc[c].cdte_track,toc[c].cdte_adr,toc[c].cdte_ctrl,toc[c].cdte_addr.msf.minute, toc[c].cdte_addr.msf.second, toc[c].cdte_addr.msf.frame,MSFtoLBA(toc[c].cdte_addr.msf.minute, toc[c].cdte_addr.msf.second, toc[c].cdte_addr.msf.frame)); + b[len++] = 0; /*Reserved*/ + b[len++] = (toc[c].cdte_adr << 4) | toc[c].cdte_ctrl; + b[len++] = toc[c].cdte_track; + b[len++] = 0; /*Reserved*/ + address = MSFtoLBA(toc[c].cdte_addr.msf.minute, toc[c].cdte_addr.msf.second, toc[c].cdte_addr.msf.frame); + if (address > last_block) + last_block = address; + + if (msf) + { + b[len++] = 0; + b[len++] = toc[c].cdte_addr.msf.minute; + b[len++] = toc[c].cdte_addr.msf.second; + b[len++] = toc[c].cdte_addr.msf.frame; + } + else + { + temp = MSFtoLBA(toc[c].cdte_addr.msf.minute, toc[c].cdte_addr.msf.second, toc[c].cdte_addr.msf.frame); + b[len++] = temp >> 24; + b[len++] = temp >> 16; + b[len++] = temp >> 8; + b[len++] = temp; + } + if (single) + break; + } + b[0] = (uint8_t)(((len-2) >> 8) & 0xff); + b[1] = (uint8_t)((len-2) & 0xff); +/* pclog("Table of Contents (%i bytes) : \n", size); + pclog("First track - %02X\n", first_track); + pclog("Last track - %02X\n", last_track); + for (c = 0; c <= last_track; c++) + pclog("Track %02X - number %02X control %02X adr %02X address %02X %02X %02X %02X\n", c, toc[c].cdte_track, toc[c].cdte_ctrl, toc[c].cdte_adr, 0, toc[c].cdte_addr.msf.minute, toc[c].cdte_addr.msf.second, toc[c].cdte_addr.msf.frame); + for (c = 0;c <= last_track; c++) + pclog("Track %02X - number %02X control %02X adr %02X address %06X\n", c, toc[c].cdte_track, toc[c].cdte_ctrl, toc[c].cdte_adr, MSFtoLBA(toc[c].cdte_addr.msf.minute, toc[c].cdte_addr.msf.second, toc[c].cdte_addr.msf.frame));*/ + return len; +} + +static int ioctl_readtoc_session(unsigned char *b, int msf, int maxlen) +{ + struct cdrom_multisession session; + int len = 4; + int err; + int fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); + + if (fd <= 0) + return 0; + + session.addr_format = CDROM_MSF; + err = ioctl(fd, CDROMMULTISESSION, &session); + + if (err == -1) + { + close(fd); + return 0; + } + + b[2] = 0; + b[3] = 0; + b[len++] = 0; /*Reserved*/ + b[len++] = (toc[0].cdte_adr << 4) | toc[0].cdte_ctrl; + b[len++] = toc[0].cdte_track; + b[len++] = 0; /*Reserved*/ + if (msf) + { + b[len++] = 0; + b[len++] = session.addr.msf.minute; + b[len++] = session.addr.msf.second; + b[len++] = session.addr.msf.frame; + } + else + { + uint32_t temp = MSFtoLBA(session.addr.msf.minute, session.addr.msf.second, session.addr.msf.frame); + b[len++] = temp >> 24; + b[len++] = temp >> 16; + b[len++] = temp >> 8; + b[len++] = temp; + } + + return len; +} + +static int ioctl_readtoc_raw(unsigned char *b, int maxlen) +{ + struct cdrom_tochdr toc_hdr; + struct cdrom_tocentry toc2[100]; + int track, err; + int len = 4; + int fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); +//pclog("read_toc\n"); + if (fd <= 0) + return 0; + + err = ioctl(fd, CDROMREADTOCHDR, &toc_hdr); + if (err == -1) + { + pclog("read_toc: CDROMREADTOCHDR failed\n"); + return 0; + } + + b[2] = toc_hdr.cdth_trk0; + b[3] = toc_hdr.cdth_trk1; + + //pclog("read_toc: first_track=%i last_track=%i\n", first_track, last_track); + memset(toc, 0, sizeof(toc)); + + for (track = toc_hdr.cdth_trk0; track <= toc_hdr.cdth_trk1; track++) + { + if ((len + 11) > maxlen) + { + pclog("ioctl_readtocraw: This iteration would fill the buffer beyond the bounds, aborting...\n"); + close(fd); + return len; + } + + toc2[track].cdte_track = track; + toc2[track].cdte_format = CDROM_MSF; + err = ioctl(fd, CDROMREADTOCENTRY, &toc2[track]); + if (err == -1) + { +// pclog("read_toc: CDROMREADTOCENTRY failed on track %i\n", track); + close(fd); + return 0; + } +// pclog("read_toc: Track %02X - number %02X control %02X adr %02X address %02X %02X %02X %02X\n", track, toc[track].cdte_track, toc[track].cdte_ctrl, toc[track].cdte_adr, 0, toc[track].cdte_addr.msf.minute, toc[track].cdte_addr.msf.second, toc[track].cdte_addr.msf.frame); + + b[len++] = toc2[track].cdte_track; + b[len++]= (toc2[track].cdte_adr << 4) | toc[track].cdte_ctrl; + b[len++]=0; + b[len++]=0; + b[len++]=0; + b[len++]=0; + b[len++]=0; + b[len++]=0; + b[len++] = toc2[track].cdte_addr.msf.minute; + b[len++] = toc2[track].cdte_addr.msf.second; + b[len++] = toc2[track].cdte_addr.msf.frame; + } + close(fd); + return len; +} + +static uint32_t ioctl_size() +{ + return cdrom_capacity; +} + +static int ioctl_status() +{ + if (!(ioctl_ready) && (cdrom_drive <= 0)) return CD_STATUS_EMPTY; + + switch(ioctl_cd_state) + { + case CD_PLAYING: + return CD_STATUS_PLAYING; + case CD_PAUSED: + return CD_STATUS_PAUSED; + case CD_STOPPED: + return CD_STATUS_STOPPED; + } +} +void ioctl_reset() +{ + int fd = open("/dev/cdrom", O_RDONLY|O_NONBLOCK); +//pclog("ioctl_reset: fd=%i\n", fd); + tocvalid = 0; + + if (fd <= 0) + return; + + tocvalid = read_toc(fd, toc); + + close(fd); +} + +int ioctl_open(char d) +{ + atapi=&ioctl_atapi; + return 0; +} + +void ioctl_close(void) +{ +} + +static void ioctl_exit(void) +{ + ioctl_stop(); + ioctl_inited = 0; + tocvalid=0; +} + +static ATAPI ioctl_atapi= +{ + ioctl_ready, + ioctl_medium_changed, + ioctl_readtoc, + ioctl_readtoc_session, + ioctl_readtoc_raw, + ioctl_getcurrentsubchannel, + ioctl_readsector, + ioctl_readsector_raw, + ioctl_playaudio, + ioctl_seek, + ioctl_load, + ioctl_eject, + ioctl_pause, + ioctl_resume, + ioctl_size, + ioctl_status, + ioctl_is_track_audio, + ioctl_stop, + ioctl_exit +}; diff --git a/src/cdrom-ioctl.c b/src/cdrom-ioctl.c new file mode 100644 index 000000000..a7642f5cb --- /dev/null +++ b/src/cdrom-ioctl.c @@ -0,0 +1,747 @@ +/*Win32 CD-ROM support via IOCTL*/ + +#include +#include +#include "ntddcdrm.h" +#include "ibm.h" +#include "ide.h" +#include "cdrom-ioctl.h" + +int cdrom_drive; +int old_cdrom_drive; + +static ATAPI ioctl_atapi; + +static uint32_t last_block = 0; +static uint32_t cdrom_capacity = 0; +static int ioctl_inited = 0; +static char ioctl_path[8]; +void ioctl_close(void); +static HANDLE hIOCTL; +static CDROM_TOC toc; +static int tocvalid = 0; + +// #define MSFtoLBA(m,s,f) (((((m*60)+s)*75)+f)-150) +/* The addresses sent from the guest are absolute, ie. a LBA of 0 corresponds to a MSF of 00:00:00. Otherwise, the counter displayed by the guest is wrong: + there is a seeming 2 seconds in which audio plays but counter does not move, while a data track before audio jumps to 2 seconds before the actual start + of the audio while audio still plays. With an absolute conversion, the counter is fine. */ +#define MSFtoLBA(m,s,f) ((((m*60)+s)*75)+f) + +enum +{ + CD_STOPPED = 0, + CD_PLAYING, + CD_PAUSED +}; + +static int ioctl_cd_state = CD_STOPPED; +static uint32_t ioctl_cd_pos = 0, ioctl_cd_end = 0; + +#define BUF_SIZE 32768 +static int16_t cd_buffer[BUF_SIZE]; +static int cd_buflen = 0; +void ioctl_audio_callback(int16_t *output, int len) +{ + RAW_READ_INFO in; + DWORD count; + +// return; +// pclog("Audio callback %08X %08X %i %i %i %04X %i\n", ioctl_cd_pos, ioctl_cd_end, ioctl_cd_state, cd_buflen, len, cd_buffer[4], GetTickCount()); + if (ioctl_cd_state != CD_PLAYING) + { + memset(output, 0, len * 2); + return; + } + while (cd_buflen < len) + { + if (ioctl_cd_pos < ioctl_cd_end) + { + in.DiskOffset.LowPart = (ioctl_cd_pos - 150) * 2048; + in.DiskOffset.HighPart = 0; + in.SectorCount = 1; + in.TrackMode = CDDA; + ioctl_open(0); +// pclog("Read to %i\n", cd_buflen); + if (!DeviceIoControl(hIOCTL, IOCTL_CDROM_RAW_READ, &in, sizeof(in), &cd_buffer[cd_buflen], 2352, &count, NULL)) + { +// pclog("DeviceIoControl returned false\n"); + memset(&cd_buffer[cd_buflen], 0, (BUF_SIZE - cd_buflen) * 2); + ioctl_cd_state = CD_STOPPED; + cd_buflen = len; + } + else + { +// pclog("DeviceIoControl returned true\n"); + ioctl_cd_pos++; + cd_buflen += (2352 / 2); + } + ioctl_close(); + } + else + { + memset(&cd_buffer[cd_buflen], 0, (BUF_SIZE - cd_buflen) * 2); + ioctl_cd_state = CD_STOPPED; + cd_buflen = len; + } + } + memcpy(output, cd_buffer, len * 2); +// for (c = 0; c < BUF_SIZE - len; c++) +// cd_buffer[c] = cd_buffer[c + cd_buflen]; + memcpy(&cd_buffer[0], &cd_buffer[len], (BUF_SIZE - len) * 2); + cd_buflen -= len; +// pclog("Done %i\n", GetTickCount()); +} + +void ioctl_audio_stop() +{ + ioctl_cd_state = CD_STOPPED; +} + +static int get_track_nr(uint32_t pos) +{ + int c; + int track = 0; + + if (!tocvalid) + return 0; + + for (c = toc.FirstTrack; c < toc.LastTrack; c++) + { + uint32_t track_address = toc.TrackData[c].Address[3] + + (toc.TrackData[c].Address[2] * 75) + + (toc.TrackData[c].Address[1] * 75 * 60); + + if (track_address <= pos) + track = c; + } + return track; +} + +static void ioctl_playaudio(uint32_t pos, uint32_t len, int ismsf) +{ + if (!cdrom_drive) return; + pclog("Play audio - %08X %08X %i\n", pos, len, ismsf); + if (ismsf) + { + int m = (pos >> 16) & 0xff; + int s = (pos >> 8) & 0xff; + int f = pos & 0xff; + pos = MSFtoLBA(m, s, f); + m = (len >> 16) & 0xff; + s = (len >> 8) & 0xff; + f = len & 0xff; + len = MSFtoLBA(m, s, f); + pclog("MSF - pos = %08X len = %08X\n", pos, len); + } + else + len += pos; + ioctl_cd_pos = pos;// + 150; + ioctl_cd_end = len;// + 150; + if (ioctl_cd_pos < 150) + { + /* Adjust because the host expects a minimum adjusted LBA of 0 which is equivalent to an absolute LBA of 150. */ + ioctl_cd_pos = 150; + } + ioctl_cd_state = CD_PLAYING; + pclog("Audio start %08X %08X %i %i %i\n", ioctl_cd_pos, ioctl_cd_end, ioctl_cd_state, cd_buflen, len); +/* CDROM_PLAY_AUDIO_MSF msf; + long size; + BOOL b; + if (ismsf) + { + msf.StartingF=pos&0xFF; + msf.StartingS=(pos>>8)&0xFF; + msf.StartingM=(pos>>16)&0xFF; + msf.EndingF=len&0xFF; + msf.EndingS=(len>>8)&0xFF; + msf.EndingM=(len>>16)&0xFF; + } + else + { + msf.StartingF=(uint8_t)(addr%75); addr/=75; + msf.StartingS=(uint8_t)(addr%60); addr/=60; + msf.StartingM=(uint8_t)(addr); + addr=pos+len+150; + msf.EndingF=(uint8_t)(addr%75); addr/=75; + msf.EndingS=(uint8_t)(addr%60); addr/=60; + msf.EndingM=(uint8_t)(addr); + } + ioctl_open(0); + b = DeviceIoControl(hIOCTL,IOCTL_CDROM_PLAY_AUDIO_MSF,&msf,sizeof(msf),NULL,0,&size,NULL); + pclog("DeviceIoControl returns %i\n", (int) b); + ioctl_close();*/ +} + +static void ioctl_pause(void) +{ + if (!cdrom_drive) return; + if (ioctl_cd_state == CD_PLAYING) + ioctl_cd_state = CD_PAUSED; +// ioctl_open(0); +// DeviceIoControl(hIOCTL,IOCTL_CDROM_PAUSE_AUDIO,NULL,0,NULL,0,&size,NULL); +// ioctl_close(); +} + +static void ioctl_resume(void) +{ + if (!cdrom_drive) return; + if (ioctl_cd_state == CD_PAUSED) + ioctl_cd_state = CD_PLAYING; +// ioctl_open(0); +// DeviceIoControl(hIOCTL,IOCTL_CDROM_RESUME_AUDIO,NULL,0,NULL,0,&size,NULL); +// ioctl_close(); +} + +static void ioctl_stop(void) +{ + if (!cdrom_drive) return; + ioctl_cd_state = CD_STOPPED; +// ioctl_open(0); +// DeviceIoControl(hIOCTL,IOCTL_CDROM_STOP_AUDIO,NULL,0,NULL,0,&size,NULL); +// ioctl_close(); +} + +static void ioctl_seek(uint32_t pos) +{ + if (!cdrom_drive) return; + // ioctl_cd_state = CD_STOPPED; + pclog("Seek %08X\n", pos); + ioctl_cd_pos = pos; + ioctl_cd_state = CD_STOPPED; +/* pos+=150; + CDROM_SEEK_AUDIO_MSF msf; + msf.F=(uint8_t)(pos%75); pos/=75; + msf.S=(uint8_t)(pos%60); pos/=60; + msf.M=(uint8_t)(pos); +// pclog("Seek to %02i:%02i:%02i\n",msf.M,msf.S,msf.F); + ioctl_open(0); + DeviceIoControl(hIOCTL,IOCTL_CDROM_SEEK_AUDIO_MSF,&msf,sizeof(msf),NULL,0,&size,NULL); + ioctl_close();*/ +} + +static int ioctl_ready(void) +{ + long size; + int temp; + CDROM_TOC ltoc; +// pclog("Ready? %i\n",cdrom_drive); + if (!cdrom_drive) return 0; + ioctl_open(0); + temp=DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,<oc,sizeof(ltoc),&size,NULL); + ioctl_close(); + if (!temp) + return 0; + //pclog("ioctl_ready(): Drive opened successfully\n"); + //if ((cdrom_drive != old_cdrom_drive)) pclog("Drive has changed\n"); + if ((ltoc.TrackData[ltoc.LastTrack].Address[1] != toc.TrackData[toc.LastTrack].Address[1]) || + (ltoc.TrackData[ltoc.LastTrack].Address[2] != toc.TrackData[toc.LastTrack].Address[2]) || + (ltoc.TrackData[ltoc.LastTrack].Address[3] != toc.TrackData[toc.LastTrack].Address[3]) || + !tocvalid || (cdrom_drive != old_cdrom_drive)) + { + //pclog("ioctl_ready(): Disc or drive changed\n"); + ioctl_cd_state = CD_STOPPED; + /* pclog("Not ready %02X %02X %02X %02X %02X %02X %i\n",ltoc.TrackData[ltoc.LastTrack].Address[1],ltoc.TrackData[ltoc.LastTrack].Address[2],ltoc.TrackData[ltoc.LastTrack].Address[3], + toc.TrackData[ltoc.LastTrack].Address[1], toc.TrackData[ltoc.LastTrack].Address[2], toc.TrackData[ltoc.LastTrack].Address[3],tocvalid);*/ + // atapi_discchanged(); +/* ioctl_open(0); + temp=DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,&toc,sizeof(toc),&size,NULL); + ioctl_close();*/ + if (cdrom_drive != old_cdrom_drive) + old_cdrom_drive = cdrom_drive; + return 1; + } +// pclog("IOCTL says ready\n"); +// pclog("ioctl_ready(): All is good\n"); + return 1; +} + +static int ioctl_get_last_block(unsigned char starttrack, int msf, int maxlen, int single) +{ + int len=4; + long size; + int c,d; + uint32_t temp; + CDROM_TOC lbtoc; + int lb=0; + if (!cdrom_drive) return 0; + ioctl_cd_state = CD_STOPPED; + pclog("ioctl_readtoc(): IOCtl state now CD_STOPPED\n"); + ioctl_open(0); + DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,&lbtoc,sizeof(lbtoc),&size,NULL); + ioctl_close(); + tocvalid=1; + for (c=d;c<=lbtoc.LastTrack;c++) + { + uint32_t address; + address = MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]); + if (address > lb) + lb = address; + } + return lb; +} + +static int ioctl_medium_changed(void) +{ + long size; + int temp; + CDROM_TOC ltoc; + if (!cdrom_drive) return 0; /* This will be handled by the not ready handler instead. */ + ioctl_open(0); + temp=DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,<oc,sizeof(ltoc),&size,NULL); + ioctl_close(); + if (!temp) + return 0; /* Drive empty, a not ready handler matter, not disc change. */ + if (!tocvalid || (cdrom_drive != old_cdrom_drive)) + { + ioctl_cd_state = CD_STOPPED; + toc = ltoc; + tocvalid = 1; + if (cdrom_drive != old_cdrom_drive) + old_cdrom_drive = cdrom_drive; + cdrom_capacity = ioctl_get_last_block(0, 0, 4096, 0); + return 0; + } + if ((ltoc.TrackData[ltoc.LastTrack].Address[1] != toc.TrackData[toc.LastTrack].Address[1]) || + (ltoc.TrackData[ltoc.LastTrack].Address[2] != toc.TrackData[toc.LastTrack].Address[2]) || + (ltoc.TrackData[ltoc.LastTrack].Address[3] != toc.TrackData[toc.LastTrack].Address[3])) + { + ioctl_cd_state = CD_STOPPED; + toc = ltoc; + cdrom_capacity = ioctl_get_last_block(0, 0, 4096, 0); + return 1; /* TOC mismatches. */ + } + return 0; /* None of the above, return 0. */ +} + +static uint8_t ioctl_getcurrentsubchannel(uint8_t *b, int msf) +{ + CDROM_SUB_Q_DATA_FORMAT insub; + SUB_Q_CHANNEL_DATA sub; + long size; + int pos=0; + if (!cdrom_drive) return 0; + + insub.Format = IOCTL_CDROM_CURRENT_POSITION; + ioctl_open(0); + DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_Q_CHANNEL,&insub,sizeof(insub),&sub,sizeof(sub),&size,NULL); + ioctl_close(); + + if (ioctl_cd_state == CD_PLAYING || ioctl_cd_state == CD_PAUSED) + { + uint32_t cdpos = ioctl_cd_pos; + int track = get_track_nr(cdpos); + uint32_t track_address = toc.TrackData[track].Address[3] + + (toc.TrackData[track].Address[2] * 75) + + (toc.TrackData[track].Address[1] * 75 * 60); + + b[pos++] = sub.CurrentPosition.Control; + b[pos++] = track + 1; + b[pos++] = sub.CurrentPosition.IndexNumber; + + if (msf) + { + uint32_t dat = cdpos; + b[pos + 3] = (uint8_t)(dat % 75); dat /= 75; + b[pos + 2] = (uint8_t)(dat % 60); dat /= 60; + b[pos + 1] = (uint8_t)dat; + b[pos] = 0; + pos += 4; + dat = cdpos - track_address; + b[pos + 3] = (uint8_t)(dat % 75); dat /= 75; + b[pos + 2] = (uint8_t)(dat % 60); dat /= 60; + b[pos + 1] = (uint8_t)dat; + b[pos] = 0; + pos += 4; + } + else + { + b[pos++] = (cdpos >> 24) & 0xff; + b[pos++] = (cdpos >> 16) & 0xff; + b[pos++] = (cdpos >> 8) & 0xff; + b[pos++] = cdpos & 0xff; + cdpos -= track_address; + b[pos++] = (cdpos >> 24) & 0xff; + b[pos++] = (cdpos >> 16) & 0xff; + b[pos++] = (cdpos >> 8) & 0xff; + b[pos++] = cdpos & 0xff; + } + + if (ioctl_cd_state == CD_PLAYING) return 0x11; + return 0x12; + } + + b[pos++]=sub.CurrentPosition.Control; + b[pos++]=sub.CurrentPosition.TrackNumber; + b[pos++]=sub.CurrentPosition.IndexNumber; + + if (msf) + { + int c; + for (c = 0; c < 4; c++) + b[pos++] = sub.CurrentPosition.AbsoluteAddress[c]; + for (c = 0; c < 4; c++) + b[pos++] = sub.CurrentPosition.TrackRelativeAddress[c]; + } + else + { + uint32_t temp = MSFtoLBA(sub.CurrentPosition.AbsoluteAddress[1], sub.CurrentPosition.AbsoluteAddress[2], sub.CurrentPosition.AbsoluteAddress[3]); + b[pos++] = temp >> 24; + b[pos++] = temp >> 16; + b[pos++] = temp >> 8; + b[pos++] = temp; + temp = MSFtoLBA(sub.CurrentPosition.TrackRelativeAddress[1], sub.CurrentPosition.TrackRelativeAddress[2], sub.CurrentPosition.TrackRelativeAddress[3]); + b[pos++] = temp >> 24; + b[pos++] = temp >> 16; + b[pos++] = temp >> 8; + b[pos++] = temp; + } + + return 0x13; +} + +static void ioctl_eject(void) +{ + long size; + if (!cdrom_drive) return; + ioctl_cd_state = CD_STOPPED; + ioctl_open(0); + DeviceIoControl(hIOCTL,IOCTL_STORAGE_EJECT_MEDIA,NULL,0,NULL,0,&size,NULL); + ioctl_close(); +} + +static void ioctl_load(void) +{ + long size; + if (!cdrom_drive) return; + ioctl_cd_state = CD_STOPPED; + ioctl_open(0); + DeviceIoControl(hIOCTL,IOCTL_STORAGE_LOAD_MEDIA,NULL,0,NULL,0,&size,NULL); + ioctl_close(); + cdrom_capacity = ioctl_get_last_block(0, 0, 4096, 0); +} + +static void ioctl_readsector(uint8_t *b, int sector) +{ + LARGE_INTEGER pos; + long size; + if (!cdrom_drive) return; + + if (ioctl_cd_state == CD_PLAYING) + return; + + ioctl_cd_state = CD_STOPPED; + pos.QuadPart=sector*2048; + ioctl_open(0); + SetFilePointer(hIOCTL,pos.LowPart,&pos.HighPart,FILE_BEGIN); + ReadFile(hIOCTL,b,2048,&size,NULL); + ioctl_close(); +} + +static int is_track_audio(uint32_t pos) +{ + int c; + int control = 0; + + if (!tocvalid) + return 0; + + for (c = toc.FirstTrack; c < toc.LastTrack; c++) + { + uint32_t track_address = toc.TrackData[c].Address[3] + + (toc.TrackData[c].Address[2] * 75) + + (toc.TrackData[c].Address[1] * 75 * 60); + + if (track_address <= pos) + control = toc.TrackData[c].Control; + } + return (control & 4) ? 0 : 1; +} + +static int ioctl_is_track_audio(uint32_t pos, int ismsf) +{ + if (ismsf) + { + int m = (pos >> 16) & 0xff; + int s = (pos >> 8) & 0xff; + int f = pos & 0xff; + pos = MSFtoLBA(m, s, f); + } + return is_track_audio(pos); +} + +static void ioctl_readsector_raw(uint8_t *b, int sector) +{ + LARGE_INTEGER pos; + long size; + uint32_t temp; + if (!cdrom_drive) return; + if (ioctl_cd_state == CD_PLAYING) + return; + + ioctl_cd_state = CD_STOPPED; + pos.QuadPart=sector*2048; /* Yes, 2048, the API specifies that. */ + ioctl_open(0); + /* This should read the actual raw sectors from the disc. */ + DeviceIoControl( hIOCTL, IOCTL_CDROM_RAW_READ, NULL, 0, b, 1, &size, NULL ); + ioctl_close(); +} + +static int ioctl_readtoc(unsigned char *b, unsigned char starttrack, int msf, int maxlen, int single) +{ + int len=4; + long size; + int c,d; + uint32_t temp; + if (!cdrom_drive) return 0; + ioctl_cd_state = CD_STOPPED; + ioctl_open(0); + DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC, NULL,0,&toc,sizeof(toc),&size,NULL); + ioctl_close(); + tocvalid=1; +// pclog("Read TOC done! %i\n",single); + b[2]=toc.FirstTrack; + b[3]=toc.LastTrack; + d=0; + for (c=0;c<=toc.LastTrack;c++) + { + if (toc.TrackData[c].TrackNumber>=starttrack) + { + d=c; + break; + } + } + b[2]=toc.TrackData[c].TrackNumber; + last_block = 0; + for (c=d;c<=toc.LastTrack;c++) + { + uint32_t address; + if ((len+8)>maxlen) break; +// pclog("Len %i max %i Track %02X - %02X %02X %i %i %i %i %08X\n",len,maxlen,toc.TrackData[c].TrackNumber,toc.TrackData[c].Adr,toc.TrackData[c].Control,toc.TrackData[c].Address[0],toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3],MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3])); + b[len++]=0; /*Reserved*/ + b[len++]=(toc.TrackData[c].Adr<<4)|toc.TrackData[c].Control; + b[len++]=toc.TrackData[c].TrackNumber; + b[len++]=0; /*Reserved*/ + address = MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]); + if (address > last_block) + last_block = address; + + if (msf) + { + b[len++]=toc.TrackData[c].Address[0]; + b[len++]=toc.TrackData[c].Address[1]; + b[len++]=toc.TrackData[c].Address[2]; + b[len++]=toc.TrackData[c].Address[3]; + } + else + { + temp=MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]); + b[len++]=temp>>24; + b[len++]=temp>>16; + b[len++]=temp>>8; + b[len++]=temp; + } + if (single) break; + } + b[0] = (uint8_t)(((len-2) >> 8) & 0xff); + b[1] = (uint8_t)((len-2) & 0xff); +/* pclog("Table of Contents (%i bytes) : \n",size); + pclog("First track - %02X\n",toc.FirstTrack); + pclog("Last track - %02X\n",toc.LastTrack); + for (c=0;c<=toc.LastTrack;c++) + pclog("Track %02X - number %02X control %02X adr %02X address %02X %02X %02X %02X\n",c,toc.TrackData[c].TrackNumber,toc.TrackData[c].Control,toc.TrackData[c].Adr,toc.TrackData[c].Address[0],toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]); + for (c=0;c<=toc.LastTrack;c++) + pclog("Track %02X - number %02X control %02X adr %02X address %06X\n",c,toc.TrackData[c].TrackNumber,toc.TrackData[c].Control,toc.TrackData[c].Adr,MSFtoLBA(toc.TrackData[c].Address[1],toc.TrackData[c].Address[2],toc.TrackData[c].Address[3]));*/ + return len; +} + +static int ioctl_readtoc_session(unsigned char *b, int msf, int maxlen) +{ + int len=4; + int size; + uint32_t temp; + CDROM_READ_TOC_EX toc_ex; + CDROM_TOC_SESSION_DATA toc; + if (!cdrom_drive) return 0; + ioctl_cd_state = CD_STOPPED; + memset(&toc_ex,0,sizeof(toc_ex)); + memset(&toc,0,sizeof(toc)); + toc_ex.Format=CDROM_READ_TOC_EX_FORMAT_SESSION; + toc_ex.Msf=msf; + toc_ex.SessionTrack=0; + ioctl_open(0); + DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC_EX, &toc_ex,sizeof(toc_ex),&toc,sizeof(toc),(PDWORD)&size,NULL); + ioctl_close(); +// pclog("Read TOC session - %i %02X %02X %i %i %02X %02X %02X\n",size,toc.Length[0],toc.Length[1],toc.FirstCompleteSession,toc.LastCompleteSession,toc.TrackData[0].Adr,toc.TrackData[0].Control,toc.TrackData[0].TrackNumber); + b[2]=toc.FirstCompleteSession; + b[3]=toc.LastCompleteSession; + b[len++]=0; /*Reserved*/ + b[len++]=(toc.TrackData[0].Adr<<4)|toc.TrackData[0].Control; + b[len++]=toc.TrackData[0].TrackNumber; + b[len++]=0; /*Reserved*/ + if (msf) + { + b[len++]=toc.TrackData[0].Address[0]; + b[len++]=toc.TrackData[0].Address[1]; + b[len++]=toc.TrackData[0].Address[2]; + b[len++]=toc.TrackData[0].Address[3]; + } + else + { + temp=MSFtoLBA(toc.TrackData[0].Address[1],toc.TrackData[0].Address[2],toc.TrackData[0].Address[3]); + b[len++]=temp>>24; + b[len++]=temp>>16; + b[len++]=temp>>8; + b[len++]=temp; + } + + return len; +} + +static int ioctl_readtoc_raw(unsigned char *b, int maxlen) +{ + int len=4; + int size; + uint32_t temp; + int i; + int BytesRead = 0; + CDROM_READ_TOC_EX toc_ex; + CDROM_TOC_FULL_TOC_DATA toc; + if (!cdrom_drive) return 0; + ioctl_cd_state = CD_STOPPED; + memset(&toc_ex,0,sizeof(toc_ex)); + memset(&toc,0,sizeof(toc)); + toc_ex.Format=CDROM_READ_TOC_EX_FORMAT_FULL_TOC; + toc_ex.Msf=1; + toc_ex.SessionTrack=0; + ioctl_open(0); + DeviceIoControl(hIOCTL,IOCTL_CDROM_READ_TOC_EX, &toc_ex,sizeof(toc_ex),&toc,sizeof(toc),(PDWORD)&size,NULL); + ioctl_close(); +// pclog("Read TOC session - %i %02X %02X %i %i %02X %02X %02X\n",size,toc.Length[0],toc.Length[1],toc.FirstCompleteSession,toc.LastCompleteSession,toc.TrackData[0].Adr,toc.TrackData[0].Control,toc.TrackData[0].TrackNumber); + b[2]=toc.FirstCompleteSession; + b[3]=toc.LastCompleteSession; + + size -= sizeof(CDROM_TOC_FULL_TOC_DATA); + size /= sizeof(toc.Descriptors[0]); + + for (i = 0; i <= size; i++) + { + b[len++]=toc.Descriptors[i].SessionNumber; + b[len++]=(toc.Descriptors[i].Adr<<4)|toc.Descriptors[i].Control; + b[len++]=0; + b[len++]=toc.Descriptors[i].Reserved1; /*Reserved*/ + b[len++]=toc.Descriptors[i].MsfExtra[0]; + b[len++]=toc.Descriptors[i].MsfExtra[1]; + b[len++]=toc.Descriptors[i].MsfExtra[2]; + b[len++]=toc.Descriptors[i].Zero; + b[len++]=toc.Descriptors[i].Msf[0]; + b[len++]=toc.Descriptors[i].Msf[1]; + b[len++]=toc.Descriptors[i].Msf[2]; + } + + return len; +} + +static uint32_t ioctl_size() +{ + return cdrom_capacity; +} + +static int ioctl_status() +{ + if (!(ioctl_ready) && (cdrom_drive <= 0)) + return CD_STATUS_EMPTY; + + switch(ioctl_cd_state) + { + case CD_PLAYING: + return CD_STATUS_PLAYING; + case CD_PAUSED: + return CD_STATUS_PAUSED; + case CD_STOPPED: + return CD_STATUS_STOPPED; + } +} + +void ioctl_reset() +{ + CDROM_TOC ltoc; + int temp; + long size; + + if (!cdrom_drive) + { + tocvalid = 0; + return; + } + + ioctl_open(0); + temp = DeviceIoControl(hIOCTL, IOCTL_CDROM_READ_TOC, NULL, 0, <oc, sizeof(ltoc), &size, NULL); + ioctl_close(); + + toc = ltoc; + tocvalid = 1; +} + +int ioctl_open(char d) +{ +// char s[8]; + if (!ioctl_inited) + { + sprintf(ioctl_path,"\\\\.\\%c:",d); + pclog("Path is %s\n",ioctl_path); + tocvalid=0; + } +// pclog("Opening %s\n",ioctl_path); + hIOCTL = CreateFile(/*"\\\\.\\g:"*/ioctl_path,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,0,NULL); + if (!hIOCTL) + { + //fatal("IOCTL"); + } + atapi=&ioctl_atapi; + if (!ioctl_inited) + { + ioctl_inited=1; + CloseHandle(hIOCTL); + hIOCTL = NULL; + } + return 0; +} + +void ioctl_close(void) +{ + if (hIOCTL) + { + CloseHandle(hIOCTL); + hIOCTL = NULL; + } +} + +static void ioctl_exit(void) +{ + ioctl_stop(); + ioctl_inited=0; + tocvalid=0; +} + +static ATAPI ioctl_atapi= +{ + ioctl_ready, + ioctl_medium_changed, + ioctl_readtoc, + ioctl_readtoc_session, + ioctl_readtoc_raw, + ioctl_getcurrentsubchannel, + ioctl_readsector, + ioctl_readsector_raw, + ioctl_playaudio, + ioctl_seek, + ioctl_load, + ioctl_eject, + ioctl_pause, + ioctl_resume, + ioctl_size, + ioctl_status, + ioctl_is_track_audio, + ioctl_stop, + ioctl_exit +}; diff --git a/src/cdrom-ioctl.h b/src/cdrom-ioctl.h new file mode 100644 index 000000000..4d7ca2ff3 --- /dev/null +++ b/src/cdrom-ioctl.h @@ -0,0 +1,12 @@ +#ifndef CDROM_IOCTL_H +#define CDROM_IOCTL_H + +/* this header file lists the functions provided by + various platform specific cdrom-ioctl files */ + +extern int ioctl_open(char d); +extern void ioctl_reset(); + +extern void ioctl_close(void); + +#endif /* ! CDROM_IOCTL_H */ diff --git a/src/cdrom-iso.c b/src/cdrom-iso.c new file mode 100644 index 000000000..4a46f0507 --- /dev/null +++ b/src/cdrom-iso.c @@ -0,0 +1,396 @@ +/*ISO CD-ROM support*/ + +#include "ibm.h" +#include "ide.h" +#include "cdrom-iso.h" +#include + +static ATAPI iso_atapi; + +static uint32_t last_block = 0; +static uint64_t image_size = 0; +static int iso_inited = 0; +char iso_path[1024]; +void iso_close(void); +static FILE* iso_image; +static int iso_changed = 0; + +static uint32_t iso_cd_pos = 0, iso_cd_end = 0; + +void iso_audio_callback(int16_t *output, int len) +{ + memset(output, 0, len * 2); + return; +} + +void iso_audio_stop() +{ + pclog("iso_audio_stop stub\n"); +} + +static int get_track_nr(uint32_t pos) +{ + pclog("get_track_nr stub\n"); + return 0; +} + +static void iso_playaudio(uint32_t pos, uint32_t len, int ismsf) +{ + pclog("iso_playaudio stub\n"); + return; +} + +static void iso_pause(void) +{ + pclog("iso_pause stub\n"); + return; +} + +static void iso_resume(void) +{ + pclog("iso_resume stub\n"); + return; +} + +static void iso_stop(void) +{ + pclog("iso_stop stub\n"); + return; +} + +static void iso_seek(uint32_t pos) +{ + pclog("iso_seek stub\n"); + return; +} + +static int iso_ready(void) +{ + if (strlen(iso_path) == 0) + { + return 0; + } + if (old_cdrom_drive != cdrom_drive) + { + // old_cdrom_drive = cdrom_drive; + return 1; + } + + if (iso_changed) + { + iso_changed = 0; + return 1; + } + + return 1; +} + +/* Always return 0, because there is no way to change the ISO without unmounting and remounting it. */ +static int iso_medium_changed(void) +{ + if (strlen(iso_path) == 0) + { + return 0; + } + if (old_cdrom_drive != cdrom_drive) + { + old_cdrom_drive = cdrom_drive; + return 0; + } + + if (iso_changed) + { + iso_changed = 0; + return 0; + } + + return 0; +} + +static uint8_t iso_getcurrentsubchannel(uint8_t *b, int msf) +{ + pclog("iso_getcurrentsubchannel stub\n"); + return 0; +} + +static void iso_eject(void) +{ + pclog("iso_eject stub\n"); +} + +static void iso_load(void) +{ + pclog("iso_load stub\n"); +} + +static void iso_readsector(uint8_t *b, int sector) +{ + if (!cdrom_drive) return; + iso_image = fopen(iso_path, "rb"); + fseek(iso_image,sector*2048,SEEK_SET); + fread(b,2048,1,iso_image); + fclose(iso_image); +} + +static void lba_to_msf(uint8_t *buf, int lba) +{ + double dlba = (double) lba + 150; + buf[2] = (uint8_t) (((uint32_t) dlba) % 75); + dlba /= 75; + buf[1] = (uint8_t) (((uint32_t) dlba) % 60); + dlba /= 60; + buf[0] = (uint8_t) dlba; +} + +#if 0 +static void lba_to_msf(uint8_t *buf, int lba) +{ + lba += 150; + buf[0] = (lba / 75) / 60; + buf[1] = (lba / 75) % 60; + buf[2] = lba % 75; +} +#endif + +static void iso_readsector_raw(uint8_t *b, int sector) +{ + uint32_t temp; + if (!cdrom_drive) return; + iso_image = fopen(iso_path, "rb"); + fseek(iso_image, sector*2048, SEEK_SET); + fread(b+16, 2048, 1, iso_image); + fclose(iso_image); + + /* sync bytes */ + b[0] = 0; + memset(b + 1, 0xff, 10); + b[11] = 0; + b += 12; + lba_to_msf(b, sector); + b[3] = 1; /* mode 1 data */ + b += 4; + b += 2048; + memset(b, 0, 288); +} + +static int iso_readtoc(unsigned char *buf, unsigned char start_track, int msf, int maxlen, int single) +{ + uint8_t *q; + int len; + + if (start_track > 1 && start_track != 0xaa) + return -1; + q = buf + 2; + *q++ = 1; /* first session */ + *q++ = 1; /* last session */ + if (start_track <= 1) { + *q++ = 0; /* reserved */ + *q++ = 0x14; /* ADR, control */ + *q++ = 1; /* track number */ + *q++ = 0; /* reserved */ + if (msf) { + *q++ = 0; /* reserved */ + lba_to_msf(q, 0); + q += 3; + } else { + /* sector 0 */ + *q++ = 0; + *q++ = 0; + *q++ = 0; + *q++ = 0; + } + } + /* lead out track */ + *q++ = 0; /* reserved */ + *q++ = 0x16; /* ADR, control */ + *q++ = 0xaa; /* track number */ + *q++ = 0; /* reserved */ + last_block = image_size >> 11; + if (msf) { + *q++ = 0; /* reserved */ + lba_to_msf(q, last_block); + q += 3; + } else { + *q++ = last_block >> 24; + *q++ = last_block >> 16; + *q++ = last_block >> 8; + *q++ = last_block; + } + len = q - buf; + buf[0] = (uint8_t)(((len-2) >> 8) & 0xff); + buf[1] = (uint8_t)((len-2) & 0xff); + return len; +} + +static int iso_readtoc_session(unsigned char *buf, int msf, int maxlen) +{ + uint8_t *q; + + q = buf + 2; + *q++ = 1; /* first session */ + *q++ = 1; /* last session */ + + *q++ = 1; /* session number */ + *q++ = 0x14; /* data track */ + *q++ = 0; /* track number */ + *q++ = 0xa0; /* lead-in */ + *q++ = 0; /* min */ + *q++ = 0; /* sec */ + *q++ = 0; /* frame */ + *q++ = 0; + + return 12; +} + +static int iso_readtoc_raw(unsigned char *buf, int maxlen) +{ + uint8_t *q; + int len; + + q = buf + 2; + *q++ = 1; /* first session */ + *q++ = 1; /* last session */ + + *q++ = 1; /* session number */ + *q++ = 0x14; /* data track */ + *q++ = 0; /* track number */ + *q++ = 0xa0; /* lead-in */ + *q++ = 0; /* min */ + *q++ = 0; /* sec */ + *q++ = 0; /* frame */ + *q++ = 0; + *q++ = 1; /* first track */ + *q++ = 0x00; /* disk type */ + *q++ = 0x00; + + *q++ = 1; /* session number */ + *q++ = 0x14; /* data track */ + *q++ = 0; /* track number */ + *q++ = 0xa1; + *q++ = 0; /* min */ + *q++ = 0; /* sec */ + *q++ = 0; /* frame */ + *q++ = 0; + *q++ = 1; /* last track */ + *q++ = 0x00; + *q++ = 0x00; + + *q++ = 1; /* session number */ + *q++ = 0x14; /* data track */ + *q++ = 0; /* track number */ + *q++ = 0xa2; /* lead-out */ + *q++ = 0; /* min */ + *q++ = 0; /* sec */ + *q++ = 0; /* frame */ + last_block = image_size >> 11; + /* this is raw, must be msf */ + *q++ = 0; /* reserved */ + lba_to_msf(q, last_block); + q += 3; + + *q++ = 1; /* session number */ + *q++ = 0x14; /* ADR, control */ + *q++ = 0; /* track number */ + *q++ = 1; /* point */ + *q++ = 0; /* min */ + *q++ = 0; /* sec */ + *q++ = 0; /* frame */ + /* same here */ + *q++ = 0; + *q++ = 0; + *q++ = 0; + *q++ = 0; + + len = q - buf; + buf[0] = (uint8_t)(((len-2) >> 8) & 0xff); + buf[1] = (uint8_t)((len-2) & 0xff); + return len; +} + +static uint32_t iso_size() +{ + unsigned char b[4096]; + + atapi->readtoc(b, 0, 0, 4096, 0); + + return last_block; +} + +static int iso_status() +{ + if (!(iso_ready()) && (cdrom_drive != 200)) return CD_STATUS_EMPTY; + + return CD_STATUS_DATA_ONLY; +} + +void iso_reset() +{ +} + +int iso_open(char *fn) +{ + if (strcmp(fn, iso_path) != 0) + { + iso_changed = 1; + } + /* Make sure iso_changed stays when changing from ISO to another ISO. */ + if (!iso_inited && (cdrom_drive != 200)) iso_changed = 0; + if (!iso_inited || iso_changed) + { + sprintf(iso_path, "%s", fn); + pclog("Path is %s\n", iso_path); + } + iso_image = fopen(iso_path, "rb"); + atapi = &iso_atapi; + if (!iso_inited || iso_changed) + { + if (!iso_inited) iso_inited = 1; + fclose(iso_image); + } + + struct stat st; + stat(iso_path, &st); + image_size = st.st_size; + + return 0; +} + +void iso_close(void) +{ + if (iso_image) fclose(iso_image); + memset(iso_path, 0, 1024); +} + +static void iso_exit(void) +{ + // iso_stop(); + iso_inited = 0; +} + +static int iso_is_track_audio(uint32_t pos, int ismsf) +{ + return 0; +} + +static ATAPI iso_atapi = +{ + iso_ready, + iso_medium_changed, + iso_readtoc, + iso_readtoc_session, + iso_readtoc_raw, + iso_getcurrentsubchannel, + iso_readsector, + iso_readsector_raw, + iso_playaudio, + iso_seek, + iso_load, + iso_eject, + iso_pause, + iso_resume, + iso_size, + iso_status, + iso_is_track_audio, + iso_stop, + iso_exit +}; diff --git a/src/cdrom-iso.h b/src/cdrom-iso.h new file mode 100644 index 000000000..3ff743486 --- /dev/null +++ b/src/cdrom-iso.h @@ -0,0 +1,14 @@ +#ifndef CDROM_ISO_H +#define CDROM_ISO_H + +/* this header file lists the functions provided by + various platform specific cdrom-ioctl files */ + +extern char iso_path[1024]; + +extern int iso_open(char *fn); +extern void iso_reset(); + +extern void iso_close(void); + +#endif /* ! CDROM_ISO_H */ diff --git a/src/cdrom-null.c b/src/cdrom-null.c new file mode 100644 index 000000000..dc2c02a2c --- /dev/null +++ b/src/cdrom-null.c @@ -0,0 +1,139 @@ +#include "ibm.h" +#include "ide.h" +#include "cdrom-ioctl.h" + +int cdrom_drive; + +static ATAPI null_atapi; + +void cdrom_null_audio_callback(int16_t *output, int len) +{ + memset(output, 0, len * 2); +} + +void cdrom_null_audio_stop() +{ +} + +static void null_playaudio(uint32_t pos, uint32_t len, int ismsf) +{ +} + +static void null_pause(void) +{ +} + +static void null_resume(void) +{ +} + +static void null_stop(void) +{ +} + +static void null_seek(uint32_t pos) +{ +} + +static int null_ready(void) +{ + return 0; +} + +/* Always return 0, the contents of a null CD-ROM drive never change. */ +static int null_medium_changed(void) +{ + return 0; +} + +static uint8_t null_getcurrentsubchannel(uint8_t *b, int msf) +{ + return 0x13; +} + +static void null_eject(void) +{ +} + +static void null_load(void) +{ +} + +static void null_readsector(uint8_t *b, int sector) +{ +} + +static void null_readsector_raw(uint8_t *b, int sector) +{ +} + +static int null_readtoc(unsigned char *b, unsigned char starttrack, int msf, int maxlen, int single) +{ + return 0; +} + +static int null_readtoc_session(unsigned char *b, int msf, int maxlen) +{ + return 0; +} + +static int null_readtoc_raw(unsigned char *b, int maxlen) +{ + return 0; +} + +static uint32_t null_size() +{ + return 0; +} + +static int null_status() +{ + return CD_STATUS_EMPTY; +} + +void cdrom_null_reset() +{ +} + +int cdrom_null_open(char d) +{ + atapi = &null_atapi; + return 0; +} + +void null_close(void) +{ +} + +static void null_exit(void) +{ +} + +static int null_is_track_audio(uint32_t pos, int ismsf) +{ + return 0; +} + +static ATAPI null_atapi = +{ + null_ready, + null_medium_changed, + null_readtoc, + null_readtoc_session, + null_readtoc_raw, + null_getcurrentsubchannel, + null_readsector, + null_readsector_raw, + null_playaudio, + null_seek, + null_load, + null_eject, + null_pause, + null_resume, + null_size, + null_status, + null_is_track_audio, + null_stop, + null_exit +}; diff --git a/src/cdrom-null.h b/src/cdrom-null.h new file mode 100644 index 000000000..007e86478 --- /dev/null +++ b/src/cdrom-null.h @@ -0,0 +1,11 @@ +#ifndef CDROM_IOCTL_H +#define CDROM_IOCTL_H + +/* this header file lists the functions provided by + various platform specific cdrom-ioctl files */ + +extern int cdrom_null_open(char d); +extern void cdrom_null_reset(); +extern void null_close(); + +#endif /* ! CDROM_IOCTL_H */ diff --git a/src/codegen.c b/src/codegen.c new file mode 100644 index 000000000..5667c9bad --- /dev/null +++ b/src/codegen.c @@ -0,0 +1,21 @@ +#include "ibm.h" +#include "x86_ops.h" +#include "mem.h" +#include "codegen.h" + +void (*codegen_timing_start)(); +void (*codegen_timing_prefix)(uint8_t prefix, uint32_t fetchdat); +void (*codegen_timing_opcode)(uint8_t opcode, uint32_t fetchdat, int op_32); +void (*codegen_timing_block_start)(); +void (*codegen_timing_block_end)(); + +void codegen_timing_set(codegen_timing_t *timing) +{ + codegen_timing_start = timing->start; + codegen_timing_prefix = timing->prefix; + codegen_timing_opcode = timing->opcode; + codegen_timing_block_start = timing->block_start; + codegen_timing_block_end = timing->block_end; +} + +int codegen_in_recompile; diff --git a/src/codegen.h b/src/codegen.h new file mode 100644 index 000000000..b9a53c887 --- /dev/null +++ b/src/codegen.h @@ -0,0 +1,340 @@ +#include "mem.h" + +#ifdef __amd64__ +#include "codegen_x86-64.h" +#elif defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 +#include "codegen_x86.h" +#else +#error Dynamic recompiler not implemented on your platform +#endif + +/*Handling self-modifying code (of which there is a lot on x86) : + + PCem tracks a 'dirty mask' for each physical page, in which each bit + represents 64 bytes. This is only tracked for pages that have code in - when a + page first has a codeblock generated, it is evicted from the writelookup and + added to the page_lookup for this purpose. When in the page_lookup, each write + will go through the mem_write_ram*_page() functions and set the dirty mask + appropriately. + + Each codeblock also contains a code mask (actually two masks, one for each + page the block is/may be in), again with each bit representing 64 bytes. + + Each page has a list of codeblocks present in it. As each codeblock can span + up to two pages, two lists are present. + + When a codeblock is about to be executed, the code masks are compared with the + dirty masks for the relevant pages. If either intersect, then + codegen_check_flush() is called on the affected page(s), and all affected + blocks are evicted. + + The 64 byte granularity appears to work reasonably well for most cases, + avoiding most unnecessary evictions (eg when code & data are stored in the + same page). +*/ + +typedef struct codeblock_t +{ + /*Previous and next pointers, for the codeblock list associated with + each physical page. Two sets of pointers, as a codeblock can be + present in two pages.*/ + struct codeblock_t *prev, *next; + struct codeblock_t *prev_2, *next_2; + + /*Pointers for codeblock tree, used to search for blocks when hash lookup + fails.*/ + struct codeblock_t *parent, *left, *right; + + uint32_t pc; + uint32_t _cs; + uint32_t endpc; + uint32_t phys, phys_2; + uint32_t use32; + int stack32; + int pnt; + int ins; + uint64_t page_mask, page_mask2; + + uint8_t data[2048]; +} codeblock_t; + +static inline codeblock_t *codeblock_tree_find(uint32_t phys) +{ + codeblock_t *block = pages[phys >> 12].head; + + while (block) + { + if (phys == block->phys) + break; + else if (phys < block->phys) + block = block->left; + else + block = block->right; + } + + return block; +} + +static inline void codeblock_tree_add(codeblock_t *new_block) +{ + codeblock_t *block = pages[new_block->phys >> 12].head; + + if (!block) + { + pages[new_block->phys >> 12].head = new_block; + new_block->parent = new_block->left = new_block->right = NULL; + } + else + { + codeblock_t *old_block = NULL; + while (block) + { + old_block = block; + + if (new_block->phys < old_block->phys) + block = block->left; + else + block = block->right; + } + + if (new_block->phys < old_block->phys) + old_block->left = new_block; + else + old_block->right = new_block; + + new_block->parent = old_block; + new_block->left = new_block->right = NULL; + } +} + +static inline void codeblock_tree_delete(codeblock_t *block) +{ + codeblock_t *parent = block->parent; + + if (!block->left && !block->right) + { + /*Easy case - remove from parent*/ + if (!parent) + pages[block->phys >> 12].head = NULL; + else + { + if (parent->left == block) + parent->left = NULL; + if (parent->right == block) + parent->right = NULL; + } + return; + } + else if (!block->left) + { + /*Only right node*/ + if (!parent) + { + pages[block->phys >> 12].head = block->right; + pages[block->phys >> 12].head->parent = NULL; + } + else + { + if (parent->left == block) + { + parent->left = block->right; + parent->left->parent = parent; + } + if (parent->right == block) + { + parent->right = block->right; + parent->right->parent = parent; + } + } + return; + } + else if (!block->right) + { + /*Only left node*/ + if (!parent) + { + pages[block->phys >> 12].head = block->left; + pages[block->phys >> 12].head->parent = NULL; + } + else + { + if (parent->left == block) + { + parent->left = block->left; + parent->left->parent = parent; + } + if (parent->right == block) + { + parent->right = block->left; + parent->right->parent = parent; + } + } + return; + } + else + { + /*Difficult case - node has two children. Walk right child to find lowest node*/ + codeblock_t *lowest = block->right, *highest; + codeblock_t *old_parent; + + while (lowest->left) + lowest = lowest->left; + + old_parent = lowest->parent; + + /*Replace deleted node with lowest node*/ + if (!parent) + pages[block->phys >> 12].head = lowest; + else + { + if (parent->left == block) + parent->left = lowest; + if (parent->right == block) + parent->right = lowest; + } + + lowest->parent = parent; + lowest->left = block->left; + if (lowest->left) + lowest->left->parent = lowest; + + old_parent->left = NULL; + + highest = lowest->right; + if (!highest) + { + if (lowest != block->right) + { + lowest->right = block->right; + block->right->parent = lowest; + } + return; + } + + while (highest->right) + highest = highest->right; + + if (block->right && block->right != lowest) + { + highest->right = block->right; + block->right->parent = highest; + } + } +} + +#define PAGE_MASK_MASK 63 +#define PAGE_MASK_SHIFT 6 + +extern codeblock_t *codeblock; + +extern codeblock_t **codeblock_hash; + +void codegen_init(); +void codegen_reset(); +void codegen_block_init(uint32_t phys_addr); +void codegen_block_remove(); +void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_pc, uint32_t old_pc); +void codegen_generate_seg_restore(); +void codegen_check_abrt(); +void codegen_set_op32(); +void codegen_flush(); +void codegen_check_flush(struct page_t *page, uint64_t mask, uint32_t phys_addr); + +extern int cpu_block_end; + +extern int cpu_recomp_blocks, cpu_recomp_ins, cpu_recomp_full_ins, cpu_new_blocks; +extern int cpu_recomp_blocks_latched, cpu_recomp_ins_latched, cpu_recomp_full_ins_latched, cpu_new_blocks_latched; +extern int cpu_recomp_flushes, cpu_recomp_flushes_latched; +extern int cpu_recomp_evicted, cpu_recomp_evicted_latched; +extern int cpu_recomp_reuse, cpu_recomp_reuse_latched; +extern int cpu_recomp_removed, cpu_recomp_removed_latched; + +extern int cpu_reps, cpu_reps_latched; +extern int cpu_notreps, cpu_notreps_latched; + +extern int codegen_block_cycles; + +extern void (*codegen_timing_start)(); +extern void (*codegen_timing_prefix)(uint8_t prefix, uint32_t fetchdat); +extern void (*codegen_timing_opcode)(uint8_t opcode, uint32_t fetchdat, int op_32); +extern void (*codegen_timing_block_start)(); +extern void (*codegen_timing_block_end)(); + +typedef struct codegen_timing_t +{ + void (*start)(); + void (*prefix)(uint8_t prefix, uint32_t fetchdat); + void (*opcode)(uint8_t opcode, uint32_t fetchdat, int op_32); + void (*block_start)(); + void (*block_end)(); +} codegen_timing_t; + +extern codegen_timing_t codegen_timing_pentium; +extern codegen_timing_t codegen_timing_686; +extern codegen_timing_t codegen_timing_486; +extern codegen_timing_t codegen_timing_winchip; + +void codegen_timing_set(codegen_timing_t *timing); + +extern int block_current; +extern int block_pos; + +#define CPU_BLOCK_END() cpu_block_end = 1 + +static inline void addbyte(uint8_t val) +{ + codeblock[block_current].data[block_pos++] = val; + if (block_pos >= 1760) + { + CPU_BLOCK_END(); + } +} + +static inline void addword(uint16_t val) +{ + *(uint16_t *)&codeblock[block_current].data[block_pos] = val; + block_pos += 2; + if (block_pos >= 1720) + { + CPU_BLOCK_END(); + } +} + +static inline void addlong(uint32_t val) +{ + *(uint32_t *)&codeblock[block_current].data[block_pos] = val; + block_pos += 4; + if (block_pos >= 1720) + { + CPU_BLOCK_END(); + } +} + +static inline void addquad(uint64_t val) +{ + *(uint64_t *)&codeblock[block_current].data[block_pos] = val; + block_pos += 8; + if (block_pos >= 1720) + { + CPU_BLOCK_END(); + } +} + +/*Current physical page of block being recompiled. -1 if no recompilation taking place */ +extern uint32_t recomp_page; + +extern x86seg *op_ea_seg; +extern int op_ssegs; +extern uint32_t op_old_pc; + +/*Set to 1 if flags have been changed in the block being recompiled, and hence + flags_op is known and can be relied on */ +extern int codegen_flags_changed; + +extern int codegen_fpu_entered; +extern int codegen_mmx_entered; + +extern int codegen_fpu_loaded_iq[8]; +extern int codegen_reg_loaded[8]; + +extern int codegen_in_recompile; diff --git a/src/codegen_ops.c b/src/codegen_ops.c new file mode 100644 index 000000000..083c80b7d --- /dev/null +++ b/src/codegen_ops.c @@ -0,0 +1,497 @@ +#include "ibm.h" +#include "x86.h" +#include "x86_ops.h" +#include "x86_flags.h" +#include "x87.h" +#include "386_common.h" +#include "cpu.h" +#include "codegen.h" +#include "codegen_ops.h" + +#ifdef __amd64__ +#include "codegen_ops_x86-64.h" +#elif defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 +#include "codegen_ops_x86.h" +#endif + +#include "codegen_ops_arith.h" +#include "codegen_ops_fpu.h" +#include "codegen_ops_jump.h" +#include "codegen_ops_logic.h" +#include "codegen_ops_misc.h" +#include "codegen_ops_mmx.h" +#include "codegen_ops_mov.h" +#include "codegen_ops_shift.h" +#include "codegen_ops_stack.h" +#include "codegen_ops_xchg.h" + +RecompOpFn recomp_opcodes[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropADD_b_rmw, ropADD_w_rmw, ropADD_b_rm, ropADD_w_rm, ropADD_AL_imm, ropADD_AX_imm, ropPUSH_ES_16, NULL, ropOR_b_rmw, ropOR_w_rmw, ropOR_b_rm, ropOR_w_rm, ropOR_AL_imm, ropOR_AX_imm, ropPUSH_CS_16, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_SS_16, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_DS_16, NULL, +/*20*/ ropAND_b_rmw, ropAND_w_rmw, ropAND_b_rm, ropAND_w_rm, ropAND_AL_imm, ropAND_AX_imm, NULL, NULL, ropSUB_b_rmw, ropSUB_w_rmw, ropSUB_b_rm, ropSUB_w_rm, ropSUB_AL_imm, ropSUB_AX_imm, NULL, NULL, +/*30*/ ropXOR_b_rmw, ropXOR_w_rmw, ropXOR_b_rm, ropXOR_w_rm, ropXOR_AL_imm, ropXOR_AX_imm, NULL, NULL, ropCMP_b_rmw, ropCMP_w_rmw, ropCMP_b_rm, ropCMP_w_rm, ropCMP_AL_imm, ropCMP_AX_imm, NULL, NULL, + +/*40*/ ropINC_rw, ropINC_rw, ropINC_rw, ropINC_rw, ropINC_rw, ropINC_rw, ropINC_rw, ropINC_rw, ropDEC_rw, ropDEC_rw, ropDEC_rw, ropDEC_rw, ropDEC_rw, ropDEC_rw, ropDEC_rw, ropDEC_rw, +/*50*/ ropPUSH_16, ropPUSH_16, ropPUSH_16, ropPUSH_16, ropPUSH_16, ropPUSH_16, ropPUSH_16, ropPUSH_16, ropPOP_16, ropPOP_16, ropPOP_16, ropPOP_16, ropPOP_16, ropPOP_16, ropPOP_16, ropPOP_16, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_imm_16, NULL, ropPUSH_imm_b16,NULL, NULL, NULL, NULL, NULL, +/*70*/ ropJO, ropJNO, ropJB, ropJNB, ropJE, ropJNE, ropJBE, ropJNBE, ropJS, ropJNS, ropJP, ropJNP, ropJL, ropJNL, ropJLE, ropJNLE, + +/*80*/ rop80, rop81_w, rop80, rop83_w, ropTEST_b_rm, ropTEST_w_rm, ropXCHG_b, ropXCHG_w, ropMOV_b_r, ropMOV_w_r, ropMOV_r_b, ropMOV_r_w, NULL, ropLEA_w, NULL, NULL, +/*90*/ ropNOP, ropXCHG_AX_CX, ropXCHG_AX_DX, ropXCHG_AX_BX, ropXCHG_AX_SP, ropXCHG_AX_BP, ropXCHG_AX_SI, ropXCHG_AX_DI, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*a0*/ ropMOV_AL_a, ropMOV_AX_a, ropMOV_a_AL, ropMOV_a_AX, NULL, NULL, NULL, NULL, ropTEST_AL_imm, ropTEST_AX_imm, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rw_imm, ropMOV_rw_imm, ropMOV_rw_imm, ropMOV_rw_imm, ropMOV_rw_imm, ropMOV_rw_imm, ropMOV_rw_imm, ropMOV_rw_imm, + +/*c0*/ ropC0, ropC1_w, ropRET_imm_16, ropRET_16, NULL, NULL, ropMOV_b_imm, ropMOV_w_imm, NULL, ropLEAVE_16, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ ropD0, ropD1_w, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, ropLOOP, ropJCXZ, NULL, NULL, NULL, NULL, ropCALL_r16, ropJMP_r16, NULL, ropJMP_r8, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, ropF6, ropF7_w, NULL, NULL, NULL, NULL, ropCLD, ropSTD, NULL, ropFF_16, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropADD_b_rmw, ropADD_l_rmw, ropADD_b_rm, ropADD_l_rm, ropADD_AL_imm, ropADD_EAX_imm, ropPUSH_ES_32, NULL, ropOR_b_rmw, ropOR_l_rmw, ropOR_b_rm, ropOR_l_rm, ropOR_AL_imm, ropOR_EAX_imm, ropPUSH_CS_32, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_SS_32, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_DS_32, NULL, +/*20*/ ropAND_b_rmw, ropAND_l_rmw, ropAND_b_rm, ropAND_l_rm, ropAND_AL_imm, ropAND_EAX_imm, NULL, NULL, ropSUB_b_rmw, ropSUB_l_rmw, ropSUB_b_rm, ropSUB_l_rm, ropSUB_AL_imm, ropSUB_EAX_imm, NULL, NULL, +/*30*/ ropXOR_b_rmw, ropXOR_l_rmw, ropXOR_b_rm, ropXOR_l_rm, ropXOR_AL_imm, ropXOR_EAX_imm, NULL, NULL, ropCMP_b_rmw, ropCMP_l_rmw, ropCMP_b_rm, ropCMP_l_rm, ropCMP_AL_imm, ropCMP_EAX_imm, NULL, NULL, + +/*40*/ ropINC_rl, ropINC_rl, ropINC_rl, ropINC_rl, ropINC_rl, ropINC_rl, ropINC_rl, ropINC_rl, ropDEC_rl, ropDEC_rl, ropDEC_rl, ropDEC_rl, ropDEC_rl, ropDEC_rl, ropDEC_rl, ropDEC_rl, +/*50*/ ropPUSH_32, ropPUSH_32, ropPUSH_32, ropPUSH_32, ropPUSH_32, ropPUSH_32, ropPUSH_32, ropPUSH_32, ropPOP_32, ropPOP_32, ropPOP_32, ropPOP_32, ropPOP_32, ropPOP_32, ropPOP_32, ropPOP_32, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropPUSH_imm_32, NULL, ropPUSH_imm_b32,NULL, NULL, NULL, NULL, NULL, +/*70*/ ropJO, ropJNO, ropJB, ropJNB, ropJE, ropJNE, ropJBE, ropJNBE, ropJS, ropJNS, ropJP, ropJNP, ropJL, ropJNL, ropJLE, ropJNLE, + +/*80*/ rop80, rop81_l, rop80, rop83_l, ropTEST_b_rm, ropTEST_l_rm, ropXCHG_b, ropXCHG_l, ropMOV_b_r, ropMOV_l_r, ropMOV_r_b, ropMOV_r_l, NULL, ropLEA_l, NULL, NULL, +/*90*/ ropNOP, ropXCHG_EAX_ECX,ropXCHG_EAX_EDX,ropXCHG_EAX_EBX,ropXCHG_EAX_ESP,ropXCHG_EAX_EBP,ropXCHG_EAX_ESI,ropXCHG_EAX_EDI,NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*a0*/ ropMOV_AL_a, ropMOV_EAX_a, ropMOV_a_AL, ropMOV_a_EAX, NULL, NULL, NULL, NULL, ropTEST_AL_imm, ropTEST_EAX_imm,NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rb_imm, ropMOV_rl_imm, ropMOV_rl_imm, ropMOV_rl_imm, ropMOV_rl_imm, ropMOV_rl_imm, ropMOV_rl_imm, ropMOV_rl_imm, ropMOV_rl_imm, + +/*c0*/ ropC0, ropC1_l, ropRET_imm_32, ropRET_32, NULL, NULL, ropMOV_b_imm, ropMOV_l_imm, NULL, ropLEAVE_32, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ ropD0, ropD1_l, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, ropLOOP, ropJCXZ, NULL, NULL, NULL, NULL, ropCALL_r32, ropJMP_r32, NULL, ropJMP_r8, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, ropF6, ropF7_l, NULL, NULL, NULL, NULL, ropCLD, ropSTD, NULL, ropFF_32 +}; + +RecompOpFn recomp_opcodes_0f[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropEMMS, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*80*/ ropJO_w, ropJNO_w, ropJB_w, ropJNB_w, ropJE_w, ropJNE_w, ropJBE_w, ropJNBE_w, ropJS_w, ropJNS_w, ropJP_w, ropJNP_w, ropJL_w, ropJNL_w, ropJLE_w, ropJNLE_w, +/*90*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, ropMOVZX_w_b, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropMOVSX_w_b, NULL, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ ropPUNPCKLBW, ropPUNPCKLWD, ropPUNPCKLDQ, ropPACKSSWB, ropPCMPGTB, ropPCMPGTW, ropPCMPGTD, ropPACKUSWB, ropPUNPCKHBW, ropPUNPCKHWD, ropPUNPCKHDQ, ropPACKSSDW, NULL, NULL, ropMOVD_mm_l, ropMOVQ_mm_q, +/*70*/ NULL, ropPSxxW_imm, ropPSxxD_imm, ropPSxxQ_imm, ropPCMPEQB, ropPCMPEQW, ropPCMPEQD, ropEMMS, NULL, NULL, NULL, NULL, NULL, NULL, ropMOVD_l_mm, ropMOVQ_q_mm, + +/*80*/ ropJO_l, ropJNO_l, ropJB_l, ropJNB_l, ropJE_l, ropJNE_l, ropJBE_l, ropJNBE_l, ropJS_l, ropJNS_l, ropJP_l, ropJNP_l, ropJL_l, ropJNL_l, ropJLE_l, ropJNLE_l, +/*90*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, ropMOVZX_l_b, ropMOVZX_l_w, NULL, NULL, NULL, NULL, NULL, NULL, ropMOVSX_l_b, ropMOVSX_l_w, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, ropPSRLW, ropPSRLD, ropPSRLQ, NULL, ropPMULLW, NULL, NULL, ropPSUBUSB, ropPSUBUSW, NULL, ropPAND, ropPADDUSB, ropPADDUSW, NULL, ropPANDN, +/*e0*/ NULL, ropPSRAW, ropPSRAD, NULL, NULL, ropPMULHW, NULL, NULL, ropPSUBSB, ropPSUBSW, NULL, ropPOR, ropPADDSB, ropPADDSW, NULL, ropPXOR, +/*f0*/ NULL, ropPSLLW, ropPSLLD, ropPSLLQ, NULL, ropPMADDWD, NULL, NULL, ropPSUBB, ropPSUBW, ropPSUBD, NULL, ropPADDB, ropPADDW, ropPADDD, NULL, +}; + + +RecompOpFn recomp_opcodes_d8[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, +/*10*/ ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, +/*20*/ ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, +/*30*/ ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, + +/*40*/ ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, +/*50*/ ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, +/*60*/ ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, +/*70*/ ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, + +/*80*/ ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, +/*90*/ ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, +/*a0*/ ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, +/*b0*/ ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, + +/*c0*/ ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, +/*d0*/ ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, +/*e0*/ ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, +/*f0*/ ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, +/*10*/ ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, +/*20*/ ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, +/*30*/ ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, + +/*40*/ ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, +/*50*/ ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, +/*60*/ ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, +/*70*/ ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, + +/*80*/ ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFADDs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, ropFMULs, +/*90*/ ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, ropFCOMPs, +/*a0*/ ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, ropFSUBRs, +/*b0*/ ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, ropFDIVRs, + +/*c0*/ ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFADD, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, ropFMUL, +/*d0*/ ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, +/*e0*/ ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUB, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, ropFSUBR, +/*f0*/ ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIV, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, ropFDIVR, +}; + +RecompOpFn recomp_opcodes_d9[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, + +/*40*/ ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, + +/*80*/ ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, + +/*c0*/ ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, + +/*40*/ ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, + +/*80*/ ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, ropFLDs, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, ropFSTPs, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, ropFLDCW, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, ropFSTCW, + +/*c0*/ ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFLD, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, ropFXCH, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +RecompOpFn recomp_opcodes_da[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, +/*10*/ ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, +/*20*/ ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, +/*30*/ ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, + +/*40*/ ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, +/*50*/ ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, +/*60*/ ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, +/*70*/ ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, + +/*80*/ ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, +/*90*/ ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, +/*a0*/ ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, +/*b0*/ ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, +/*10*/ ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, +/*20*/ ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, +/*30*/ ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, + +/*40*/ ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, +/*50*/ ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, +/*60*/ ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, +/*70*/ ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, + +/*80*/ ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFADDil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, ropFMULil, +/*90*/ ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, ropFCOMPil, +/*a0*/ ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, ropFSUBRil, +/*b0*/ ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, ropFDIVRil, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +RecompOpFn recomp_opcodes_db[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*80*/ ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*80*/ ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*80*/ ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, ropFILDl, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, ropFISTPl, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +RecompOpFn recomp_opcodes_dc[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, +/*10*/ ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, +/*20*/ ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, +/*30*/ ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, + +/*40*/ ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, +/*50*/ ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, +/*60*/ ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, +/*70*/ ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, + +/*80*/ ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, +/*90*/ ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, +/*a0*/ ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, +/*b0*/ ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, + +/*c0*/ ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, +/*d0*/ ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, +/*e0*/ ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, +/*f0*/ ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, +/*10*/ ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, +/*20*/ ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, +/*30*/ ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, + +/*40*/ ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, +/*50*/ ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, +/*60*/ ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, +/*70*/ ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, + +/*80*/ ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFADDd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, ropFMULd, +/*90*/ ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, ropFCOMPd, +/*a0*/ ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, ropFSUBRd, +/*b0*/ ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, ropFDIVRd, + +/*c0*/ ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFADDr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, ropFMULr, +/*d0*/ ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOM, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, ropFCOMP, +/*e0*/ ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBRr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, ropFSUBr, +/*f0*/ ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVRr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, ropFDIVr, +}; + +RecompOpFn recomp_opcodes_dd[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*80*/ ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ ropFST, ropFST, ropFST, ropFST, ropFST, ropFST, ropFST, ropFST, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*80*/ ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, ropFLDd, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, ropFSTPd, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ ropFST, ropFST, ropFST, ropFST, ropFST, ropFST, ropFST, ropFST, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, ropFSTP, +/*e0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +RecompOpFn recomp_opcodes_de[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, +/*10*/ ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, +/*20*/ ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, +/*30*/ ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, + +/*40*/ ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, +/*50*/ ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, +/*60*/ ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, +/*70*/ ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, + +/*80*/ ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, +/*90*/ ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, +/*a0*/ ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, +/*b0*/ ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, + +/*c0*/ ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, +/*f0*/ ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, +/*10*/ ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, +/*20*/ ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, +/*30*/ ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, + +/*40*/ ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, +/*50*/ ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, +/*60*/ ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, +/*70*/ ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, + +/*80*/ ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFADDiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, ropFMULiw, +/*90*/ ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, ropFCOMPiw, +/*a0*/ ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, ropFSUBRiw, +/*b0*/ ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIViw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, ropFDIVRiw, + +/*c0*/ ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFADDP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, ropFMULP, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBRP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, ropFSUBP, +/*f0*/ ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVRP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, ropFDIVP, +}; + +RecompOpFn recomp_opcodes_df[512] = +{ + /*16-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, + +/*40*/ ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, + +/*80*/ ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ ropFSTSW_AX, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + + /*32-bit data*/ +/* 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f*/ +/*00*/ ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, +/*20*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, +/*30*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, + +/*40*/ ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, +/*60*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, +/*70*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, + +/*80*/ ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, ropFILDw, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*90*/ ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, ropFISTPw, +/*a0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, ropFILDq, +/*b0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, ropFISTPq, + +/*c0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*d0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ ropFSTSW_AX, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*f0*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; diff --git a/src/codegen_ops.h b/src/codegen_ops.h new file mode 100644 index 000000000..36b21918e --- /dev/null +++ b/src/codegen_ops.h @@ -0,0 +1,37 @@ +typedef uint32_t (*RecompOpFn)(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block); + +extern RecompOpFn recomp_opcodes[512]; +extern RecompOpFn recomp_opcodes_0f[512]; +extern RecompOpFn recomp_opcodes_d8[512]; +extern RecompOpFn recomp_opcodes_d9[512]; +extern RecompOpFn recomp_opcodes_da[512]; +extern RecompOpFn recomp_opcodes_db[512]; +extern RecompOpFn recomp_opcodes_dc[512]; +extern RecompOpFn recomp_opcodes_dd[512]; +extern RecompOpFn recomp_opcodes_de[512]; +extern RecompOpFn recomp_opcodes_df[512]; + +#define REG_EAX 0 +#define REG_ECX 1 +#define REG_EDX 2 +#define REG_EBX 3 +#define REG_ESP 4 +#define REG_EBP 5 +#define REG_ESI 6 +#define REG_EDI 7 +#define REG_AX 0 +#define REG_CX 1 +#define REG_DX 2 +#define REG_BX 3 +#define REG_SP 4 +#define REG_BP 5 +#define REG_SI 6 +#define REG_DI 7 +#define REG_AL 0 +#define REG_AH 4 +#define REG_CL 1 +#define REG_CH 5 +#define REG_DL 2 +#define REG_DH 6 +#define REG_BL 3 +#define REG_BH 7 diff --git a/src/codegen_ops_arith.h b/src/codegen_ops_arith.h new file mode 100644 index 000000000..1753bde8f --- /dev/null +++ b/src/codegen_ops_arith.h @@ -0,0 +1,816 @@ +static uint32_t ropINC_rw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + CALL_FUNC(flags_rebuild_c); + + host_reg = LOAD_REG_W(opcode & 7); + + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM_W(host_reg, 1); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_INC16); + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, host_reg); + STORE_REG_W_RELEASE(host_reg); + + codegen_flags_changed = 1; + + return op_pc; +} +static uint32_t ropINC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + CALL_FUNC(flags_rebuild_c); + + host_reg = LOAD_REG_L(opcode & 7); + + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM(host_reg, 1); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_INC32); + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, host_reg); + STORE_REG_L_RELEASE(host_reg); + + codegen_flags_changed = 1; + + return op_pc; +} +static uint32_t ropDEC_rw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + CALL_FUNC(flags_rebuild_c); + + host_reg = LOAD_REG_W(opcode & 7); + + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM_W(host_reg, 1); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_DEC16); + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, host_reg); + STORE_REG_W_RELEASE(host_reg); + + codegen_flags_changed = 1; + + return op_pc; +} +static uint32_t ropDEC_rl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + CALL_FUNC(flags_rebuild_c); + + host_reg = LOAD_REG_L(opcode & 7); + + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM(host_reg, 1); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, 1); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_DEC32); + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, host_reg); + STORE_REG_L_RELEASE(host_reg); + + codegen_flags_changed = 1; + + return op_pc; +} + +#define ROP_ARITH_RMW(name, op, writeback) \ + static uint32_t rop ## name ## _b_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + \ + if ((fetchdat & 0xc0) != 0xc0) \ + return 0; \ + \ + dst_reg = LOAD_REG_B(fetchdat & 7); \ + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ ## op ## 8); \ + src_reg = LOAD_REG_B((fetchdat >> 3) & 7); \ + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, dst_reg); \ + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op2, src_reg); \ + op ## _HOST_REG_B(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) STORE_REG_B_RELEASE(dst_reg); \ + else RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + codegen_flags_changed = 1; \ + return op_pc + 1; \ + } \ + static uint32_t rop ## name ## _w_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + \ + if ((fetchdat & 0xc0) != 0xc0) \ + return 0; \ + \ + dst_reg = LOAD_REG_W(fetchdat & 7); \ + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ ## op ## 16); \ + src_reg = LOAD_REG_W((fetchdat >> 3) & 7); \ + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, dst_reg); \ + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op2, src_reg); \ + op ## _HOST_REG_W(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) STORE_REG_W_RELEASE(dst_reg); \ + else RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + codegen_flags_changed = 1; \ + return op_pc + 1; \ + } \ + static uint32_t rop ## name ## _l_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + \ + if ((fetchdat & 0xc0) != 0xc0) \ + return 0; \ + \ + dst_reg = LOAD_REG_L(fetchdat & 7); \ + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ ## op ## 32); \ + src_reg = LOAD_REG_L((fetchdat >> 3) & 7); \ + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, dst_reg); \ + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op2, src_reg); \ + op ## _HOST_REG_L(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) STORE_REG_L_RELEASE(dst_reg); \ + else RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + codegen_flags_changed = 1; \ + return op_pc + 1; \ + } + +#define ROP_ARITH_RM(name, op, writeback) \ + static uint32_t rop ## name ## _b_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + src_reg = LOAD_REG_B(fetchdat & 7); \ + } \ + else \ + { \ + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); \ + MEM_LOAD_ADDR_EA_B(target_seg); \ + src_reg = 0; \ + } \ + \ + dst_reg = LOAD_REG_B((fetchdat >> 3) & 7); \ + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ ## op ## 8); \ + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, dst_reg); \ + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op2, src_reg); \ + op ## _HOST_REG_B(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) STORE_REG_B_RELEASE(dst_reg); \ + else RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + codegen_flags_changed = 1; \ + return op_pc + 1; \ + } \ + static uint32_t rop ## name ## _w_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + src_reg = LOAD_REG_W(fetchdat & 7); \ + } \ + else \ + { \ + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); \ + MEM_LOAD_ADDR_EA_W(target_seg); \ + src_reg = 0; \ + } \ + \ + dst_reg = LOAD_REG_W((fetchdat >> 3) & 7); \ + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ ## op ## 16); \ + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, dst_reg); \ + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op2, src_reg); \ + op ## _HOST_REG_W(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) STORE_REG_W_RELEASE(dst_reg); \ + else RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + codegen_flags_changed = 1; \ + return op_pc + 1; \ + } \ + static uint32_t rop ## name ## _l_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + src_reg = LOAD_REG_L(fetchdat & 7); \ + } \ + else \ + { \ + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); \ + MEM_LOAD_ADDR_EA_L(target_seg); \ + src_reg = 0; \ + } \ + \ + dst_reg = LOAD_REG_L((fetchdat >> 3) & 7); \ + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ ## op ## 32); \ + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, dst_reg); \ + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op2, src_reg); \ + op ## _HOST_REG_L(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) STORE_REG_L_RELEASE(dst_reg); \ + else RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + codegen_flags_changed = 1; \ + return op_pc + 1; \ + } + +ROP_ARITH_RMW(ADD, ADD, 1) +ROP_ARITH_RMW(SUB, SUB, 1) +ROP_ARITH_RM(ADD, ADD, 1) +ROP_ARITH_RM(SUB, SUB, 1) + +static uint32_t ropCMP_b_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg; + + if ((fetchdat & 0xc0) == 0xc0) + { + src_reg = LOAD_REG_B(fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_B(target_seg); + src_reg = 0; + } + + dst_reg = LOAD_REG_B((fetchdat >> 3) & 7); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB8); + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, dst_reg); + dst_reg = CMP_HOST_REG_B(dst_reg, src_reg); + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op2, src_reg); + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_res, dst_reg); + RELEASE_REG(dst_reg); + RELEASE_REG(src_reg); + + codegen_flags_changed = 1; + return op_pc + 1; +} +static uint32_t ropCMP_w_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg; + + if ((fetchdat & 0xc0) == 0xc0) + { + src_reg = LOAD_REG_W(fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_W(target_seg); + src_reg = 0; + } + + dst_reg = LOAD_REG_W((fetchdat >> 3) & 7); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB16); + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, dst_reg); + dst_reg = CMP_HOST_REG_W(dst_reg, src_reg); + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op2, src_reg); + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, dst_reg); + RELEASE_REG(dst_reg); + RELEASE_REG(src_reg); + + codegen_flags_changed = 1; + return op_pc + 1; +} +static uint32_t ropCMP_l_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg; + + if ((fetchdat & 0xc0) == 0xc0) + { + src_reg = LOAD_REG_L(fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_L(target_seg); + src_reg = 0; + } + + dst_reg = LOAD_REG_L((fetchdat >> 3) & 7); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB32); + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, dst_reg); + dst_reg = CMP_HOST_REG_L(dst_reg, src_reg); + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op2, src_reg); + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, dst_reg); + RELEASE_REG(dst_reg); + RELEASE_REG(src_reg); + + codegen_flags_changed = 1; + return op_pc + 1; +} + +static uint32_t ropCMP_b_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg; + + if ((fetchdat & 0xc0) == 0xc0) + { + dst_reg = LOAD_REG_B(fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_B(target_seg); + dst_reg = 0; + } + + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB8); + src_reg = LOAD_REG_B((fetchdat >> 3) & 7); + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, dst_reg); + dst_reg = CMP_HOST_REG_B(dst_reg, src_reg); + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op2, src_reg); + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_res, dst_reg); + RELEASE_REG(dst_reg); + RELEASE_REG(src_reg); + + codegen_flags_changed = 1; + return op_pc + 1; +} +static uint32_t ropCMP_w_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg; + + if ((fetchdat & 0xc0) == 0xc0) + { + dst_reg = LOAD_REG_W(fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_W(target_seg); + dst_reg = 0; + } \ + + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB16); + src_reg = LOAD_REG_W((fetchdat >> 3) & 7); + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, dst_reg); + dst_reg = CMP_HOST_REG_W(dst_reg, src_reg); + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op2, src_reg); + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, dst_reg); + RELEASE_REG(dst_reg); + RELEASE_REG(src_reg); + + codegen_flags_changed = 1; + return op_pc + 1; +} +static uint32_t ropCMP_l_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg; + + if ((fetchdat & 0xc0) == 0xc0) + { + dst_reg = LOAD_REG_L(fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_L(target_seg); + dst_reg = 0; + } + + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB32); + src_reg = LOAD_REG_L((fetchdat >> 3) & 7); + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, dst_reg); + dst_reg = CMP_HOST_REG_L(dst_reg, src_reg); + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op2, src_reg); + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, dst_reg); + RELEASE_REG(dst_reg); + RELEASE_REG(src_reg); + + codegen_flags_changed = 1; + return op_pc + 1; +} + + +static uint32_t ropADD_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_B(REG_AL); + + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM_B(host_reg, fetchdat & 0xff); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, fetchdat & 0xff); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ADD8); + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_res, host_reg); + STORE_REG_B_RELEASE(host_reg); + + codegen_flags_changed = 1; + return op_pc + 1; +} +static uint32_t ropADD_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_W(REG_AX); + + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM_W(host_reg, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ADD16); + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, host_reg); + STORE_REG_W_RELEASE(host_reg); + + codegen_flags_changed = 1; + return op_pc + 2; +} +static uint32_t ropADD_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_L(REG_EAX); + + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + fetchdat = fastreadl(cs + op_pc); + ADD_HOST_REG_IMM(host_reg, fetchdat); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, fetchdat); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ADD32); + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, host_reg); + STORE_REG_L_RELEASE(host_reg); + + codegen_flags_changed = 1; + return op_pc + 4; +} + +static uint32_t ropCMP_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_B(REG_AL); + + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, host_reg); + host_reg = CMP_HOST_REG_IMM_B(host_reg, fetchdat & 0xff); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, fetchdat & 0xff); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB8); + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_res, host_reg); + RELEASE_REG(host_reg); + + codegen_flags_changed = 1; + return op_pc + 1; +} +static uint32_t ropCMP_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_W(REG_AX); + + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + host_reg = CMP_HOST_REG_IMM_W(host_reg, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB16); + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, host_reg); + RELEASE_REG(host_reg); + + codegen_flags_changed = 1; + return op_pc + 2; +} +static uint32_t ropCMP_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_L(REG_EAX); + + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + fetchdat = fastreadl(cs + op_pc); + host_reg = CMP_HOST_REG_IMM_L(host_reg, fetchdat); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, fetchdat); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB32); + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, host_reg); + RELEASE_REG(host_reg); + + codegen_flags_changed = 1; + return op_pc + 4; +} + +static uint32_t ropSUB_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_B(REG_AL); + + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM_B(host_reg, fetchdat & 0xff); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, fetchdat & 0xff); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB8); + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_res, host_reg); + STORE_REG_B_RELEASE(host_reg); + + codegen_flags_changed = 1; + return op_pc + 1; +} +static uint32_t ropSUB_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_W(REG_AX); + + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM_W(host_reg, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB16); + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, host_reg); + STORE_REG_W_RELEASE(host_reg); + + codegen_flags_changed = 1; + return op_pc + 2; +} +static uint32_t ropSUB_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_L(REG_EAX); + + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + fetchdat = fastreadl(cs + op_pc); + SUB_HOST_REG_IMM(host_reg, fetchdat); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, fetchdat); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB32); + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, host_reg); + STORE_REG_L_RELEASE(host_reg); + + codegen_flags_changed = 1; + return op_pc + 4; +} + +static uint32_t rop80(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + uint32_t imm; + + if ((fetchdat & 0x30) == 0x10 || (fetchdat & 0xc0) != 0xc0) + return 0; + + host_reg = LOAD_REG_B(fetchdat & 7); + imm = (fetchdat >> 8) & 0xff; + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM_B(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ADD8); + break; + case 0x08: /*OR*/ + OR_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN8); + break; + case 0x20: /*AND*/ + AND_HOST_REG_IMM(host_reg, imm | 0xffffff00); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN8); + break; + case 0x28: /*SUB*/ + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM_B(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB8); + break; + case 0x30: /*XOR*/ + XOR_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN8); + break; + case 0x38: /*CMP*/ + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_op1, host_reg); + host_reg = CMP_HOST_REG_IMM_B(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB8); + break; + } + + STORE_HOST_REG_ADDR_BL((uint32_t)&cpu_state.flags_res, host_reg); + if ((fetchdat & 0x38) != 0x38) + STORE_REG_B_RELEASE(host_reg); + else + RELEASE_REG(host_reg); + + codegen_flags_changed = 1; + return op_pc + 2; +} + +static uint32_t rop81_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + uint32_t imm; + + if ((fetchdat & 0x30) == 0x10 || (fetchdat & 0xc0) != 0xc0) + return 0; + + host_reg = LOAD_REG_W(fetchdat & 7); + imm = (fetchdat >> 8) & 0xffff; + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM_W(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ADD16); + break; + case 0x08: /*OR*/ + OR_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN16); + break; + case 0x20: /*AND*/ + AND_HOST_REG_IMM(host_reg, imm | 0xffff0000); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN16); + break; + case 0x28: /*SUB*/ + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM_W(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB16); + break; + case 0x30: /*XOR*/ + XOR_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN16); + break; + case 0x38: /*CMP*/ + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + host_reg = CMP_HOST_REG_IMM_W(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB16); + break; + } + + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, host_reg); + if ((fetchdat & 0x38) != 0x38) + STORE_REG_W_RELEASE(host_reg); + else + RELEASE_REG(host_reg); + + codegen_flags_changed = 1; + return op_pc + 3; +} +static uint32_t rop81_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + uint32_t imm; + + if ((fetchdat & 0x30) == 0x10 || (fetchdat & 0xc0) != 0xc0) + return 0; + + imm = fastreadl(cs + op_pc + 1); + + host_reg = LOAD_REG_L(fetchdat & 7); + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ADD32); + break; + case 0x08: /*OR*/ + OR_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN32); + break; + case 0x20: /*AND*/ + AND_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN32); + break; + case 0x28: /*SUB*/ + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB32); + break; + case 0x30: /*XOR*/ + XOR_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN32); + break; + case 0x38: /*CMP*/ + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + host_reg = CMP_HOST_REG_IMM_L(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB32); + break; + } + + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, host_reg); + if ((fetchdat & 0x38) != 0x38) + STORE_REG_L_RELEASE(host_reg); + else + RELEASE_REG(host_reg); + + codegen_flags_changed = 1; + return op_pc + 5; +} + +static uint32_t rop83_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + uint32_t imm; + + if ((fetchdat & 0x30) == 0x10 || (fetchdat & 0xc0) != 0xc0) + return 0; + + host_reg = LOAD_REG_W(fetchdat & 7); + imm = (fetchdat >> 8) & 0xff; + if (imm & 0x80) + imm |= 0xff80; + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM_W(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ADD16); + break; + case 0x08: /*OR*/ + OR_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN16); + break; + case 0x20: /*AND*/ + AND_HOST_REG_IMM(host_reg, imm | 0xffff0000); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN16); + break; + case 0x28: /*SUB*/ + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM_W(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB16); + break; + case 0x30: /*XOR*/ + XOR_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN16); + break; + case 0x38: /*CMP*/ + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_op1, host_reg); + host_reg = CMP_HOST_REG_IMM_W(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB16); + break; + } + + STORE_HOST_REG_ADDR_WL((uint32_t)&cpu_state.flags_res, host_reg); + if ((fetchdat & 0x38) != 0x38) + STORE_REG_W_RELEASE(host_reg); + else + RELEASE_REG(host_reg); + + codegen_flags_changed = 1; + return op_pc + 2; +} +static uint32_t rop83_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + uint32_t imm; + + if ((fetchdat & 0x30) == 0x10 || (fetchdat & 0xc0) != 0xc0) + return 0; + + host_reg = LOAD_REG_L(fetchdat & 7); + imm = (fetchdat >> 8) & 0xff; + if (imm & 0x80) + imm |= 0xffffff80; + + switch (fetchdat & 0x38) + { + case 0x00: /*ADD*/ + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + ADD_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ADD32); + break; + case 0x08: /*OR*/ + OR_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN32); + break; + case 0x20: /*AND*/ + AND_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN32); + break; + case 0x28: /*SUB*/ + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + SUB_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB32); + break; + case 0x30: /*XOR*/ + XOR_HOST_REG_IMM(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_ZN32); + break; + case 0x38: /*CMP*/ + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_op1, host_reg); + host_reg = CMP_HOST_REG_IMM_L(host_reg, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, imm); + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SUB32); + break; + } + + STORE_HOST_REG_ADDR((uint32_t)&cpu_state.flags_res, host_reg); + if ((fetchdat & 0x38) != 0x38) + STORE_REG_L_RELEASE(host_reg); + else + RELEASE_REG(host_reg); + + codegen_flags_changed = 1; + return op_pc + 2; +} diff --git a/src/codegen_ops_fpu.h b/src/codegen_ops_fpu.h new file mode 100644 index 000000000..d300926da --- /dev/null +++ b/src/codegen_ops_fpu.h @@ -0,0 +1,601 @@ +static uint32_t ropFXCH(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + + FP_FXCH(opcode & 7); + + return op_pc; +} + +static uint32_t ropFLD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + + FP_FLD(opcode & 7); + + return op_pc; +} + +static uint32_t ropFST(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + + FP_FST(opcode & 7); + + return op_pc; +} +static uint32_t ropFSTP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + + FP_FST(opcode & 7); + FP_POP(); + + return op_pc; +} + + +static uint32_t ropFLDs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + MEM_LOAD_ADDR_EA_L(target_seg); + + FP_LOAD_S(); + + return op_pc + 1; +} +static uint32_t ropFLDd(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + MEM_LOAD_ADDR_EA_Q(target_seg); + + FP_LOAD_D(); + + return op_pc + 1; +} + +static uint32_t ropFILDw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + MEM_LOAD_ADDR_EA_W(target_seg); + + FP_LOAD_IW(); + + return op_pc + 1; +} +static uint32_t ropFILDl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + MEM_LOAD_ADDR_EA_L(target_seg); + + FP_LOAD_IL(); + + return op_pc + 1; +} +static uint32_t ropFILDq(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + MEM_LOAD_ADDR_EA_Q(target_seg); + + FP_LOAD_IQ(); + + codegen_fpu_loaded_iq[(TOP - 1) & 7] = 1; + + return op_pc + 1; +} + +static uint32_t ropFSTs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + int host_reg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + host_reg = FP_LOAD_REG(0); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_WRITE(target_seg); + + MEM_STORE_ADDR_EA_L(target_seg, host_reg); + + return op_pc + 1; +} +static uint32_t ropFSTd(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + int host_reg1, host_reg2; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + FP_LOAD_REG_D(0, &host_reg1, &host_reg2); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_WRITE(target_seg); + CHECK_SEG_LIMITS(target_seg, 7); + + MEM_STORE_ADDR_EA_Q(target_seg, host_reg1, host_reg2); + + return op_pc + 1; +} + +static uint32_t ropFSTPs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t new_pc = ropFSTs(opcode, fetchdat, op_32, op_pc, block); + + FP_POP(); + + return new_pc; +} +static uint32_t ropFSTPd(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t new_pc = ropFSTd(opcode, fetchdat, op_32, op_pc, block); + + FP_POP(); + + return new_pc; +} + +#define ropFarith(name, size, load, op) \ +static uint32_t ropF ## name ## size(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ +{ \ + x86seg *target_seg; \ + \ + FP_ENTER(); \ + op_pc--; \ + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + \ + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); \ + \ + CHECK_SEG_READ(target_seg); \ + load(target_seg); \ + \ + op(FPU_ ## name); \ + \ + return op_pc + 1; \ +} + +ropFarith(ADD, s, MEM_LOAD_ADDR_EA_L, FP_OP_S); +ropFarith(DIV, s, MEM_LOAD_ADDR_EA_L, FP_OP_S); +ropFarith(DIVR, s, MEM_LOAD_ADDR_EA_L, FP_OP_S); +ropFarith(MUL, s, MEM_LOAD_ADDR_EA_L, FP_OP_S); +ropFarith(SUB, s, MEM_LOAD_ADDR_EA_L, FP_OP_S); +ropFarith(SUBR, s, MEM_LOAD_ADDR_EA_L, FP_OP_S); +ropFarith(ADD, d, MEM_LOAD_ADDR_EA_Q, FP_OP_D); +ropFarith(DIV, d, MEM_LOAD_ADDR_EA_Q, FP_OP_D); +ropFarith(DIVR, d, MEM_LOAD_ADDR_EA_Q, FP_OP_D); +ropFarith(MUL, d, MEM_LOAD_ADDR_EA_Q, FP_OP_D); +ropFarith(SUB, d, MEM_LOAD_ADDR_EA_Q, FP_OP_D); +ropFarith(SUBR, d, MEM_LOAD_ADDR_EA_Q, FP_OP_D); +ropFarith(ADD, iw, MEM_LOAD_ADDR_EA_W, FP_OP_IW); +ropFarith(DIV, iw, MEM_LOAD_ADDR_EA_W, FP_OP_IW); +ropFarith(DIVR, iw, MEM_LOAD_ADDR_EA_W, FP_OP_IW); +ropFarith(MUL, iw, MEM_LOAD_ADDR_EA_W, FP_OP_IW); +ropFarith(SUB, iw, MEM_LOAD_ADDR_EA_W, FP_OP_IW); +ropFarith(SUBR, iw, MEM_LOAD_ADDR_EA_W, FP_OP_IW); +ropFarith(ADD, il, MEM_LOAD_ADDR_EA_L, FP_OP_IL); +ropFarith(DIV, il, MEM_LOAD_ADDR_EA_L, FP_OP_IL); +ropFarith(DIVR, il, MEM_LOAD_ADDR_EA_L, FP_OP_IL); +ropFarith(MUL, il, MEM_LOAD_ADDR_EA_L, FP_OP_IL); +ropFarith(SUB, il, MEM_LOAD_ADDR_EA_L, FP_OP_IL); +ropFarith(SUBR, il, MEM_LOAD_ADDR_EA_L, FP_OP_IL); + +#define ropFcompare(name, size, load, op) \ +static uint32_t ropF ## name ## size(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ +{ \ + x86seg *target_seg; \ + \ + FP_ENTER(); \ + op_pc--; \ + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + \ + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); \ + \ + CHECK_SEG_READ(target_seg); \ + load(target_seg); \ + \ + op(); \ + \ + return op_pc + 1; \ +} \ +static uint32_t ropF ## name ## P ## size(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ +{ \ + uint32_t new_pc = ropF ## name ## size(opcode, fetchdat, op_32, op_pc, block); \ + \ + FP_POP(); \ + \ + return new_pc; \ +} + +ropFcompare(COM, s, MEM_LOAD_ADDR_EA_L, FP_COMPARE_S); +ropFcompare(COM, d, MEM_LOAD_ADDR_EA_Q, FP_COMPARE_D); +ropFcompare(COM, iw, MEM_LOAD_ADDR_EA_W, FP_COMPARE_IW); +ropFcompare(COM, il, MEM_LOAD_ADDR_EA_L, FP_COMPARE_IL); + +/*static uint32_t ropFADDs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + MEM_LOAD_ADDR_EA_L(target_seg); + + FP_OP_S(FPU_ADD); + + return op_pc + 1; +} +static uint32_t ropFDIVs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + MEM_LOAD_ADDR_EA_L(target_seg); + + FP_OP_S(FPU_DIV); + + return op_pc + 1; +} +static uint32_t ropFMULs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + MEM_LOAD_ADDR_EA_L(target_seg); + + FP_OP_S(FPU_MUL); + + return op_pc + 1; +} +static uint32_t ropFSUBs(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + MEM_LOAD_ADDR_EA_L(target_seg); + + FP_OP_S(FPU_SUB); + + return op_pc + 1; +}*/ + + +static uint32_t ropFADD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_ADD, 0, opcode & 7); + + return op_pc; +} +static uint32_t ropFCOM(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_COMPARE_REG(0, opcode & 7); + + return op_pc; +} +static uint32_t ropFDIV(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_DIV, 0, opcode & 7); + + return op_pc; +} +static uint32_t ropFDIVR(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_DIVR, 0, opcode & 7); + + return op_pc; +} +static uint32_t ropFMUL(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_MUL, 0, opcode & 7); + + return op_pc; +} +static uint32_t ropFSUB(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_SUB, 0, opcode & 7); + + return op_pc; +} +static uint32_t ropFSUBR(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_SUBR, 0, opcode & 7); + + return op_pc; +} + +static uint32_t ropFADDr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_ADD, opcode & 7, 0); + + return op_pc; +} +static uint32_t ropFDIVr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_DIV, opcode & 7, 0); + + return op_pc; +} +static uint32_t ropFDIVRr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_DIVR, opcode & 7, 0); + + return op_pc; +} +static uint32_t ropFMULr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_MUL, opcode & 7, 0); + + return op_pc; +} +static uint32_t ropFSUBr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_SUB, opcode & 7, 0); + + return op_pc; +} +static uint32_t ropFSUBRr(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_SUBR, opcode & 7, 0); + + return op_pc; +} + +static uint32_t ropFADDP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_ADD, opcode & 7, 0); + FP_POP(); + + return op_pc; +} +static uint32_t ropFCOMP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_COMPARE_REG(0, opcode & 7); + FP_POP(); + + return op_pc; +} +static uint32_t ropFDIVP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_DIV, opcode & 7, 0); + FP_POP(); + + return op_pc; +} +static uint32_t ropFDIVRP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_DIVR, opcode & 7, 0); + FP_POP(); + + return op_pc; +} +static uint32_t ropFMULP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_MUL, opcode & 7, 0); + FP_POP(); + + return op_pc; +} +static uint32_t ropFSUBP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_SUB, opcode & 7, 0); + FP_POP(); + + return op_pc; +} +static uint32_t ropFSUBRP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + FP_ENTER(); + FP_OP_REG(FPU_SUBR, opcode & 7, 0); + FP_POP(); + + return op_pc; +} + + +static uint32_t ropFSTSW_AX(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + FP_ENTER(); + host_reg = LOAD_VAR_W(&npxs); + STORE_REG_TARGET_W_RELEASE(host_reg, REG_AX); + + return op_pc; +} + + +static uint32_t ropFISTw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + int host_reg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + host_reg = FP_LOAD_REG_INT_W(0); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_WRITE(target_seg); + + MEM_STORE_ADDR_EA_W(target_seg, host_reg); + + return op_pc + 1; +} +static uint32_t ropFISTl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + int host_reg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + host_reg = FP_LOAD_REG_INT(0); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_WRITE(target_seg); + + MEM_STORE_ADDR_EA_L(target_seg, host_reg); + + return op_pc + 1; +} + +static uint32_t ropFISTPw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t new_pc = ropFISTw(opcode, fetchdat, op_32, op_pc, block); + + FP_POP(); + + return new_pc; +} +static uint32_t ropFISTPl(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t new_pc = ropFISTl(opcode, fetchdat, op_32, op_pc, block); + + FP_POP(); + + return new_pc; +} +static uint32_t ropFISTPq(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + int host_reg1, host_reg2; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + FP_LOAD_REG_INT_Q(0, &host_reg1, &host_reg2); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_WRITE(target_seg); + + MEM_STORE_ADDR_EA_Q(target_seg, host_reg1, host_reg2); + + FP_POP(); + + return op_pc + 1; +} + + +static uint32_t ropFLDCW(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_W(target_seg); + STORE_HOST_REG_ADDR_W((uintptr_t)&npxc, 0); + + return op_pc + 1; +} +static uint32_t ropFSTCW(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + x86seg *target_seg; + + FP_ENTER(); + op_pc--; + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + CHECK_SEG_WRITE(target_seg); + + host_reg = LOAD_VAR_W((uintptr_t)&npxc); + MEM_STORE_ADDR_EA_W(target_seg, host_reg); + + return op_pc + 1; +} diff --git a/src/codegen_ops_jump.h b/src/codegen_ops_jump.h new file mode 100644 index 000000000..8dba96c7c --- /dev/null +++ b/src/codegen_ops_jump.h @@ -0,0 +1,270 @@ +static uint32_t ropJMP_r8(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t offset = fetchdat & 0xff; + + if (offset & 0x80) + offset |= 0xffffff00; + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, op_pc+1+offset); + + return -1; +} + +static uint32_t ropJMP_r16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint16_t offset = fetchdat & 0xffff; + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, (op_pc+2+offset) & 0xffff); + + return -1; +} + +static uint32_t ropJMP_r32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t offset = fastreadl(cs + op_pc); + + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, op_pc+4+offset); + + return -1; +} + + +static uint32_t ropJCXZ(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t offset = fetchdat & 0xff; + + if (offset & 0x80) + offset |= 0xffffff00; + + if (op_32 & 0x200) + { + int host_reg = LOAD_REG_L(REG_ECX); + TEST_ZERO_JUMP_L(host_reg, op_pc+1+offset, 0); + } + else + { + int host_reg = LOAD_REG_W(REG_CX); + TEST_ZERO_JUMP_W(host_reg, op_pc+1+offset, 0); + } + + return op_pc+1; +} + +static uint32_t ropLOOP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t offset = fetchdat & 0xff; + + if (offset & 0x80) + offset |= 0xffffff00; + + if (op_32 & 0x200) + { + int host_reg = LOAD_REG_L(REG_ECX); + SUB_HOST_REG_IMM(host_reg, 1); + STORE_REG_L_RELEASE(host_reg); + TEST_NONZERO_JUMP_L(host_reg, op_pc+1+offset, 0); + } + else + { + int host_reg = LOAD_REG_W(REG_CX); + SUB_HOST_REG_IMM(host_reg, 1); + STORE_REG_W_RELEASE(host_reg); + TEST_NONZERO_JUMP_W(host_reg, op_pc+1+offset, 0); + } + + return op_pc+1; +} + +static int BRANCH_COND_B(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + CALL_FUNC(CF_SET); + if (not) + TEST_ZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); + else + TEST_NONZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); +} + +static int BRANCH_COND_E(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + int host_reg; + + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + case FLAGS_ADD8: + case FLAGS_ADD16: + case FLAGS_ADD32: + case FLAGS_SUB8: + case FLAGS_SUB16: + case FLAGS_SUB32: + case FLAGS_SHL8: + case FLAGS_SHL16: + case FLAGS_SHL32: + case FLAGS_SHR8: + case FLAGS_SHR16: + case FLAGS_SHR32: + case FLAGS_SAR8: + case FLAGS_SAR16: + case FLAGS_SAR32: + case FLAGS_INC8: + case FLAGS_INC16: + case FLAGS_INC32: + case FLAGS_DEC8: + case FLAGS_DEC16: + case FLAGS_DEC32: + host_reg = LOAD_VAR_L((uintptr_t)&cpu_state.flags_res); + if (not) + TEST_NONZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); + else + TEST_ZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); + break; + + case FLAGS_UNKNOWN: + CALL_FUNC(ZF_SET); + if (not) + TEST_ZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); + else + TEST_NONZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); + break; + } +} + +static int BRANCH_COND_O(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + CALL_FUNC(VF_SET); + if (not) + TEST_ZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); + else + TEST_NONZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); +} + +static int BRANCH_COND_P(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + CALL_FUNC(PF_SET); + if (not) + TEST_ZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); + else + TEST_NONZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); +} + +static int BRANCH_COND_S(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + int host_reg; + + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_ZN8: + case FLAGS_ADD8: + case FLAGS_SUB8: + case FLAGS_SHL8: + case FLAGS_SHR8: + case FLAGS_SAR8: + case FLAGS_INC8: + case FLAGS_DEC8: + host_reg = LOAD_VAR_L((uintptr_t)&cpu_state.flags_res); + AND_HOST_REG_IMM(host_reg, 0x80); + if (not) + TEST_ZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); + else + TEST_NONZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); + break; + + case FLAGS_ZN16: + case FLAGS_ADD16: + case FLAGS_SUB16: + case FLAGS_SHL16: + case FLAGS_SHR16: + case FLAGS_SAR16: + case FLAGS_INC16: + case FLAGS_DEC16: + host_reg = LOAD_VAR_L((uintptr_t)&cpu_state.flags_res); + AND_HOST_REG_IMM(host_reg, 0x8000); + if (not) + TEST_ZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); + else + TEST_NONZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); + break; + + case FLAGS_ZN32: + case FLAGS_ADD32: + case FLAGS_SUB32: + case FLAGS_SHL32: + case FLAGS_SHR32: + case FLAGS_SAR32: + case FLAGS_INC32: + case FLAGS_DEC32: + host_reg = LOAD_VAR_L((uintptr_t)&cpu_state.flags_res); + AND_HOST_REG_IMM(host_reg, 0x80000000); + if (not) + TEST_ZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); + else + TEST_NONZERO_JUMP_L(host_reg, op_pc+pc_offset+offset, timing_bt); + break; + + case FLAGS_UNKNOWN: + CALL_FUNC(NF_SET); + if (not) + TEST_ZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); + else + TEST_NONZERO_JUMP_L(0, op_pc+pc_offset+offset, timing_bt); + break; + } +} + + +#define ropBRANCH(name, func, not) \ +static uint32_t rop ## name(uint8_t opcode, uint32_t fetchdat, \ + uint32_t op_32, uint32_t op_pc, \ + codeblock_t *block) \ +{ \ + uint32_t offset = fetchdat & 0xff; \ + \ + if (offset & 0x80) \ + offset |= 0xffffff00; \ + \ + func(1, op_pc, offset, not); \ + \ + return op_pc+1; \ +} \ +static uint32_t rop ## name ## _w(uint8_t opcode, \ + uint32_t fetchdat, uint32_t op_32, \ + uint32_t op_pc, codeblock_t *block) \ +{ \ + uint32_t offset = fetchdat & 0xffff; \ + \ + if (offset & 0x8000) \ + offset |= 0xffff0000; \ + \ + func(2, op_pc, offset, not); \ + \ + return op_pc+2; \ +} \ +static uint32_t rop ## name ## _l(uint8_t opcode, \ + uint32_t fetchdat, uint32_t op_32, \ + uint32_t op_pc, codeblock_t *block) \ +{ \ + uint32_t offset = fastreadl(cs + op_pc); \ + \ + func(4, op_pc, offset, not); \ + \ + return op_pc+4; \ +} + +ropBRANCH(JB, BRANCH_COND_B, 0) +ropBRANCH(JNB, BRANCH_COND_B, 1) +ropBRANCH(JE, BRANCH_COND_E, 0) +ropBRANCH(JNE, BRANCH_COND_E, 1) +ropBRANCH(JO, BRANCH_COND_O, 0) +ropBRANCH(JNO, BRANCH_COND_O, 1) +ropBRANCH(JP, BRANCH_COND_P, 0) +ropBRANCH(JNP, BRANCH_COND_P, 1) +ropBRANCH(JS, BRANCH_COND_S, 0) +ropBRANCH(JNS, BRANCH_COND_S, 1) +ropBRANCH(JL, BRANCH_COND_L, 0) +ropBRANCH(JNL, BRANCH_COND_L, 1) +ropBRANCH(JLE, BRANCH_COND_LE, 0) +ropBRANCH(JNLE, BRANCH_COND_LE, 1) +ropBRANCH(JBE, BRANCH_COND_BE, 0) +ropBRANCH(JNBE, BRANCH_COND_BE, 1) diff --git a/src/codegen_ops_logic.h b/src/codegen_ops_logic.h new file mode 100644 index 000000000..02384cd97 --- /dev/null +++ b/src/codegen_ops_logic.h @@ -0,0 +1,507 @@ +#define ROP_LOGIC(name, op, writeback) \ + static uint32_t rop ## name ## _b_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + \ + if ((fetchdat & 0xc0) != 0xc0) \ + return 0; \ + \ + dst_reg = LOAD_REG_B(fetchdat & 7); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); \ + src_reg = LOAD_REG_B((fetchdat >> 3) & 7); \ + op ## _HOST_REG_B(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) STORE_REG_B_RELEASE(dst_reg); \ + else RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + return op_pc + 1; \ + } \ + static uint32_t rop ## name ## _w_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + \ + if ((fetchdat & 0xc0) != 0xc0) \ + return 0; \ + \ + dst_reg = LOAD_REG_W(fetchdat & 7); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); \ + src_reg = LOAD_REG_W((fetchdat >> 3) & 7); \ + op ## _HOST_REG_W(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) STORE_REG_W_RELEASE(dst_reg); \ + else RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + return op_pc + 1; \ + } \ + static uint32_t rop ## name ## _l_rmw(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + \ + if ((fetchdat & 0xc0) != 0xc0) \ + return 0; \ + \ + dst_reg = LOAD_REG_L(fetchdat & 7); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); \ + src_reg = LOAD_REG_L((fetchdat >> 3) & 7); \ + op ## _HOST_REG_L(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) STORE_REG_L_RELEASE(dst_reg); \ + else RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + return op_pc + 1; \ + } \ + static uint32_t rop ## name ## _b_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + src_reg = LOAD_REG_B(fetchdat & 7); \ + } \ + else \ + { \ + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); \ + MEM_LOAD_ADDR_EA_B(target_seg); \ + src_reg = 0; \ + } \ + \ + dst_reg = LOAD_REG_B((fetchdat >> 3) & 7); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); \ + op ## _HOST_REG_B(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) STORE_REG_B_RELEASE(dst_reg); \ + else RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + return op_pc + 1; \ + } \ + static uint32_t rop ## name ## _w_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + src_reg = LOAD_REG_W(fetchdat & 7); \ + } \ + else \ + { \ + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); \ + MEM_LOAD_ADDR_EA_W(target_seg); \ + src_reg = 0; \ + } \ + \ + dst_reg = LOAD_REG_W((fetchdat >> 3) & 7); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); \ + op ## _HOST_REG_W(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) STORE_REG_W_RELEASE(dst_reg); \ + else RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + return op_pc + 1; \ + } \ + static uint32_t rop ## name ## _l_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int src_reg, dst_reg; \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + src_reg = LOAD_REG_L(fetchdat & 7); \ + } \ + else \ + { \ + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); \ + MEM_LOAD_ADDR_EA_L(target_seg); \ + src_reg = 0; \ + } \ + \ + dst_reg = LOAD_REG_L((fetchdat >> 3) & 7); \ + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); \ + op ## _HOST_REG_L(dst_reg, src_reg); \ + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, dst_reg); \ + if (writeback) STORE_REG_L_RELEASE(dst_reg); \ + else RELEASE_REG(dst_reg); \ + RELEASE_REG(src_reg); \ + \ + return op_pc + 1; \ + } + +ROP_LOGIC(AND, AND, 1) +ROP_LOGIC(OR, OR, 1) +ROP_LOGIC(XOR, XOR, 1) + +static uint32_t ropTEST_b_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg; + + if ((fetchdat & 0xc0) == 0xc0) + { + src_reg = LOAD_REG_B(fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_B(target_seg); + src_reg = 0; + } + + dst_reg = LOAD_REG_B((fetchdat >> 3) & 7); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); + dst_reg = TEST_HOST_REG_B(dst_reg, src_reg); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, dst_reg); + RELEASE_REG(dst_reg); + RELEASE_REG(src_reg); + + return op_pc + 1; +} +static uint32_t ropTEST_w_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg; + + if ((fetchdat & 0xc0) == 0xc0) + { + src_reg = LOAD_REG_W(fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_W(target_seg); + src_reg = 0; + } + + dst_reg = LOAD_REG_W((fetchdat >> 3) & 7); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); + dst_reg = TEST_HOST_REG_W(dst_reg, src_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, dst_reg); + RELEASE_REG(dst_reg); + RELEASE_REG(src_reg); + + return op_pc + 1; +} +static uint32_t ropTEST_l_rm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg; + + if ((fetchdat & 0xc0) == 0xc0) + { + src_reg = LOAD_REG_L(fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_L(target_seg); + src_reg = 0; + } + + dst_reg = LOAD_REG_L((fetchdat >> 3) & 7); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); + dst_reg = TEST_HOST_REG_L(dst_reg, src_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, dst_reg); + RELEASE_REG(dst_reg); + RELEASE_REG(src_reg); + + return op_pc + 1; +} + +static uint32_t ropAND_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_B(REG_AL); + + AND_HOST_REG_IMM(host_reg, (fetchdat & 0xff) | 0xffffff00); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_B_RELEASE(host_reg); + + return op_pc + 1; +} +static uint32_t ropAND_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_W(REG_AX); + + AND_HOST_REG_IMM(host_reg, (fetchdat & 0xffff) | 0xffff0000); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_W_RELEASE(host_reg); + + return op_pc + 2; +} +static uint32_t ropAND_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_L(REG_EAX); + + fetchdat = fastreadl(cs + op_pc); + AND_HOST_REG_IMM(host_reg, fetchdat); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_L_RELEASE(host_reg); + + return op_pc + 4; +} + +static uint32_t ropOR_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_B(REG_AL); + + OR_HOST_REG_IMM(host_reg, fetchdat & 0xff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_B_RELEASE(host_reg); + + return op_pc + 1; +} +static uint32_t ropOR_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_W(REG_AX); + + OR_HOST_REG_IMM(host_reg, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_W_RELEASE(host_reg); + + return op_pc + 2; +} +static uint32_t ropOR_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_L(REG_EAX); + + fetchdat = fastreadl(cs + op_pc); + OR_HOST_REG_IMM(host_reg, fetchdat); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_L_RELEASE(host_reg); + + return op_pc + 4; +} + +static uint32_t ropTEST_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_B(REG_AL); + + host_reg = TEST_HOST_REG_IMM(host_reg, fetchdat & 0xff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + RELEASE_REG(host_reg); + + return op_pc + 1; +} +static uint32_t ropTEST_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_W(REG_AX); + + host_reg = TEST_HOST_REG_IMM(host_reg, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + RELEASE_REG(host_reg); + + return op_pc + 2; +} +static uint32_t ropTEST_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_L(REG_EAX); + + fetchdat = fastreadl(cs + op_pc); + host_reg = TEST_HOST_REG_IMM(host_reg, fetchdat); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + RELEASE_REG(host_reg); + + return op_pc + 4; +} + +static uint32_t ropXOR_AL_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_B(REG_AL); + + XOR_HOST_REG_IMM(host_reg, fetchdat & 0xff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_B_RELEASE(host_reg); + + return op_pc + 1; +} +static uint32_t ropXOR_AX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_W(REG_AX); + + XOR_HOST_REG_IMM(host_reg, fetchdat & 0xffff); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_W_RELEASE(host_reg); + + return op_pc + 2; +} +static uint32_t ropXOR_EAX_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_L(REG_EAX); + + fetchdat = fastreadl(cs + op_pc); + XOR_HOST_REG_IMM(host_reg, fetchdat); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + STORE_REG_L_RELEASE(host_reg); + + return op_pc + 4; +} + +static uint32_t ropF6(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + int host_reg; + uint8_t imm; + + switch (fetchdat & 0x38) + { + case 0x00: /*TEST b,#8*/ + if ((fetchdat & 0xc0) == 0xc0) + { + host_reg = LOAD_REG_B(fetchdat & 7); + imm = (fetchdat >> 8) & 0xff; + } + else + { + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + imm = fastreadb(cs + op_pc + 1); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_B(target_seg); + host_reg = 0; + } + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN8); + host_reg = TEST_HOST_REG_IMM(host_reg, imm); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); + RELEASE_REG(host_reg); + return op_pc + 2; + + case 0x10: /*NOT b*/ + if ((fetchdat & 0xc0) != 0xc0) + return 0; + host_reg = LOAD_REG_B(fetchdat & 7); + XOR_HOST_REG_IMM(host_reg, 0xff); + STORE_REG_B_RELEASE(host_reg); + return op_pc + 1; + + case 0x18: /*NEG b*/ + if ((fetchdat & 0xc0) != 0xc0) + return 0; + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB8); + host_reg = LOAD_REG_B(fetchdat & 7); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_op2, host_reg); + NEG_HOST_REG_B(host_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op1, 0); + STORE_REG_B_RELEASE(host_reg); + STORE_HOST_REG_ADDR_BL((uintptr_t)&cpu_state.flags_res, host_reg); + return op_pc + 1; + } + + return 0; +} +static uint32_t ropF7_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + int host_reg; + uint16_t imm; + + switch (fetchdat & 0x38) + { + case 0x00: /*TEST w,#*/ + if ((fetchdat & 0xc0) == 0xc0) + { + host_reg = LOAD_REG_W(fetchdat & 7); + imm = (fetchdat >> 8) & 0xffff; + } + else + { + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + imm = fastreadw(cs + op_pc + 1); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_W(target_seg); + host_reg = 0; + } + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN16); + host_reg = TEST_HOST_REG_IMM(host_reg, imm); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + RELEASE_REG(host_reg); + return op_pc + 3; + + case 0x10: /*NOT w*/ + if ((fetchdat & 0xc0) != 0xc0) + return 0; + host_reg = LOAD_REG_W(fetchdat & 7); + XOR_HOST_REG_IMM(host_reg, 0xffff); + STORE_REG_W_RELEASE(host_reg); + return op_pc + 1; + + case 0x18: /*NEG w*/ + if ((fetchdat & 0xc0) != 0xc0) + return 0; + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB16); + host_reg = LOAD_REG_W(fetchdat & 7); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_op2, host_reg); + NEG_HOST_REG_W(host_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op1, 0); + STORE_REG_W_RELEASE(host_reg); + STORE_HOST_REG_ADDR_WL((uintptr_t)&cpu_state.flags_res, host_reg); + return op_pc + 1; + } + + return 0; +} +static uint32_t ropF7_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + x86seg *target_seg; + int host_reg; + uint32_t imm; + + switch (fetchdat & 0x38) + { + case 0x00: /*TEST l,#*/ + if ((fetchdat & 0xc0) == 0xc0) + { + host_reg = LOAD_REG_L(fetchdat & 7); + imm = fastreadl(cs + op_pc + 1); + } + else + { + target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + imm = fastreadl(cs + op_pc + 1); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_L(target_seg); + host_reg = 0; + } + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_ZN32); + host_reg = TEST_HOST_REG_IMM(host_reg, imm); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + RELEASE_REG(host_reg); + return op_pc + 5; + + case 0x10: /*NOT l*/ + if ((fetchdat & 0xc0) != 0xc0) + return 0; + host_reg = LOAD_REG_L(fetchdat & 7); + XOR_HOST_REG_IMM(host_reg, 0xffffffff); + STORE_REG_L_RELEASE(host_reg); + return op_pc + 1; + + case 0x18: /*NEG l*/ + if ((fetchdat & 0xc0) != 0xc0) + return 0; + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op, FLAGS_SUB32); + host_reg = LOAD_REG_L(fetchdat & 7); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_op2, host_reg); + NEG_HOST_REG_L(host_reg); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.flags_op1, 0); + STORE_REG_L_RELEASE(host_reg); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.flags_res, host_reg); + return op_pc + 1; + } + + return 0; +} diff --git a/src/codegen_ops_misc.h b/src/codegen_ops_misc.h new file mode 100644 index 000000000..7ed3ceeb9 --- /dev/null +++ b/src/codegen_ops_misc.h @@ -0,0 +1,115 @@ +static uint32_t ropNOP(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + return op_pc; +} + +static uint32_t ropCLD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + CLEAR_BITS((uintptr_t)&flags, D_FLAG); + return op_pc; +} +static uint32_t ropSTD(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + SET_BITS((uintptr_t)&flags, D_FLAG); + return op_pc; +} + +static uint32_t codegen_temp; +static uint32_t ropFF_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + if ((fetchdat & 0x38) != 0x10 && (fetchdat & 0x38) != 0x20)// && (fetchdat & 0x38) != 0x30) + return 0; + + if ((fetchdat & 0xc0) == 0xc0) + { + host_reg = LOAD_REG_W(fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_W(target_seg); + host_reg = 0; + } + + switch (fetchdat & 0x38) + { + case 0x10: /*CALL*/ + STORE_HOST_REG_ADDR_W((uintptr_t)&codegen_temp, host_reg); + RELEASE_REG(host_reg); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(-2); + host_reg = LOAD_REG_IMM(op_pc + 1); + MEM_STORE_ADDR_EA_W(&_ss, host_reg); + SP_MODIFY(-2); + + host_reg = LOAD_VAR_W((uintptr_t)&codegen_temp); + STORE_HOST_REG_ADDR_W((uintptr_t)&cpu_state.pc, host_reg); + return -1; + + case 0x20: /*JMP*/ + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.pc, host_reg); + return -1; + + case 0x30: /*PUSH*/ + if (!host_reg) + host_reg = LOAD_HOST_REG(host_reg); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(-2); + MEM_STORE_ADDR_EA_W(&_ss, host_reg); + SP_MODIFY(-2); + return op_pc + 1; + } +} +static uint32_t ropFF_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + if ((fetchdat & 0x38) != 0x10 && (fetchdat & 0x38) != 0x20)// && (fetchdat & 0x38) != 0x30) + return 0; + + if ((fetchdat & 0xc0) == 0xc0) + { + host_reg = LOAD_REG_L(fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + MEM_LOAD_ADDR_EA_L(target_seg); + host_reg = 0; + } + + switch (fetchdat & 0x38) + { + case 0x10: /*CALL*/ + STORE_HOST_REG_ADDR((uintptr_t)&codegen_temp, host_reg); + RELEASE_REG(host_reg); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(-4); + host_reg = LOAD_REG_IMM(op_pc + 1); + MEM_STORE_ADDR_EA_L(&_ss, host_reg); + SP_MODIFY(-4); + + host_reg = LOAD_VAR_L((uintptr_t)&codegen_temp); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.pc, host_reg); + return -1; + + case 0x20: /*JMP*/ + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.pc, host_reg); + return -1; + + case 0x30: /*PUSH*/ + if (!host_reg) + host_reg = LOAD_HOST_REG(host_reg); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(-4); + MEM_STORE_ADDR_EA_L(&_ss, host_reg); + SP_MODIFY(-4); + return op_pc + 1; + } +} diff --git a/src/codegen_ops_mmx.h b/src/codegen_ops_mmx.h new file mode 100644 index 000000000..9d8b49c84 --- /dev/null +++ b/src/codegen_ops_mmx.h @@ -0,0 +1,277 @@ +static uint32_t ropMOVQ_q_mm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg1, host_reg2; + + MMX_ENTER(); + + LOAD_MMX_Q((fetchdat >> 3) & 7, &host_reg1, &host_reg2); + + if ((fetchdat & 0xc0) == 0xc0) + { + STORE_MMX_Q(fetchdat & 7, host_reg1, host_reg2); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_WRITE(target_seg); + CHECK_SEG_LIMITS(target_seg, 7); + + MEM_STORE_ADDR_EA_Q(target_seg, host_reg1, host_reg2); + } + + return op_pc + 1; +} + +static uint32_t ropMOVQ_mm_q(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + MMX_ENTER(); + + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg1, host_reg2; + + LOAD_MMX_Q(fetchdat & 7, &host_reg1, &host_reg2); + STORE_MMX_Q((fetchdat >> 3) & 7, host_reg1, host_reg2); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_Q(target_seg); + STORE_MMX_Q((fetchdat >> 3) & 7, LOAD_Q_REG_1, LOAD_Q_REG_2); + } + + return op_pc + 1; +} + +static uint32_t ropMOVD_l_mm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + MMX_ENTER(); + + host_reg = LOAD_MMX_D((fetchdat >> 3) & 7); + + if ((fetchdat & 0xc0) == 0xc0) + { + STORE_REG_TARGET_L_RELEASE(host_reg, fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_WRITE(target_seg); + CHECK_SEG_LIMITS(target_seg, 3); + + MEM_STORE_ADDR_EA_L(target_seg, host_reg); + } + + return op_pc + 1; +} +static uint32_t ropMOVD_mm_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + MMX_ENTER(); + + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg = LOAD_REG_L(fetchdat & 7); + STORE_MMX_LQ((fetchdat >> 3) & 7, host_reg); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_L(target_seg); + STORE_MMX_LQ((fetchdat >> 3) & 7, 0); + } + + return op_pc + 1; +} + +#define MMX_OP(name, func) \ +static uint32_t name(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ +{ \ + int src_reg1, src_reg2; \ + int xmm_src, xmm_dst; \ + \ + MMX_ENTER(); \ + \ + if ((fetchdat & 0xc0) == 0xc0) \ + { \ + xmm_src = LOAD_MMX_Q_MMX(fetchdat & 7); \ + } \ + else \ + { \ + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); \ + \ + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); \ + \ + CHECK_SEG_READ(target_seg); \ + \ + MEM_LOAD_ADDR_EA_Q(target_seg); \ + src_reg1 = LOAD_Q_REG_1; \ + src_reg2 = LOAD_Q_REG_2; \ + xmm_src = LOAD_INT_TO_MMX(src_reg1, src_reg2); \ + } \ + xmm_dst = LOAD_MMX_Q_MMX((fetchdat >> 3) & 7); \ + func(xmm_dst, xmm_src); \ + STORE_MMX_Q_MMX((fetchdat >> 3) & 7, xmm_dst); \ + \ + return op_pc + 1; \ +} + +MMX_OP(ropPAND, MMX_AND) +MMX_OP(ropPANDN, MMX_ANDN) +MMX_OP(ropPOR, MMX_OR) +MMX_OP(ropPXOR, MMX_XOR) + +MMX_OP(ropPADDB, MMX_ADDB) +MMX_OP(ropPADDW, MMX_ADDW) +MMX_OP(ropPADDD, MMX_ADDD) +MMX_OP(ropPADDSB, MMX_ADDSB) +MMX_OP(ropPADDSW, MMX_ADDSW) +MMX_OP(ropPADDUSB, MMX_ADDUSB) +MMX_OP(ropPADDUSW, MMX_ADDUSW) + +MMX_OP(ropPSUBB, MMX_SUBB) +MMX_OP(ropPSUBW, MMX_SUBW) +MMX_OP(ropPSUBD, MMX_SUBD) +MMX_OP(ropPSUBSB, MMX_SUBSB) +MMX_OP(ropPSUBSW, MMX_SUBSW) +MMX_OP(ropPSUBUSB, MMX_SUBUSB) +MMX_OP(ropPSUBUSW, MMX_SUBUSW) + +MMX_OP(ropPUNPCKLBW, MMX_PUNPCKLBW); +MMX_OP(ropPUNPCKLWD, MMX_PUNPCKLWD); +MMX_OP(ropPUNPCKLDQ, MMX_PUNPCKLDQ); +MMX_OP(ropPACKSSWB, MMX_PACKSSWB); +MMX_OP(ropPCMPGTB, MMX_PCMPGTB); +MMX_OP(ropPCMPGTW, MMX_PCMPGTW); +MMX_OP(ropPCMPGTD, MMX_PCMPGTD); +MMX_OP(ropPACKUSWB, MMX_PACKUSWB); +MMX_OP(ropPUNPCKHBW, MMX_PUNPCKHBW); +MMX_OP(ropPUNPCKHWD, MMX_PUNPCKHWD); +MMX_OP(ropPUNPCKHDQ, MMX_PUNPCKHDQ); +MMX_OP(ropPACKSSDW, MMX_PACKSSDW); + +MMX_OP(ropPCMPEQB, MMX_PCMPEQB); +MMX_OP(ropPCMPEQW, MMX_PCMPEQW); +MMX_OP(ropPCMPEQD, MMX_PCMPEQD); + +MMX_OP(ropPSRLW, MMX_PSRLW) +MMX_OP(ropPSRLD, MMX_PSRLD) +MMX_OP(ropPSRLQ, MMX_PSRLQ) +MMX_OP(ropPSRAW, MMX_PSRAW) +MMX_OP(ropPSRAD, MMX_PSRAD) +MMX_OP(ropPSLLW, MMX_PSLLW) +MMX_OP(ropPSLLD, MMX_PSLLD) +MMX_OP(ropPSLLQ, MMX_PSLLQ) + +MMX_OP(ropPMULLW, MMX_PMULLW); +MMX_OP(ropPMULHW, MMX_PMULHW); +MMX_OP(ropPMADDWD, MMX_PMADDWD); + +static uint32_t ropPSxxW_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int xmm_dst; + + if ((fetchdat & 0xc0) != 0xc0) + return 0; + if ((fetchdat & 0x08) || !(fetchdat & 0x30)) + return 0; + + MMX_ENTER(); + + xmm_dst = LOAD_MMX_Q_MMX(fetchdat & 7); + switch (fetchdat & 0x38) + { + case 0x10: /*PSRLW*/ + MMX_PSRLW_imm(xmm_dst, (fetchdat >> 8) & 0xff); + break; + case 0x20: /*PSRAW*/ + MMX_PSRAW_imm(xmm_dst, (fetchdat >> 8) & 0xff); + break; + case 0x30: /*PSLLW*/ + MMX_PSLLW_imm(xmm_dst, (fetchdat >> 8) & 0xff); + break; + } + STORE_MMX_Q_MMX(fetchdat & 7, xmm_dst); + + return op_pc + 2; +} +static uint32_t ropPSxxD_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int xmm_dst; + + if ((fetchdat & 0xc0) != 0xc0) + return 0; + if ((fetchdat & 0x08) || !(fetchdat & 0x30)) + return 0; + + MMX_ENTER(); + + xmm_dst = LOAD_MMX_Q_MMX(fetchdat & 7); + switch (fetchdat & 0x38) + { + case 0x10: /*PSRLD*/ + MMX_PSRLD_imm(xmm_dst, (fetchdat >> 8) & 0xff); + break; + case 0x20: /*PSRAD*/ + MMX_PSRAD_imm(xmm_dst, (fetchdat >> 8) & 0xff); + break; + case 0x30: /*PSLLD*/ + MMX_PSLLD_imm(xmm_dst, (fetchdat >> 8) & 0xff); + break; + } + STORE_MMX_Q_MMX(fetchdat & 7, xmm_dst); + + return op_pc + 2; +} +static uint32_t ropPSxxQ_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int xmm_dst; + + if ((fetchdat & 0xc0) != 0xc0) + return 0; + if ((fetchdat & 0x08) || !(fetchdat & 0x30)) + return 0; + + MMX_ENTER(); + + xmm_dst = LOAD_MMX_Q_MMX(fetchdat & 7); + switch (fetchdat & 0x38) + { + case 0x10: /*PSRLQ*/ + MMX_PSRLQ_imm(xmm_dst, (fetchdat >> 8) & 0xff); + break; + case 0x20: /*PSRAQ*/ + MMX_PSRAQ_imm(xmm_dst, (fetchdat >> 8) & 0xff); + break; + case 0x30: /*PSLLQ*/ + MMX_PSLLQ_imm(xmm_dst, (fetchdat >> 8) & 0xff); + break; + } + STORE_MMX_Q_MMX(fetchdat & 7, xmm_dst); + + return op_pc + 2; +} + +static uint32_t ropEMMS(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + codegen_mmx_entered = 0; + + return 0; +} diff --git a/src/codegen_ops_mov.h b/src/codegen_ops_mov.h new file mode 100644 index 000000000..ea1dfd006 --- /dev/null +++ b/src/codegen_ops_mov.h @@ -0,0 +1,506 @@ +static uint32_t ropMOV_rb_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + STORE_IMM_REG_B(opcode & 7, fetchdat & 0xff); + + return op_pc + 1; +} +static uint32_t ropMOV_rw_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + STORE_IMM_REG_W(opcode & 7, fetchdat & 0xffff); + + return op_pc + 2; +} +static uint32_t ropMOV_rl_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + fetchdat = fastreadl(cs + op_pc); + + STORE_IMM_REG_L(opcode & 7, fetchdat); + + return op_pc + 4; +} + + +static uint32_t ropMOV_b_r(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_B((fetchdat >> 3) & 7); + + if ((fetchdat & 0xc0) == 0xc0) + { + STORE_REG_TARGET_B_RELEASE(host_reg, fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_WRITE(target_seg); + CHECK_SEG_LIMITS(target_seg, 0); + + MEM_STORE_ADDR_EA_B(target_seg, host_reg); + RELEASE_REG(host_reg); + } + + return op_pc + 1; +} +static uint32_t ropMOV_w_r(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg = LOAD_REG_W((fetchdat >> 3) & 7); + + if ((fetchdat & 0xc0) == 0xc0) + { + STORE_REG_TARGET_W_RELEASE(host_reg, fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_WRITE(target_seg); + CHECK_SEG_LIMITS(target_seg, 1); + + MEM_STORE_ADDR_EA_W(target_seg, host_reg); + RELEASE_REG(host_reg); + } + + return op_pc + 1; +} + +static uint32_t ropMOV_l_r(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + host_reg = LOAD_REG_L((fetchdat >> 3) & 7); + + if ((fetchdat & 0xc0) == 0xc0) + { + STORE_REG_TARGET_L_RELEASE(host_reg, fetchdat & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_WRITE(target_seg); + CHECK_SEG_LIMITS(target_seg, 3); + + MEM_STORE_ADDR_EA_L(target_seg, host_reg); + RELEASE_REG(host_reg); + + } + + return op_pc + 1; +} + +static uint32_t ropMOV_r_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg = LOAD_REG_B(fetchdat & 7); + STORE_REG_TARGET_B_RELEASE(host_reg, (fetchdat >> 3) & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_B(target_seg); + STORE_REG_TARGET_B_RELEASE(0, (fetchdat >> 3) & 7); + } + + return op_pc + 1; +} +static uint32_t ropMOV_r_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg = LOAD_REG_W(fetchdat & 7); + STORE_REG_TARGET_W_RELEASE(host_reg, (fetchdat >> 3) & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_W(target_seg); + STORE_REG_TARGET_W_RELEASE(0, (fetchdat >> 3) & 7); + } + + return op_pc + 1; +} +static uint32_t ropMOV_r_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg = LOAD_REG_L(fetchdat & 7); + STORE_REG_TARGET_L_RELEASE(host_reg, (fetchdat >> 3) & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_L(target_seg); + STORE_REG_TARGET_L_RELEASE(0, (fetchdat >> 3) & 7); + } + + return op_pc + 1; +} + +static uint32_t ropMOV_b_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + STORE_IMM_REG_B(fetchdat & 7, (fetchdat >> 8) & 0xff); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + uint32_t imm = fastreadb(cs + op_pc + 1); + int host_reg = LOAD_REG_IMM(imm); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + CHECK_SEG_WRITE(target_seg); + + MEM_STORE_ADDR_EA_B(target_seg, host_reg); + RELEASE_REG(host_reg); + } + + return op_pc + 2; +} +static uint32_t ropMOV_w_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + STORE_IMM_REG_W(fetchdat & 7, (fetchdat >> 8) & 0xffff); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + uint32_t imm = fastreadw(cs + op_pc + 1); + int host_reg = LOAD_REG_IMM(imm); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + CHECK_SEG_WRITE(target_seg); + + MEM_STORE_ADDR_EA_W(target_seg, host_reg); + RELEASE_REG(host_reg); + } + + return op_pc + 3; +} +static uint32_t ropMOV_l_imm(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + uint32_t imm = fastreadl(cs + op_pc + 1); + + STORE_IMM_REG_L(fetchdat & 7, imm); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + uint32_t imm = fastreadl(cs + op_pc + 1); + int host_reg = LOAD_REG_IMM(imm); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + CHECK_SEG_WRITE(target_seg); + + MEM_STORE_ADDR_EA_L(target_seg, host_reg); + RELEASE_REG(host_reg); + } + + return op_pc + 5; +} + + +static uint32_t ropMOV_AL_a(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t addr; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + CHECK_SEG_READ(op_ea_seg); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + MEM_LOAD_ADDR_IMM_B(op_ea_seg, addr); + STORE_REG_TARGET_B_RELEASE(0, REG_AL); + + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} +static uint32_t ropMOV_AX_a(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t addr; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + CHECK_SEG_READ(op_ea_seg); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + MEM_LOAD_ADDR_IMM_W(op_ea_seg, addr); + STORE_REG_TARGET_W_RELEASE(0, REG_AX); + + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} +static uint32_t ropMOV_EAX_a(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t addr; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + CHECK_SEG_READ(op_ea_seg); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + MEM_LOAD_ADDR_IMM_L(op_ea_seg, addr); + STORE_REG_TARGET_L_RELEASE(0, REG_EAX); + + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} + +static uint32_t ropMOV_a_AL(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t addr; + int host_reg; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + CHECK_SEG_WRITE(op_ea_seg); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + host_reg = LOAD_REG_B(REG_AL); + + MEM_STORE_ADDR_IMM_B(op_ea_seg, addr, host_reg); + RELEASE_REG(host_reg); + + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} +static uint32_t ropMOV_a_AX(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t addr; + int host_reg; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + CHECK_SEG_WRITE(op_ea_seg); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + host_reg = LOAD_REG_W(REG_AX); + + MEM_STORE_ADDR_IMM_W(op_ea_seg, addr, host_reg); + RELEASE_REG(host_reg); + + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} +static uint32_t ropMOV_a_EAX(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t addr; + int host_reg; + + if (op_32 & 0x200) + addr = fastreadl(cs + op_pc); + else + addr = fastreadw(cs + op_pc); + + CHECK_SEG_WRITE(op_ea_seg); + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + host_reg = LOAD_REG_L(REG_EAX); + + MEM_STORE_ADDR_IMM_L(op_ea_seg, addr, host_reg); + RELEASE_REG(host_reg); + + return op_pc + ((op_32 & 0x200) ? 4 : 2); +} + +static uint32_t ropLEA_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int dest_reg = (fetchdat >> 3) & 7; + + if ((fetchdat & 0xc0) == 0xc0) + return 0; + + FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_REG_TARGET_W_RELEASE(0, dest_reg); + + return op_pc + 1; +} +static uint32_t ropLEA_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int dest_reg = (fetchdat >> 3) & 7; + + if ((fetchdat & 0xc0) == 0xc0) + return 0; + + FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_REG_TARGET_L_RELEASE(0, dest_reg); + + return op_pc + 1; +} + +static uint32_t ropMOVZX_w_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg = LOAD_REG_B(fetchdat & 7); + host_reg = ZERO_EXTEND_W_B(host_reg); + STORE_REG_TARGET_W_RELEASE(host_reg, (fetchdat >> 3) & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_B(target_seg); + ZERO_EXTEND_W_B(0); + STORE_REG_TARGET_W_RELEASE(0, (fetchdat >> 3) & 7); + } + + return op_pc + 1; +} +static uint32_t ropMOVZX_l_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg = LOAD_REG_B(fetchdat & 7); + host_reg = ZERO_EXTEND_L_B(host_reg); + STORE_REG_TARGET_L_RELEASE(host_reg, (fetchdat >> 3) & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_B(target_seg); + ZERO_EXTEND_L_B(0); + STORE_REG_TARGET_L_RELEASE(0, (fetchdat >> 3) & 7); + } + + return op_pc + 1; +} +static uint32_t ropMOVZX_l_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg = LOAD_REG_W(fetchdat & 7); + host_reg = ZERO_EXTEND_L_W(host_reg); + STORE_REG_TARGET_L_RELEASE(host_reg, (fetchdat >> 3) & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_W(target_seg); + ZERO_EXTEND_L_W(0); + STORE_REG_TARGET_L_RELEASE(0, (fetchdat >> 3) & 7); + } + + return op_pc + 1; +} + +static uint32_t ropMOVSX_w_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg = LOAD_REG_B(fetchdat & 7); + host_reg = SIGN_EXTEND_W_B(host_reg); + STORE_REG_TARGET_W_RELEASE(host_reg, (fetchdat >> 3) & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_B(target_seg); + SIGN_EXTEND_W_B(0); + STORE_REG_TARGET_W_RELEASE(0, (fetchdat >> 3) & 7); + } + + return op_pc + 1; +} +static uint32_t ropMOVSX_l_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg = LOAD_REG_B(fetchdat & 7); + host_reg = SIGN_EXTEND_L_B(host_reg); + STORE_REG_TARGET_L_RELEASE(host_reg, (fetchdat >> 3) & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_B(target_seg); + SIGN_EXTEND_L_B(0); + STORE_REG_TARGET_L_RELEASE(0, (fetchdat >> 3) & 7); + } + + return op_pc + 1; +} +static uint32_t ropMOVSX_l_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + if ((fetchdat & 0xc0) == 0xc0) + { + int host_reg = LOAD_REG_W(fetchdat & 7); + host_reg = SIGN_EXTEND_L_W(host_reg); + STORE_REG_TARGET_L_RELEASE(host_reg, (fetchdat >> 3) & 7); + } + else + { + x86seg *target_seg = FETCH_EA(op_ea_seg, fetchdat, op_ssegs, &op_pc, op_32); + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + + CHECK_SEG_READ(target_seg); + + MEM_LOAD_ADDR_EA_W(target_seg); + SIGN_EXTEND_L_W(0); + STORE_REG_TARGET_L_RELEASE(0, (fetchdat >> 3) & 7); + } + + return op_pc + 1; +} diff --git a/src/codegen_ops_shift.h b/src/codegen_ops_shift.h new file mode 100644 index 000000000..cedcf0c44 --- /dev/null +++ b/src/codegen_ops_shift.h @@ -0,0 +1,114 @@ +#define SHIFT(size, size2, count, res_store) \ + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op2, count); \ + reg = LOAD_REG_ ## size(fetchdat & 7); \ + res_store((uint32_t)&cpu_state.flags_op1, reg); \ + \ + switch (fetchdat & 0x38) \ + { \ + case 0x20: case 0x30: /*SHL*/ \ + SHL_ ## size ## _IMM(reg, count); \ + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SHL ## size2); \ + break; \ + \ + case 0x28: /*SHR*/ \ + SHR_ ## size ## _IMM(reg, count); \ + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SHR ## size2); \ + break; \ + \ + case 0x38: /*SAR*/ \ + SAR_ ## size ## _IMM(reg, count); \ + STORE_IMM_ADDR_L((uint32_t)&cpu_state.flags_op, FLAGS_SAR ## size2); \ + break; \ + } \ + \ + res_store((uint32_t)&cpu_state.flags_res, reg); \ + STORE_REG_ ## size ## _RELEASE(reg); + +static uint32_t ropC0(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int count; + int reg; + + if ((fetchdat & 0xc0) != 0xc0) + return 0; + if ((fetchdat & 0x38) < 0x20) + return 0; + + count = (fetchdat >> 8) & 0x1f; + + SHIFT(B, 8, count, STORE_HOST_REG_ADDR_BL); + + return op_pc + 2; +} +static uint32_t ropC1_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int count; + int reg; + + if ((fetchdat & 0xc0) != 0xc0) + return 0; + if ((fetchdat & 0x38) < 0x20) + return 0; + + count = (fetchdat >> 8) & 0x1f; + + SHIFT(W, 16, count, STORE_HOST_REG_ADDR_WL); + + return op_pc + 2; +} +static uint32_t ropC1_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int count; + int reg; + + if ((fetchdat & 0xc0) != 0xc0) + return 0; + if ((fetchdat & 0x38) < 0x20) + return 0; + + count = (fetchdat >> 8) & 0x1f; + + SHIFT(L, 32, count, STORE_HOST_REG_ADDR); + + return op_pc + 2; +} + +static uint32_t ropD0(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int reg; + + if ((fetchdat & 0xc0) != 0xc0) + return 0; + if ((fetchdat & 0x38) < 0x20) + return 0; + + SHIFT(B, 8, 1, STORE_HOST_REG_ADDR_BL); + + return op_pc + 1; +} +static uint32_t ropD1_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int reg; + + if ((fetchdat & 0xc0) != 0xc0) + return 0; + if ((fetchdat & 0x38) < 0x20) + return 0; + + SHIFT(W, 16, 1, STORE_HOST_REG_ADDR_WL); + + return op_pc + 1; +} +static uint32_t ropD1_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int reg; + + if ((fetchdat & 0xc0) != 0xc0) + return 0; + if ((fetchdat & 0x38) < 0x20) + return 0; + + SHIFT(L, 32, 1, STORE_HOST_REG_ADDR); + + return op_pc + 1; +} diff --git a/src/codegen_ops_stack.h b/src/codegen_ops_stack.h new file mode 100644 index 000000000..d0c943d16 --- /dev/null +++ b/src/codegen_ops_stack.h @@ -0,0 +1,250 @@ +static uint32_t ropPUSH_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(-2); + host_reg = LOAD_REG_W(opcode & 7); + MEM_STORE_ADDR_EA_W(&_ss, host_reg); + SP_MODIFY(-2); + + return op_pc; +} +static uint32_t ropPUSH_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(-4); + host_reg = LOAD_REG_L(opcode & 7); + MEM_STORE_ADDR_EA_L(&_ss, host_reg); + SP_MODIFY(-4); + + return op_pc; +} + +static uint32_t ropPUSH_imm_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint16_t imm = fetchdat & 0xffff; + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(-2); + host_reg = LOAD_REG_IMM(imm); + MEM_STORE_ADDR_EA_W(&_ss, host_reg); + SP_MODIFY(-2); + + return op_pc+2; +} +static uint32_t ropPUSH_imm_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t imm = fastreadl(cs + op_pc); + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(-4); + host_reg = LOAD_REG_IMM(imm); + MEM_STORE_ADDR_EA_L(&_ss, host_reg); + SP_MODIFY(-4); + + return op_pc+4; +} + +static uint32_t ropPUSH_imm_b16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint16_t imm = fetchdat & 0xff; + int host_reg; + + if (imm & 0x80) + imm |= 0xff00; + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(-2); + host_reg = LOAD_REG_IMM(imm); + MEM_STORE_ADDR_EA_W(&_ss, host_reg); + SP_MODIFY(-2); + + return op_pc+1; +} +static uint32_t ropPUSH_imm_b32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t imm = fetchdat & 0xff; + int host_reg; + + if (imm & 0x80) + imm |= 0xffffff00; + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(-4); + host_reg = LOAD_REG_IMM(imm); + MEM_STORE_ADDR_EA_L(&_ss, host_reg); + SP_MODIFY(-4); + + return op_pc+1; +} + +static uint32_t ropPOP_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(0); + MEM_LOAD_ADDR_EA_W(&_ss); + SP_MODIFY(2); + STORE_REG_TARGET_W_RELEASE(0, opcode & 7); + + return op_pc; +} +static uint32_t ropPOP_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(0); + MEM_LOAD_ADDR_EA_L(&_ss); + SP_MODIFY(4); + STORE_REG_TARGET_L_RELEASE(0, opcode & 7); + + return op_pc; +} + +static uint32_t ropRET_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(0); + MEM_LOAD_ADDR_EA_W(&_ss); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.pc, 0); + SP_MODIFY(2); + + return -1; +} +static uint32_t ropRET_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(0); + MEM_LOAD_ADDR_EA_L(&_ss); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.pc, 0); + SP_MODIFY(4); + + return -1; +} + +static uint32_t ropRET_imm_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint16_t offset = fetchdat & 0xffff; + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(0); + MEM_LOAD_ADDR_EA_W(&_ss); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.pc, 0); + SP_MODIFY(2+offset); + + return -1; +} +static uint32_t ropRET_imm_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint16_t offset = fetchdat & 0xffff; + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(0); + MEM_LOAD_ADDR_EA_L(&_ss); + STORE_HOST_REG_ADDR((uintptr_t)&cpu_state.pc, 0); + SP_MODIFY(4+offset); + + return -1; +} + +static uint32_t ropCALL_r16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint16_t offset = fetchdat & 0xffff; + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(-2); + host_reg = LOAD_REG_IMM(op_pc+2); + MEM_STORE_ADDR_EA_W(&_ss, host_reg); + SP_MODIFY(-2); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, (op_pc+2+offset) & 0xffff); + + return -1; +} +static uint32_t ropCALL_r32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + uint32_t offset = fastreadl(cs + op_pc); + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_STACK_TO_EA(-4); + host_reg = LOAD_REG_IMM(op_pc+4); + MEM_STORE_ADDR_EA_L(&_ss, host_reg); + SP_MODIFY(-4); + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, op_pc+4+offset); + + return -1; +} + +static uint32_t ropLEAVE_16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_EBP_TO_EA(0); + MEM_LOAD_ADDR_EA_W(&_ss); + host_reg = LOAD_REG_W(REG_BP); /*SP = BP + 2*/ + ADD_HOST_REG_IMM_W(host_reg, 2); + STORE_REG_TARGET_W_RELEASE(host_reg, REG_SP); + STORE_REG_TARGET_W_RELEASE(0, REG_BP); /*BP = POP_W()*/ + + return op_pc; +} +static uint32_t ropLEAVE_32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int host_reg; + + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); + LOAD_EBP_TO_EA(0); + MEM_LOAD_ADDR_EA_L(&_ss); + host_reg = LOAD_REG_L(REG_EBP); /*ESP = EBP + 4*/ + ADD_HOST_REG_IMM(host_reg, 4); + STORE_REG_TARGET_L_RELEASE(host_reg, REG_ESP); + STORE_REG_TARGET_L_RELEASE(0, REG_EBP); /*EBP = POP_L()*/ + + return op_pc; +} + +#define ROP_PUSH_SEG(seg) \ +static uint32_t ropPUSH_ ## seg ## _16(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ +{ \ + int host_reg; \ + \ + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); \ + LOAD_STACK_TO_EA(-2); \ + host_reg = LOAD_VAR_W((uintptr_t)&seg); \ + MEM_STORE_ADDR_EA_W(&_ss, host_reg); \ + SP_MODIFY(-2); \ + \ + return op_pc; \ +} \ +static uint32_t ropPUSH_ ## seg ## _32(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ +{ \ + int host_reg; \ + \ + STORE_IMM_ADDR_L((uintptr_t)&oldpc, op_old_pc); \ + LOAD_STACK_TO_EA(-4); \ + host_reg = LOAD_VAR_W((uintptr_t)&seg); \ + MEM_STORE_ADDR_EA_L(&_ss, host_reg); \ + SP_MODIFY(-4); \ + \ + return op_pc; \ +} + +ROP_PUSH_SEG(CS) +ROP_PUSH_SEG(DS) +ROP_PUSH_SEG(ES) +ROP_PUSH_SEG(SS) diff --git a/src/codegen_ops_x86-64.h b/src/codegen_ops_x86-64.h new file mode 100644 index 000000000..173acd222 --- /dev/null +++ b/src/codegen_ops_x86-64.h @@ -0,0 +1,4734 @@ +/*Register allocation : + R8-R15 - emulated registers +*/ + +#define HOST_REG_XMM_START 0 +#define HOST_REG_XMM_END 7 +static inline int find_host_xmm_reg() +{ + int c; + for (c = HOST_REG_XMM_START; c < HOST_REG_XMM_END; c++) + { + if (host_reg_xmm_mapping[c] == -1) + break; + } + + if (c == HOST_REG_XMM_END) + fatal("Out of host XMM regs!\n"); + return c; +} +static void call(codeblock_t *block, uintptr_t func) +{ + // uintptr_t diff = func - (uintptr_t)&block->data[block_pos + 5]; + intptr_t diff = func - (intptr_t)&block->data[block_pos + 5]; + + codegen_reg_loaded[0] = codegen_reg_loaded[1] = codegen_reg_loaded[2] = codegen_reg_loaded[3] = 0; + codegen_reg_loaded[4] = codegen_reg_loaded[5] = codegen_reg_loaded[6] = codegen_reg_loaded[7] = 0; + + if (diff >= -0x80000000 && diff < 0x7fffffff) + { + addbyte(0xE8); /*CALL*/ + addlong((uint32_t)diff); + } + else + { + addbyte(0x48); /*MOV RAX, func*/ + addbyte(0xb8); + addquad(func); + addbyte(0xff); /*CALL RAX*/ + addbyte(0xd0); + } +} + +static void call_long(uintptr_t func) +{ + codegen_reg_loaded[0] = codegen_reg_loaded[1] = codegen_reg_loaded[2] = codegen_reg_loaded[3] = 0; + codegen_reg_loaded[4] = codegen_reg_loaded[5] = codegen_reg_loaded[6] = codegen_reg_loaded[7] = 0; + + addbyte(0x48); /*MOV RAX, func*/ + addbyte(0xb8); + addquad(func); + addbyte(0xff); /*CALL RAX*/ + addbyte(0xd0); +} + +static void load_param_1_32(codeblock_t *block, uint32_t param) +{ +#if WIN64 + addbyte(0xb9); /*MOVL $fetchdat,%ecx*/ +#else + addbyte(0xbf); /*MOVL $fetchdat,%edi*/ +#endif + addlong(param); +} +static void load_param_1_reg_32(int reg) +{ +#if WIN64 + if (reg & 8) + addbyte(0x44); + addbyte(0x89); /*MOV ECX, EAX*/ + addbyte(0xc0 | REG_ECX | (reg << 3)); +#else + if (reg & 8) + addbyte(0x44); + addbyte(0x89); /*MOV EDI, EAX*/ + addbyte(0xc0 | REG_EDI | (reg << 3)); +#endif +} +static void load_param_1_64(codeblock_t *block, uint64_t param) +{ + addbyte(0x48); +#if WIN64 + addbyte(0xb9); /*MOVL $fetchdat,%ecx*/ +#else + addbyte(0xbf); /*MOVL $fetchdat,%edi*/ +#endif + addquad(param); +} + +static void load_param_2_32(codeblock_t *block, uint32_t param) +{ +#if WIN64 + addbyte(0xba); /*MOVL $fetchdat,%edx*/ +#else + addbyte(0xbe); /*MOVL $fetchdat,%esi*/ +#endif + addlong(param); +} +static void load_param_2_reg_32(int reg) +{ +#if WIN64 + if (reg & 8) + addbyte(0x44); + addbyte(0x89); /*MOV EDX, EAX*/ + addbyte(0xc0 | REG_EDX | (reg << 3)); +#else + if (reg & 8) + addbyte(0x44); + addbyte(0x89); /*MOV ESI, EAX*/ + addbyte(0xc0 | REG_ESI | (reg << 3)); +#endif +} +static void load_param_2_64(codeblock_t *block, uint64_t param) +{ + addbyte(0x48); +#if WIN64 + addbyte(0xba); /*MOVL $fetchdat,%edx*/ +#else + addbyte(0xbe); /*MOVL $fetchdat,%esi*/ +#endif + addquad(param); +} + +static void load_param_3_reg_32(int reg) +{ + if (reg & 8) + { +#if WIN64 + addbyte(0x45); /*MOVL R8,reg*/ + addbyte(0x89); + addbyte(0xc0 | ((reg & 7) << 3)); +#else + addbyte(0x44); /*MOV EDX, reg*/ + addbyte(0x89); + addbyte(0xc0 | REG_EDX | (reg << 3)); +#endif + } + else + { +#if WIN64 + addbyte(0x41); /*MOVL R8,reg*/ + addbyte(0x89); + addbyte(0xc0 | ((reg & 7) << 3)); +#else + addbyte(0x90); + addbyte(0x89); /*MOV EDX, reg*/ + addbyte(0xc0 | REG_EDX | (reg << 3)); +#endif + } +} +static void load_param_3_reg_64(int reg) +{ + if (reg & 8) + { +#if WIN64 + addbyte(0x4d); /*MOVL R8,reg*/ + addbyte(0x89); + addbyte(0xc0 | ((reg & 7) << 3)); +#else + addbyte(0x4c); /*MOVL EDX,reg*/ + addbyte(0x89); + addbyte(0xc0 | REG_EDX | ((reg & 7) << 3)); +#endif + } + else + { +#if WIN64 + addbyte(0x49); /*MOVL R8,reg*/ + addbyte(0x89); + addbyte(0xc0 | ((reg & 7) << 3)); +#else + addbyte(0x48); /*MOVL EDX,reg*/ + addbyte(0x89); + addbyte(0xc0 | REG_EDX | ((reg & 7) << 3)); +#endif + } +} + +static void CALL_FUNC(uintptr_t func) +{ + codegen_reg_loaded[0] = codegen_reg_loaded[1] = codegen_reg_loaded[2] = codegen_reg_loaded[3] = 0; + codegen_reg_loaded[4] = codegen_reg_loaded[5] = codegen_reg_loaded[6] = codegen_reg_loaded[7] = 0; + + addbyte(0x48); /*MOV RAX, func*/ + addbyte(0xb8); + addquad(func); + addbyte(0xff); /*CALL RAX*/ + addbyte(0xd0); +} + +static void RELEASE_REG(int host_reg) +{ +} + +static int LOAD_REG_B(int reg) +{ + int host_reg = reg & 3; +// host_reg_mapping[host_reg] = reg; + + if (!codegen_reg_loaded[reg & 3]) + { + addbyte(0x44); /*MOVZX W[reg],host_reg*/ + addbyte(0x8b); + addbyte(0x45 | (host_reg << 3)); + addbyte((uint32_t)&cpu_state.regs[host_reg & 3].b - (uint32_t)&EAX); + } + + codegen_reg_loaded[reg & 3] = 1; + + if (reg & 4) + return host_reg | 0x18; + + return host_reg | 8; +} +static int LOAD_REG_W(int reg) +{ + int host_reg = reg; +// host_reg_mapping[host_reg] = reg; + + if (!codegen_reg_loaded[reg & 7]) + { + addbyte(0x44); /*MOVZX W[reg],host_reg*/ + addbyte(0x8b); + addbyte(0x45 | (host_reg << 3)); + addbyte((uint32_t)&cpu_state.regs[reg & 7].w - (uint32_t)&EAX); + } + + codegen_reg_loaded[reg & 7] = 1; + + return host_reg | 8; +} +static int LOAD_REG_L(int reg) +{ + int host_reg = reg; +// host_reg_mapping[host_reg] = reg; + + if (!codegen_reg_loaded[reg & 7]) + { + addbyte(0x44); /*MOVZX W[reg],host_reg*/ + addbyte(0x8b); + addbyte(0x45 | (host_reg << 3)); + addbyte((uint32_t)&cpu_state.regs[reg & 7].l - (uint32_t)&EAX); + } + + codegen_reg_loaded[reg & 7] = 1; + + return host_reg | 8; +} + +static int LOAD_REG_IMM(uint32_t imm) +{ + int host_reg = REG_EBX; + + addbyte(0xb8 | REG_EBX); /*MOVL EBX, imm*/ + addlong(imm); + + return host_reg; +} + +static void STORE_REG_TARGET_B_RELEASE(int host_reg, int guest_reg) +{ + int dest_reg = LOAD_REG_L(guest_reg & 3) & 7; + + if (guest_reg & 4) + { + if (host_reg & 8) + { + addbyte(0x66); /*MOV AX, host_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((host_reg & 3) << 3)); + if (host_reg & 0x10) + { + addbyte(0x66); /*AND AX, 0xff00*/ + addbyte(0x25); + addword(0xff00); + } + else + { + addbyte(0x66); /*SHL AX, 8*/ + addbyte(0xc1); + addbyte(0xe0); + addbyte(0x08); + } + } + else + { + if (host_reg) + { + addbyte(0x66); /*MOV AX, host_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((host_reg & 3) << 3)); + } + addbyte(0x66); /*SHL AX, 8*/ + addbyte(0xc1); + addbyte(0xe0); + addbyte(0x08); + } + addbyte(0x66); /*AND dest_reg, 0x00ff*/ + addbyte(0x41); + addbyte(0x81); + addbyte(0xe0 | dest_reg); + addword(0x00ff); + addbyte(0x66); /*OR dest_reg, AX*/ + addbyte(0x41); + addbyte(0x09); + addbyte(0xc0 | dest_reg); + addbyte(0x66); /*MOVW regs[guest_reg].w, dest_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0x45 | (dest_reg << 3)); + addbyte((uint32_t)&cpu_state.regs[guest_reg & 3].w - (uint32_t)&EAX); + } + else + { + if (host_reg & 8) + { + if (host_reg & 0x10) + { + addbyte(0x66); /*MOV AX, host_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((host_reg & 3) << 3)); + addbyte(0x88); /*MOV AL, AH*/ + addbyte(0xe0); + addbyte(0x41); /*MOV dest_reg, AL*/ + addbyte(0x88); + addbyte(0xc0 | (dest_reg & 7)); + addbyte(0x88); /*MOVB regs[reg].b, AH*/ + addbyte(0x65); + addbyte((uint32_t)&cpu_state.regs[guest_reg & 3].b - (uint32_t)&EAX); + } + else + { + addbyte(0x45); /*MOVB dest_reg, host_reg*/ + addbyte(0x88); + addbyte(0xc0 | (dest_reg & 7) | ((host_reg & 7) << 3)); + addbyte(0x44); /*MOVB regs[guest_reg].b, host_reg*/ + addbyte(0x88); + addbyte(0x45 | ((host_reg & 3) << 3)); + addbyte((uint32_t)&cpu_state.regs[guest_reg & 3].b - (uint32_t)&EAX); + } + } + else + { + if (host_reg & 0x10) + { + addbyte(0xc1); /*SHR host_reg, 8*/ + addbyte(0xe8 | (host_reg & 7)); + addbyte(8); + } + addbyte(0x41); /*MOVB dest_reg, host_reg*/ + addbyte(0x88); + addbyte(0xc0 | (dest_reg & 7) | ((host_reg & 7) << 3)); + addbyte(0x88); /*MOVB regs[guest_reg].b, host_reg*/ + addbyte(0x45 | ((host_reg & 3) << 3)); + addbyte((uint32_t)&cpu_state.regs[guest_reg & 3].b - (uint32_t)&EAX); + } + } +} +static void STORE_REG_TARGET_W_RELEASE(int host_reg, int guest_reg) +{ + int dest_reg = LOAD_REG_L(guest_reg & 7) & 7; + + if (host_reg & 8) + { + addbyte(0x66); /*MOVW guest_reg, host_reg*/ + addbyte(0x45); + addbyte(0x89); + addbyte(0xc0 | dest_reg | ((host_reg & 7) << 3)); + addbyte(0x66); /*MOVW regs[guest_reg].w, host_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0x45 | ((host_reg & 7) << 3)); + addbyte((uint32_t)&cpu_state.regs[guest_reg & 7].w - (uint32_t)&EAX); + } + else + { + addbyte(0x66); /*MOVW guest_reg, host_reg*/ + addbyte(0x41); + addbyte(0x89); + addbyte(0xc0 | dest_reg | (host_reg << 3)); + addbyte(0x66); /*MOVW regs[guest_reg].w, host_reg*/ + addbyte(0x89); + addbyte(0x45 | (host_reg << 3)); + addbyte((uint32_t)&cpu_state.regs[guest_reg & 7].w - (uint32_t)&EAX); + } +} +static void STORE_REG_TARGET_L_RELEASE(int host_reg, int guest_reg) +{ + if (host_reg & 8) + { + addbyte(0x45); /*MOVL guest_reg, host_reg*/ + addbyte(0x89); + addbyte(0xc0 | guest_reg | (host_reg << 3)); + addbyte(0x44); /*MOVL regs[guest_reg].l, host_reg*/ + addbyte(0x89); + addbyte(0x45 | (host_reg << 3)); + addbyte((uint32_t)&cpu_state.regs[guest_reg & 7].l - (uint32_t)&EAX); + } + else + { + addbyte(0x41); /*MOVL guest_reg, host_reg*/ + addbyte(0x89); + addbyte(0xc0 | guest_reg | (host_reg << 3)); + addbyte(0x89); /*MOVL regs[guest_reg].l, host_reg*/ + addbyte(0x45 | (host_reg << 3)); + addbyte((uint32_t)&cpu_state.regs[guest_reg & 7].l - (uint32_t)&EAX); + } +} + +static void STORE_REG_B_RELEASE(int host_reg) +{ + if (host_reg & 0x10) + { + addbyte(0x66); /*MOVW [reg],host_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0x45 | ((host_reg & 7) << 3)); + addbyte((uint32_t)&cpu_state.regs[host_reg & 7].w - (uint32_t)&EAX); + } + else + { + addbyte(0x44); /*MOVB [reg],host_reg*/ + addbyte(0x88); + addbyte(0x45 | ((host_reg & 7) << 3)); + addbyte((uint32_t)&cpu_state.regs[host_reg & 7].b - (uint32_t)&EAX); + } +} +static void STORE_REG_W_RELEASE(int host_reg) +{ + addbyte(0x66); /*MOVW [reg],host_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0x45 | ((host_reg & 7) << 3)); + addbyte((uint32_t)&cpu_state.regs[host_reg & 7].w - (uint32_t)&EAX); +} +static void STORE_REG_L_RELEASE(int host_reg) +{ + addbyte(0x44); /*MOVL [reg],host_reg*/ + addbyte(0x89); + addbyte(0x45 | ((host_reg & 7) << 3)); + addbyte((uint32_t)&cpu_state.regs[host_reg & 7].l - (uint32_t)&EAX); +} + +static void STORE_IMM_REG_B(int reg, uint8_t val) +{ + if (reg & 4) + { + int host_reg = LOAD_REG_W(reg & 3) & 7; + addbyte(0x66); /*AND host_reg, 0x00ff*/ + addbyte(0x41); + addbyte(0x81); + addbyte(0xe0 | host_reg); + addword(0x00ff); + addbyte(0x66); /*OR host_reg, val << 8*/ + addbyte(0x41); + addbyte(0x81); + addbyte(0xc8 | host_reg); + addword(val << 8); + addbyte(0x66); /*MOVW host_reg, regs[host_reg].w*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0x45 | (host_reg << 3)); + addbyte((uint32_t)&cpu_state.regs[reg & 3].w - (uint32_t)&EAX); + } + else + { + addbyte(0x41); /*MOVB reg, imm*/ + addbyte(0xb0 | reg); + addbyte(val); + addbyte(0x44); /*MOVB reg, regs[reg].b*/ + addbyte(0x88); + addbyte(0x45 | (reg << 3)); + addbyte((uint32_t)&cpu_state.regs[reg & 7].b - (uint32_t)&EAX); + } +} +static void STORE_IMM_REG_W(int reg, uint16_t val) +{ + addbyte(0x66); /*MOVW reg, imm*/ + addbyte(0x41); + addbyte(0xb8 | reg); + addword(val); + addbyte(0x66); /*MOVW reg, regs[reg].w*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0x45 | (reg << 3)); + addbyte((uint32_t)&cpu_state.regs[reg & 7].w - (uint32_t)&EAX); +} +static void STORE_IMM_REG_L(int reg, uint32_t val) +{ + addbyte(0x41); /*MOVL reg, imm*/ + addbyte(0xb8 | reg); + addlong(val); + addbyte(0x44); /*MOVL reg, regs[reg].l*/ + addbyte(0x89); + addbyte(0x45 | (reg << 3)); + addbyte((uint32_t)&cpu_state.regs[reg & 7].l - (uint32_t)&EAX); +} + +static void STORE_IMM_ADDR_L(uintptr_t addr, uint32_t val) +{ + if (addr < 0x100000000) + { + addbyte(0xC7); /*MOVL [addr],val*/ + addbyte(0x04); + addbyte(0x25); + addlong(addr); + addlong(val); + } + else + { + fatal("addr > 32-bit\n"); + } +} + + + + +static x86seg *FETCH_EA_16(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc) +{ + int mod = (fetchdat >> 6) & 3; + int reg = (fetchdat >> 3) & 7; + int rm = fetchdat & 7; + + if (!mod && rm == 6) + { + addbyte(0xb8); /*MOVL EAX, imm*/ + addlong((fetchdat >> 8) & 0xffff); + (*op_pc) += 2; + } + else + { + int base_reg, index_reg; + + switch (rm) + { + case 0: case 1: case 7: + base_reg = LOAD_REG_W(REG_BX); + break; + case 2: case 3: case 6: + base_reg = LOAD_REG_W(REG_BP); + break; + case 4: + base_reg = LOAD_REG_W(REG_SI); + break; + case 5: + base_reg = LOAD_REG_W(REG_DI); + break; + } + if (!(rm & 4)) + { + if (rm & 1) + index_reg = LOAD_REG_W(REG_DI); + else + index_reg = LOAD_REG_W(REG_SI); + } + base_reg &= 7; + index_reg &= 7; + + switch (mod) + { + case 0: + if (rm & 4) + { + addbyte(0x41); /*MOVZX EAX, base_reg*/ + addbyte(0x0f); + addbyte(0xb7); + addbyte(0xc0 | base_reg); + } + else + { + addbyte(0x67); /*LEA EAX, base_reg+index_reg*/ + addbyte(0x43); + addbyte(0x8d); + if (base_reg == 5) + { + addbyte(0x44); + addbyte(base_reg | (index_reg << 3)); + addbyte(0); + } + else + { + addbyte(0x04); + addbyte(base_reg | (index_reg << 3)); + } + } + break; + case 1: + if (rm & 4) + { + addbyte(0x67); /*LEA EAX, base_reg+imm8*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x40 | base_reg); + addbyte((fetchdat >> 8) & 0xff); + } + else + { + addbyte(0x67); /*LEA EAX, base_reg+index_reg+imm8*/ + addbyte(0x43); + addbyte(0x8d); + addbyte(0x44); + addbyte(base_reg | (index_reg << 3)); + addbyte((fetchdat >> 8) & 0xff); + } + (*op_pc)++; + break; + case 2: + if (rm & 4) + { + addbyte(0x67); /*LEA EAX, base_reg+imm8*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x80 | base_reg); + addlong((fetchdat >> 8) & 0xffff); + } + else + { + addbyte(0x67); /*LEA EAX, base_reg+index_reg+imm16*/ + addbyte(0x43); + addbyte(0x8d); + addbyte(0x84); + addbyte(base_reg | (index_reg << 3)); + addlong((fetchdat >> 8) & 0xffff); + } + (*op_pc) += 2; + break; + + } + if (mod || !(rm & 4)) + { + addbyte(0x25); /*ANDL $0xffff, %eax*/ + addlong(0xffff); + } + + if (mod1seg[rm] == &ss && !op_ssegs) + op_ea_seg = &_ss; + } + return op_ea_seg; +} +static x86seg *FETCH_EA_32(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, int stack_offset) +{ + int mod = (fetchdat >> 6) & 3; + int reg = (fetchdat >> 3) & 7; + int rm = fetchdat & 7; + uint32_t new_eaaddr; + + if (rm == 4) + { + uint8_t sib = fetchdat >> 8; + int base_reg = -1, index_reg = -1; + + (*op_pc)++; + + if (mod || (sib & 7) != 5) + base_reg = LOAD_REG_L(sib & 7) & 7; + + if (((sib >> 3) & 7) != 4) + index_reg = LOAD_REG_L((sib >> 3) & 7) & 7; + + if (index_reg == -1) + { + switch (mod) + { + case 0: + if ((sib & 7) == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0xb8); /*MOV EAX, imm32*/ + addlong(new_eaaddr); + (*op_pc) += 4; + } + else + { + addbyte(0x44); /*MOV EAX, base_reg*/ + addbyte(0x89); + addbyte(0xc0 | (base_reg << 3)); + } + break; + case 1: + addbyte(0x67); /*LEA EAX, imm8+base_reg*/ + addbyte(0x41); + addbyte(0x8d); + if (base_reg == 4) + { + addbyte(0x44); + addbyte(0x24); + } + else + { + addbyte(0x40 | base_reg); + } + addbyte((fetchdat >> 16) & 0xff); + (*op_pc)++; + break; + case 2: + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0x67); /*LEA EAX, imm32+base_reg*/ + addbyte(0x41); + addbyte(0x8d); + if (base_reg == 4) + { + addbyte(0x84); + addbyte(0x24); + } + else + { + addbyte(0x80 | base_reg); + } + addlong(new_eaaddr); + (*op_pc) += 4; + break; + } + } + else + { + switch (mod) + { + case 0: + if ((sib & 7) == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + if (sib >> 6) + { + addbyte(0x67); /*LEA EAX, imm32+index_reg*scale*/ + addbyte(0x42); + addbyte(0x8d); + addbyte(0x04); + addbyte(0x05 | (sib & 0xc0) | (index_reg << 3)); + addlong(new_eaaddr); + } + else + { + addbyte(0x67); /*LEA EAX, imm32+index_reg*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x80 | index_reg); + addlong(new_eaaddr); + } + (*op_pc) += 4; + } + else + { + addbyte(0x67); /*LEA EAX, base_reg+index_reg*scale*/ + addbyte(0x43); + addbyte(0x8d); + if (base_reg == 5) + { + addbyte(0x44); + addbyte(base_reg | (index_reg << 3) | (sib & 0xc0)); + addbyte(0); + } + else + { + addbyte(0x04); + addbyte(base_reg | (index_reg << 3) | (sib & 0xc0)); + } + } + break; + case 1: + addbyte(0x67); /*LEA EAX, imm8+base_reg+index_reg*scale*/ + addbyte(0x43); + addbyte(0x8d); + addbyte(0x44); + addbyte(base_reg | (index_reg << 3) | (sib & 0xc0)); + addbyte((fetchdat >> 16) & 0xff); + (*op_pc)++; + break; + case 2: + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0x67); /*LEA EAX, imm32+base_reg+index_reg*scale*/ + addbyte(0x43); + addbyte(0x8d); + addbyte(0x84); + addbyte(base_reg | (index_reg << 3) | (sib & 0xc0)); + addlong(new_eaaddr); + (*op_pc) += 4; + break; + } + } + if (stack_offset && (sib & 7) == 4 && (mod || (sib & 7) != 5)) /*ESP*/ + { + addbyte(0x05); + addlong(stack_offset); + } + if (((sib & 7) == 4 || (mod && (sib & 7) == 5)) && !op_ssegs) + op_ea_seg = &_ss; + } + else + { + int base_reg; + + if (!mod && rm == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0xb8); /*MOVL EAX, new_eaaddr*/ + addlong(new_eaaddr); + (*op_pc) += 4; + return op_ea_seg; + } + base_reg = LOAD_REG_L(rm) & 7; + if (mod) + { + if (rm == 5 && !op_ssegs) + op_ea_seg = &_ss; + if (mod == 1) + { + addbyte(0x67); /*LEA EAX, base_reg+imm8*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x40 | base_reg); + addbyte((fetchdat >> 8) & 0xff); + (*op_pc)++; + } + else + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0x67); /*LEA EAX, base_reg+imm32*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x80 | base_reg); + addlong(new_eaaddr); + (*op_pc) += 4; + } + } + else + { + addbyte(0x44); /*MOV EAX, base_reg*/ + addbyte(0x89); + addbyte(0xc0 | (base_reg << 3)); + } + } + return op_ea_seg; +} + +static x86seg *FETCH_EA(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, uint32_t op_32) +{ + if (op_32 & 0x200) + return FETCH_EA_32(op_ea_seg, fetchdat, op_ssegs, op_pc, 0); + return FETCH_EA_16(op_ea_seg, fetchdat, op_ssegs, op_pc); +} + + + +static void CHECK_SEG_READ(x86seg *seg) +{ + /*Segments always valid in real/V86 mode*/ + if (!(cr0 & 1) || (eflags & VM_FLAG)) + return; + /*CS and SS must always be valid*/ + if (seg == &_cs || seg == &_ss) + return; + if (seg->checked) + return; + + addbyte(0x83); /*CMP seg->base, -1*/ + addbyte(0x3c); + addbyte(0x25); + addlong((uint32_t)&seg->base); + addbyte(-1); + addbyte(0x0f); /*JE end*/ + addbyte(0x84); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + + seg->checked = 1; +} +static void CHECK_SEG_WRITE(x86seg *seg) +{ + /*Segments always valid in real/V86 mode*/ + if (!(cr0 & 1) || (eflags & VM_FLAG)) + return; + /*CS and SS must always be valid*/ + if (seg == &_cs || seg == &_ss) + return; + if (seg->checked) + return; + + addbyte(0x83); /*CMP seg->base, -1*/ + addbyte(0x3c); + addbyte(0x25); + addlong((uint32_t)&seg->base); + addbyte(-1); + addbyte(0x0f); /*JE end*/ + addbyte(0x84); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + + seg->checked = 1; +} +static void CHECK_SEG_LIMITS(x86seg *seg, int end_offset) +{ + addbyte(0x3b); /*CMP EAX, seg->limit_low*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&seg->limit_low); + addbyte(0x0f); /*JB BLOCK_GPF_OFFSET*/ + addbyte(0x82); + addlong(BLOCK_GPF_OFFSET - (block_pos + 4)); + if (end_offset) + { + addbyte(0x83); /*ADD EAX, end_offset*/ + addbyte(0xc0); + addbyte(end_offset); + addbyte(0x3b); /*CMP EAX, seg->limit_high*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&seg->limit_high); + addbyte(0x0f); /*JNBE BLOCK_GPF_OFFSET*/ + addbyte(0x87); + addlong(BLOCK_GPF_OFFSET - (block_pos + 4)); + addbyte(0x83); /*SUB EAX, end_offset*/ + addbyte(0xe8); + addbyte(end_offset); + } +} + +#define IS_32_ADDR(x) !(((uintptr_t)x) & 0xffffffff00000000) + +static void MEM_LOAD_ADDR_EA_B(x86seg *seg) +{ + addbyte(0x8b); /*MOVL ECX, seg->base*/ + addbyte(0x0c); + addbyte(0x25); + addlong((uint32_t)&seg->base); + addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x08); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + if (IS_32_ADDR(readlookup2)) + { + addbyte(0x67); /*MOV RSI, readlookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)readlookup2); + } + else + { + addbyte(0x48); /*MOV RDX, readlookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)readlookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2); + addbyte(0x8b); /*MOV AL,[RDI+RSI]*/ + addbyte(0x04); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+12+8+6); + /*slowpath:*/ + load_param_1_reg_32(REG_ECX); + load_param_2_reg_32(REG_EAX); + call_long(readmemb386l); + addbyte(0x83); /*CMP abrt, 0*/ + addbyte(0x3c); + addbyte(0x25); + addlong((uint32_t)&abrt); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} +static void MEM_LOAD_ADDR_EA_W(x86seg *seg) +{ + addbyte(0x8b); /*MOVL ECX, seg->base*/ + addbyte(0x0c); + addbyte(0x25); + addlong((uint32_t)&seg->base); + addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x08); + addbyte(0x67); /*LEA EDI, 1[ESI]*/ + addbyte(0x8d); + addbyte(0x7e); + addbyte(0x01); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 0xfff*/ + addbyte(0xc7); + addlong(0xfff); + if (IS_32_ADDR(readlookup2)) + { + addbyte(0x67); /*MOV RSI, readlookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)readlookup2); + } + else + { + addbyte(0x48); /*MOV RDX, readlookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)readlookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2+5+2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(5+2); + addbyte(0x66); /*MOV AX,-1[RDI+RSI]*/ + addbyte(0x8b); + addbyte(0x44); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(-1); + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+12+8+6); + /*slowpath:*/ + load_param_1_reg_32(REG_ECX); + load_param_2_reg_32(REG_EAX); + call_long(readmemwl); + addbyte(0x83); /*CMP abrt, 0*/ + addbyte(0x3c); + addbyte(0x25); + addlong((uint32_t)&abrt); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} +static void MEM_LOAD_ADDR_EA_L(x86seg *seg) +{ + addbyte(0x8b); /*MOVL ECX, seg->base*/ + addbyte(0x0c); + addbyte(0x25); + addlong((uint32_t)&seg->base); + addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x08); + addbyte(0x67); /*LEA EDI, 3[ESI]*/ + addbyte(0x8d); + addbyte(0x7e); + addbyte(0x03); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 0xffc*/ + addbyte(0xc7); + addlong(0xffc); + if (IS_32_ADDR(readlookup2)) + { + addbyte(0x67); /*MOV RSI, readlookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)readlookup2); + } + else + { + addbyte(0x48); /*MOV RDX, readlookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)readlookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2+4+2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(4+2); + addbyte(0x8b); /*MOV EAX,-3[RDI+RSI]*/ + addbyte(0x44); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(-3); + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+12+8+6); + /*slowpath:*/ + load_param_1_reg_32(REG_ECX); + load_param_2_reg_32(REG_EAX); + call_long(readmemll); + addbyte(0x83); /*CMP abrt, 0*/ + addbyte(0x3c); + addbyte(0x25); + addlong((uint32_t)&abrt); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} +static void MEM_LOAD_ADDR_EA_Q(x86seg *seg) +{ + addbyte(0x8b); /*MOVL ECX, seg->base*/ + addbyte(0x0c); + addbyte(0x25); + addlong((uint32_t)&seg->base); + addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x08); + addbyte(0x67); /*LEA EDI, 7[ESI]*/ + addbyte(0x8d); + addbyte(0x7e); + addbyte(0x07); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 0xff8*/ + addbyte(0xc7); + addlong(0xff8); + if (IS_32_ADDR(readlookup2)) + { + addbyte(0x67); /*MOV RSI, readlookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)readlookup2); + } + else + { + addbyte(0x48); /*MOV RDX, readlookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)readlookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2+5+2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(5+2); + addbyte(0x48); /*MOV RAX,-7[RDI+RSI]*/ + addbyte(0x8b); + addbyte(0x44); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(-7); + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+12+8+6); + /*slowpath:*/ + load_param_1_reg_32(REG_ECX); + load_param_2_reg_32(REG_EAX); + call_long(readmemql); + addbyte(0x83); /*CMP abrt, 0*/ + addbyte(0x3c); + addbyte(0x25); + addlong((uint32_t)&abrt); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} + +static void MEM_LOAD_ADDR_IMM_B(x86seg *seg, uint32_t addr) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_LOAD_ADDR_EA_B(seg); +} +static void MEM_LOAD_ADDR_IMM_W(x86seg *seg, uint32_t addr) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_LOAD_ADDR_EA_W(seg); +} +static void MEM_LOAD_ADDR_IMM_L(x86seg *seg, uint32_t addr) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_LOAD_ADDR_EA_L(seg); +} + +static void MEM_STORE_ADDR_EA_B(x86seg *seg, int host_reg) +{ + if (host_reg & 0x10) + { + /*Handle high byte of register*/ + if (host_reg & 8) + { + addbyte(0x45); /*MOVL R8, host_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((host_reg & 7) << 3)); + } + else + { + addbyte(0x41); /*MOVL R8, host_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((host_reg & 7) << 3)); + } + addbyte(0x66); /*SHR R8, 8*/ + addbyte(0x41); + addbyte(0xc1); + addbyte(0xe8); + addbyte(8); + host_reg = 8; + } + addbyte(0x8b); /*MOVL ECX, seg->base*/ + addbyte(0x0c); + addbyte(0x25); + addlong((uint32_t)&seg->base); + addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x08); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xf7); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + if (IS_32_ADDR(writelookup2)) + { + addbyte(0x67); /*MOV RSI, writelookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)writelookup2); + } + else + { + addbyte(0x48); /*MOV RDX, writelookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)writelookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(((host_reg & 8) ? 4:3)+2); + if (host_reg & 8) + { + addbyte(0x44); /*MOV [RDI+RSI],host_reg*/ + addbyte(0x88); + addbyte(0x04 | ((host_reg & 7) << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + } + else + { + addbyte(0x88); /*MOV [RDI+RSI],host_reg*/ + addbyte(0x04 | (host_reg << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + } + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+3+12+8+6); + /*slowpath:*/ + load_param_1_reg_32(REG_ECX); + load_param_2_reg_32(REG_EAX); + load_param_3_reg_32(host_reg); + call_long(writememb386l); + addbyte(0x83); /*CMP abrt, 0*/ + addbyte(0x3c); + addbyte(0x25); + addlong((uint32_t)&abrt); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} +static void MEM_STORE_ADDR_EA_W(x86seg *seg, int host_reg) +{ + addbyte(0x8b); /*MOVL ECX, seg->base*/ + addbyte(0x0c); + addbyte(0x25); + addlong((uint32_t)&seg->base); + addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x08); + addbyte(0x67); /*LEA EDI, 1[ESI]*/ + addbyte(0x8d); + addbyte(0x7e); + addbyte(0x01); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 0xfff*/ + addbyte(0xc7); + addlong(0xfff); + if (IS_32_ADDR(writelookup2)) + { + addbyte(0x67); /*MOV RSI, writelookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)writelookup2); + } + else + { + addbyte(0x48); /*MOV RDX, writelookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)writelookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2+((host_reg & 8) ? 6:5)+2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(((host_reg & 8) ? 6:5)+2); + if (host_reg & 8) + { + addbyte(0x66); /*MOV -1[RDI+RSI],host_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0x44 | ((host_reg & 7) << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(-1); + } + else + { + addbyte(0x66); /*MOV -1[RDI+RSI],host_reg*/ + addbyte(0x89); + addbyte(0x44 | (host_reg << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(-1); + } + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+3+12+8+6); + /*slowpath:*/ + load_param_1_reg_32(REG_ECX); + load_param_2_reg_32(REG_EAX); + load_param_3_reg_32(host_reg); + call_long(writememwl); + addbyte(0x83); /*CMP abrt, 0*/ + addbyte(0x3c); + addbyte(0x25); + addlong((uint32_t)&abrt); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} +static void MEM_STORE_ADDR_EA_L(x86seg *seg, int host_reg) +{ + addbyte(0x8b); /*MOVL ECX, seg->base*/ + addbyte(0x0c); + addbyte(0x25); + addlong((uint32_t)&seg->base); + addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x08); + addbyte(0x67); /*LEA EDI, 3[ESI]*/ + addbyte(0x8d); + addbyte(0x7e); + addbyte(0x03); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 0xffc*/ + addbyte(0xc7); + addlong(0xffc); + if (IS_32_ADDR(writelookup2)) + { + addbyte(0x67); /*MOV RSI, writelookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)writelookup2); + } + else + { + addbyte(0x48); /*MOV RDX, writelookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)writelookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2+((host_reg & 8) ? 5:4)+2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(((host_reg & 8) ? 5:4)+2); + if (host_reg & 8) + { + addbyte(0x44); /*MOV -3[RDI+RSI],host_reg*/ + addbyte(0x89); + addbyte(0x44 | ((host_reg & 7) << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(-3); + } + else + { + addbyte(0x89); /*MOV -3[RDI+RSI],host_reg*/ + addbyte(0x44 | (host_reg << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(-3); + } + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+3+12+8+6); + /*slowpath:*/ + load_param_1_reg_32(REG_ECX); + load_param_2_reg_32(REG_EAX); + load_param_3_reg_32(host_reg); + call_long(writememll); + addbyte(0x83); /*CMP abrt, 0*/ + addbyte(0x3c); + addbyte(0x25); + addlong((uint32_t)&abrt); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} +static void MEM_STORE_ADDR_EA_Q(x86seg *seg, int host_reg, int host_reg2) +{ + addbyte(0x8b); /*MOVL ECX, seg->base*/ + addbyte(0x0c); + addbyte(0x25); + addlong((uint32_t)&seg->base); + addbyte(0x67); /*LEA ESI, (EAX,ECX)*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x08); + addbyte(0x67); /*LEA EDI, 7[ESI]*/ + addbyte(0x8d); + addbyte(0x7e); + addbyte(0x07); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 0xff8*/ + addbyte(0xc7); + addlong(0xff8); + if (IS_32_ADDR(writelookup2)) + { + addbyte(0x67); /*MOV RSI, writelookup2[ESI*8]*/ + addbyte(0x48); + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf5); + addlong((uint32_t)writelookup2); + } + else + { + addbyte(0x48); /*MOV RDX, writelookup2*/ + addbyte(0xb8 | REG_EDX); + addquad((uint64_t)writelookup2); + addbyte(0x48); /*MOV RSI, [RDX+RSI*8]*/ + addbyte(0x8b); + addbyte(0x34); + addbyte(0xf2); + } + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2+5+2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(5+2); + if (host_reg & 8) + { + addbyte(0x4c); /*MOV -7[RDI+RSI],host_reg*/ + addbyte(0x89); + addbyte(0x44 | ((host_reg & 7) << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(-7); + } + else + { + addbyte(0x48); /*MOV -3[RDI+RSI],host_reg*/ + addbyte(0x89); + addbyte(0x44 | (host_reg << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(-7); + } + addbyte(0xeb); /*JMP done*/ + addbyte(2+2+3+12+8+6); + /*slowpath:*/ + load_param_1_reg_32(REG_ECX); + load_param_2_reg_32(REG_EAX); + load_param_3_reg_64(host_reg); + call_long(writememql); + addbyte(0x83); /*CMP abrt, 0*/ + addbyte(0x3c); + addbyte(0x25); + addlong((uint32_t)&abrt); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} + +static void MEM_STORE_ADDR_IMM_B(x86seg *seg, uint32_t addr, int host_reg) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_STORE_ADDR_EA_B(seg, host_reg); +} +static void MEM_STORE_ADDR_IMM_W(x86seg *seg, uint32_t addr, int host_reg) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_STORE_ADDR_EA_W(seg, host_reg); +} +static void MEM_STORE_ADDR_IMM_L(x86seg *seg, uint32_t addr, int host_reg) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_STORE_ADDR_EA_L(seg, host_reg); +} + +static void STORE_HOST_REG_ADDR_BL(uintptr_t addr, int host_reg) +{ + if (host_reg & 0x10) + { + if (host_reg & 8) + addbyte(0x41); + addbyte(0x0f); /*MOVZX EBX, host_reg*/ + addbyte(0xb7); + addbyte(0xc0 | (REG_ECX << 3) | (host_reg & 7)); + addbyte(0xc1); /*SHR EBX, 8*/ + addbyte(0xe8 | REG_ECX); + addbyte(8); + } + else + { + if (host_reg & 8) + addbyte(0x41); + addbyte(0x0f); /*MOVZX EBX, host_reg*/ + addbyte(0xb6); + addbyte(0xc0 | (REG_ECX << 3) | (host_reg & 7)); + } + addbyte(0x89); /*MOV addr, EBX*/ + addbyte(0x04 | (REG_ECX << 3)); + addbyte(0x25); + addlong(addr); +} +static void STORE_HOST_REG_ADDR_WL(uintptr_t addr, int host_reg) +{ + if (host_reg & 8) + addbyte(0x41); + addbyte(0x0f); /*MOVZX ECX, host_reg*/ + addbyte(0xb7); + addbyte(0xc0 | (REG_ECX << 3) | (host_reg & 7)); + if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x80) + { + addbyte(0x89); /*MOV addr, ECX*/ + addbyte(0x45 | (REG_ECX << 3)); + addbyte((uint32_t)addr - (uint32_t)&cpu_state); + } + else + { + addbyte(0x89); /*MOV addr, ECX*/ + addbyte(0x04 | (REG_ECX << 3)); + addbyte(0x25); + addlong(addr); + } +} +static void STORE_HOST_REG_ADDR_W(uintptr_t addr, int host_reg) +{ + if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x80) + { + addbyte(0x66); /*MOVW [addr],host_reg*/ + if (host_reg & 8) + addbyte(0x44); + addbyte(0x89); + addbyte(0x45 | ((host_reg & 7) << 3)); + addbyte((uint32_t)addr - (uint32_t)&cpu_state); + } + else + { + addbyte(0x66); + if (host_reg & 8) + addbyte(0x44); + addbyte(0x89); /*MOVL addr,host_reg*/ + addbyte(0x04 | ((host_reg & 7) << 3)); + addbyte(0x25); + addlong(addr); + } +} +static void STORE_HOST_REG_ADDR(uintptr_t addr, int host_reg) +{ + if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x80) + { + if (host_reg & 8) + addbyte(0x44); + addbyte(0x89); /*MOVL [addr],host_reg*/ + addbyte(0x45 | ((host_reg & 7) << 3)); + addbyte((uint32_t)addr - (uint32_t)&cpu_state); + } + else + { + if (host_reg & 8) + addbyte(0x44); + addbyte(0x89); /*MOVL addr,host_reg*/ + addbyte(0x04 | ((host_reg & 7) << 3)); + addbyte(0x25); + addlong(addr); + } +} + +static void AND_HOST_REG_B(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0x66); /*MOVW AX, src_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((src_reg & 7) << 3)); + if (!(src_reg & 0x10)) + { + addbyte(0x66); /*SHL AX, 8*/ + addbyte(0xc1); + addbyte(0xe0); + addbyte(8); + } + addbyte(0x66); /*OR AX, 0x00ff*/ + addbyte(0x0d); + addword(0xff); + addbyte(0x66); /*ANDW dst_reg, AX*/ + addbyte(0x41); + addbyte(0x21); + addbyte(0xc0 | (dst_reg & 7)); + } + else if (src_reg & 0x10) + { + addbyte(0x66); /*MOVW AX, src_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((src_reg & 7) << 3)); + addbyte(0x66); /*SHR AX, 8*/ + addbyte(0xc1); + addbyte(0xe8); + addbyte(8); + addbyte(0x41); /*ANDB dst_reg, AL*/ + addbyte(0x20); + addbyte(0xc0 | (dst_reg & 7)); + } + else + { + addbyte(0x45); /*ANDB dst_reg, src_reg*/ + addbyte(0x20); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else if (dst_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0x66); /*SHL src_reg, 8*/ + addbyte(0xc1); + addbyte(0xe0 | src_reg); + addbyte(0x08); + addbyte(0x66); /*OR src_reg, 0xff*/ + addbyte(0x81); + addbyte(0xc8 | src_reg); + addword(0xff); + addbyte(0x66); /*ANDW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x21); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x41); /*ANDB dst_reg, src_reg*/ + addbyte(0x20); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else if (src_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0xc1); /*SHR dst_reg, 8*/ + addbyte(0xe8 | (dst_reg & 7)); + addbyte(8); + } + if (src_reg & 0x10) + { + addbyte(0x41); /*MOVZX EBX, src_reg*/ + addbyte(0x0f); + addbyte(0xb7); + addbyte(0xd8 | (src_reg & 7)); + addbyte(0xc1); /*SHR EBX, 8*/ + addbyte(0xeb); + addbyte(8); + addbyte(0x20); /*ANDB dst_reg, EBX*/ + addbyte(0xd8 | (dst_reg & 7)); + } + else + { + addbyte(0x44); /*ANDB dst_reg, src_reg*/ + addbyte(0x20); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else + { + if (dst_reg & 0x10) + { + addbyte(0xc1); /*SHR dst_reg, 8*/ + addbyte(0xe8 | (dst_reg & 7)); + addbyte(8); + } + if (src_reg & 0x10) + { + addbyte(0x0f); /*MOVZX EBX, src_reg*/ + addbyte(0xb7); + addbyte(0xd8 | (src_reg & 7)); + addbyte(0xc1); /*SHR EBX, 8*/ + addbyte(0xeb); + addbyte(8); + addbyte(0x20); /*ANDB dst_reg, EBX*/ + addbyte(0xd8 | (dst_reg & 7)); + } + else + { + addbyte(0x20); /*ANDB dst_reg, src_reg*/ + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } +#if 0 + else if (dst_reg & 8) + { + if (dst_reg & 0x10) + { + if (src_reg & 0x10) + { + addbyte(0x66); /*SHL src_reg, 8*/ + addbyte(0xc1); + addbyte(0xe0 | src_reg); + addbyte(0x08); + addbyte(0x66); /*OR src_reg, 0xff*/ + addbyte(0x81); + addbyte(0xc8 | src_reg); + addword(0xff); + } + addbyte(0x66); /*ANDW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x21); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x41); /*ANDB dst_reg, src_reg*/ + addbyte(0x20); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else if (src_reg & 8) + { + if (src_reg & 0x10) + { + addbyte(0x66); /*OR src_reg, 0xff*/ + addbyte(0x81); + addbyte(0xc8 | src_reg); + addword(0xff); + } + if (src_reg & 0x10) + { + addbyte(0x66); /*SHL src_reg, 8*/ + addbyte(0xc1); + addbyte(0xe0 | src_reg); + addbyte(0x08); + addbyte(0x66); /*OR src_reg, 0xff*/ + addbyte(0x81); + addbyte(0xc8 | src_reg); + addword(0xff); + } + addbyte(0x66); /*ANDW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x21); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x41); /*ANDB dst_reg, src_reg*/ + addbyte(0x20); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else + fatal("!(dst_reg & src_reg & 8) b %i %i\n", dst_reg, src_reg); +#endif +} +static void AND_HOST_REG_W(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + addbyte(0x66); /*ANDW dst_reg, src_reg*/ + addbyte(0x45); + addbyte(0x21); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (dst_reg & 8) + { + addbyte(0x66); /*ANDW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x21); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (src_reg & 8) + { + addbyte(0x66); /*ANDW dst_reg, src_reg*/ + addbyte(0x44); + addbyte(0x21); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x66); /*ANDW dst_reg, src_reg*/ + addbyte(0x21); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } +} +static void AND_HOST_REG_L(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + addbyte(0x45); /*ANDL dst_reg, src_reg*/ + addbyte(0x21); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (dst_reg & 8) + { + addbyte(0x41); /*ANDL dst_reg, src_reg*/ + addbyte(0x21); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (src_reg & 8) + { + addbyte(0x44); /*ANDL dst_reg, src_reg*/ + addbyte(0x21); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x21); /*ANDL dst_reg, src_reg*/ + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } +} +static void AND_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + if (host_reg & 0x10) + { + addbyte(0x66); /*ANDW host_reg, imm<<8*/ + if (host_reg & 8) + addbyte(0x41); + addbyte(0x81); + addbyte(0xe0 | (host_reg & 7)); + addword((imm << 8) | 0xff); + } + else + { + if (host_reg & 8) + addbyte(0x41); + addbyte(0x81); /*ANDL host_reg, imm*/ + addbyte(0xe0 | (host_reg & 7)); + addlong(imm); + } +} + +static int TEST_HOST_REG_B(int dst_reg, int src_reg) +{ + if (dst_reg & 8) + { + addbyte(0x44); /*MOV EDX, dst_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((dst_reg & 7) << 3) | REG_EDX); + + dst_reg = (dst_reg & 0x10) | REG_EDX; + } + + AND_HOST_REG_B(dst_reg, src_reg); + + return dst_reg & ~0x10; +} +static int TEST_HOST_REG_W(int dst_reg, int src_reg) +{ + if (dst_reg & 8) + { + addbyte(0x44); /*MOV EDX, dst_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((dst_reg & 7) << 3) | REG_EDX); + + dst_reg = REG_EDX; + } + + AND_HOST_REG_W(dst_reg, src_reg); + + return dst_reg; +} +static int TEST_HOST_REG_L(int dst_reg, int src_reg) +{ + if (dst_reg & 8) + { + addbyte(0x44); /*MOV EDX, dst_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((dst_reg & 7) << 3) | REG_EDX); + + dst_reg = REG_EDX; + } + + AND_HOST_REG_L(dst_reg, src_reg); + + return dst_reg; +} +static int TEST_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + if (host_reg & 8) + { + addbyte(0x44); /*MOV EDX, host_reg*/ + addbyte(0x89); + addbyte(0xc0 | REG_EDX | ((host_reg & 7) << 3)); + host_reg = REG_EDX | (host_reg & 0x10); + } + if (host_reg & 0x10) + { + addbyte(0x66); /*ANDW host_reg, imm<<8*/ + addbyte(0x81); + addbyte(0xe0 | (host_reg & 7)); + addword((imm << 8) | 0xff); + } + else + { + addbyte(0x81); /*ANDL host_reg, imm*/ + addbyte(0xe0 | (host_reg & 7)); + addlong(imm); + } + + return host_reg; +} + +static void OR_HOST_REG_B(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0x66); /*MOVW AX, src_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((src_reg & 7) << 3)); + if (!(src_reg & 0x10)) + { + addbyte(0x66); /*SHL AX, 8*/ + addbyte(0xc1); + addbyte(0xe0); + addbyte(8); + } + else + { + addbyte(0x66); /*AND AX, 0xff00*/ + addbyte(0x25); + addword(0xff00); + } + addbyte(0x66); /*ORW dst_reg, AX*/ + addbyte(0x41); + addbyte(0x09); + addbyte(0xc0 | (dst_reg & 7)); + } + else if (src_reg & 0x10) + { + addbyte(0x66); /*MOVW AX, src_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((src_reg & 7) << 3)); + addbyte(0x66); /*SHR AX, 8*/ + addbyte(0xc1); + addbyte(0xe8); + addbyte(8); + addbyte(0x41); /*ORB dst_reg, AL*/ + addbyte(0x08); + addbyte(0xc0 | (dst_reg & 7)); + } + else + { + addbyte(0x45); /*ORB dst_reg, src_reg*/ + addbyte(0x08); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else if (dst_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0x66); /*SHL src_reg, 8*/ + addbyte(0xc1); + addbyte(0xe0 | src_reg); + addbyte(0x08); + addbyte(0x66); /*ORW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x09); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x41); /*ORB dst_reg, src_reg*/ + addbyte(0x08); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else + fatal("!(dst_reg & src_reg & 8)\n"); +} +static void OR_HOST_REG_W(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + addbyte(0x66); /*ORW dst_reg, src_reg*/ + addbyte(0x45); + addbyte(0x09); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (dst_reg & 8) + { + addbyte(0x66); /*ORW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x09); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + fatal("!(dst_reg & src_reg & 8)\n"); +} +static void OR_HOST_REG_L(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + addbyte(0x45); /*ORL dst_reg, src_reg*/ + addbyte(0x09); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (dst_reg & 8) + { + addbyte(0x41); /*ORL dst_reg, src_reg*/ + addbyte(0x09); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + fatal("!(dst_reg & src_reg & 8)\n"); +} +static void OR_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + if (host_reg & 0x10) + { + addbyte(0x66); /*ORW host_reg, imm<<8*/ + addbyte(0x41); + addbyte(0x81); + addbyte(0xc8 | (host_reg & 7)); + addword(imm << 8); + } + else if (host_reg & 8) + { + addbyte(0x41); /*ORL host_reg, imm*/ + addbyte(0x81); + addbyte(0xc8 | (host_reg & 7)); + addlong(imm); + } + else + fatal("OR to bad register\n"); +} + +static void XOR_HOST_REG_B(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0x66); /*MOVW AX, src_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((src_reg & 7) << 3)); + if (!(src_reg & 0x10)) + { + addbyte(0x66); /*SHL AX, 8*/ + addbyte(0xc1); + addbyte(0xe0); + addbyte(8); + } + else + { + addbyte(0x66); /*AND AX, 0xff00*/ + addbyte(0x25); + addword(0xff00); + } + addbyte(0x66); /*XORW dst_reg, AX*/ + addbyte(0x41); + addbyte(0x31); + addbyte(0xc0 | (dst_reg & 7)); + } + else if (src_reg & 0x10) + { + addbyte(0x66); /*MOVW AX, src_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((src_reg & 7) << 3)); + addbyte(0x66); /*SHR AX, 8*/ + addbyte(0xc1); + addbyte(0xe8); + addbyte(8); + addbyte(0x41); /*XORB dst_reg, AL*/ + addbyte(0x30); + addbyte(0xc0 | (dst_reg & 7)); + } + else + { + addbyte(0x45); /*XORB dst_reg, src_reg*/ + addbyte(0x30); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else if (dst_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0x66); /*SHL src_reg, 8*/ + addbyte(0xc1); + addbyte(0xe0 | src_reg); + addbyte(0x08); + addbyte(0x66); /*XORW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x31); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x41); /*XORB dst_reg, src_reg*/ + addbyte(0x30); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else + fatal("!(dst_reg & src_reg & 8)\n"); +} +static void XOR_HOST_REG_W(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + addbyte(0x66); /*XORW dst_reg, src_reg*/ + addbyte(0x45); + addbyte(0x31); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (dst_reg & 8) + { + addbyte(0x66); /*XORW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x31); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + fatal("!(dst_reg & src_reg & 8)\n"); +} +static void XOR_HOST_REG_L(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + addbyte(0x45); /*XORL dst_reg, src_reg*/ + addbyte(0x31); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (dst_reg & 8) + { + addbyte(0x41); /*XORL dst_reg, src_reg*/ + addbyte(0x31); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + fatal("!(dst_reg & src_reg & 8)\n"); +} +static void XOR_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + if (host_reg & 0x10) + { + addbyte(0x66); /*ORW host_reg, imm<<8*/ + addbyte(0x41); + addbyte(0x81); + addbyte(0xf0 | (host_reg & 7)); + addword(imm << 8); + } + else if (host_reg & 8) + { + addbyte(0x41); /*ORL host_reg, imm*/ + addbyte(0x81); + addbyte(0xf0 | (host_reg & 7)); + addlong(imm); + } + else + fatal("XOR to bad register\n"); +} + +static void ADD_HOST_REG_B(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0x66); /*MOVW AX, src_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((src_reg & 7) << 3)); + if (!(src_reg & 0x10)) + { + addbyte(0x66); /*SHL AX, 8*/ + addbyte(0xc1); + addbyte(0xe0); + addbyte(8); + } + else + { + addbyte(0x66); /*AND AX, 0xff00*/ + addbyte(0x25); + addword(0xff00); + } + addbyte(0x66); /*ADDW dst_reg, AX*/ + addbyte(0x41); + addbyte(0x01); + addbyte(0xc0 | (dst_reg & 7)); + } + else if (src_reg & 0x10) + { + addbyte(0x66); /*MOVW AX, src_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((src_reg & 7) << 3)); + addbyte(0x66); /*SHR AX, 8*/ + addbyte(0xc1); + addbyte(0xe8); + addbyte(8); + addbyte(0x41); /*ADDB dst_reg, AL*/ + addbyte(0x00); + addbyte(0xc0 | (dst_reg & 7)); + } + else + { + addbyte(0x45); /*ADDB dst_reg, src_reg*/ + addbyte(0x00); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else if (dst_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0x66); /*SHL src_reg, 8*/ + addbyte(0xc1); + addbyte(0xe0 | src_reg); + addbyte(0x08); + addbyte(0x66); /*ADDW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x01); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x41); /*ADDB dst_reg, src_reg*/ + addbyte(0x00); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else + fatal("!(dst_reg & src_reg & 8)\n"); +} +static void ADD_HOST_REG_W(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + addbyte(0x66); /*ADDW dst_reg, src_reg*/ + addbyte(0x45); + addbyte(0x01); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (dst_reg & 8) + { + addbyte(0x66); /*ADDW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x01); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + fatal("!(dst_reg & src_reg & 8)\n"); +} +static void ADD_HOST_REG_L(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + addbyte(0x45); /*ADDL dst_reg, src_reg*/ + addbyte(0x01); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (dst_reg & 8) + { + addbyte(0x41); /*ADDL dst_reg, src_reg*/ + addbyte(0x01); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + fatal("!(dst_reg & src_reg & 8)\n"); +} + +static void SUB_HOST_REG_B(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0x66); /*MOVW AX, src_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((src_reg & 7) << 3)); + if (!(src_reg & 0x10)) + { + addbyte(0x66); /*SHL AX, 8*/ + addbyte(0xc1); + addbyte(0xe0); + addbyte(8); + } + else + { + addbyte(0x66); /*AND AX, 0xff00*/ + addbyte(0x25); + addword(0xff00); + } + addbyte(0x66); /*SUBW dst_reg, AX*/ + addbyte(0x41); + addbyte(0x29); + addbyte(0xc0 | (dst_reg & 7)); + } + else if (src_reg & 0x10) + { + addbyte(0x66); /*MOVW AX, src_reg*/ + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | ((src_reg & 7) << 3)); + addbyte(0x66); /*SHR AX, 8*/ + addbyte(0xc1); + addbyte(0xe8); + addbyte(8); + addbyte(0x41); /*SUBB dst_reg, AL*/ + addbyte(0x28); + addbyte(0xc0 | (dst_reg & 7)); + } + else + { + addbyte(0x45); /*SUBB dst_reg, src_reg*/ + addbyte(0x28); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else if (dst_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0x66); /*SHL src_reg, 8*/ + addbyte(0xc1); + addbyte(0xe0 | src_reg); + addbyte(0x08); + addbyte(0x66); /*SUBW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x29); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x41); /*SUBB dst_reg, src_reg*/ + addbyte(0x28); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else if (src_reg & 8) + { + if (dst_reg & 0x10) + { + addbyte(0xc1); /*SHR dst_reg, 8*/ + addbyte(0xe8 | (dst_reg & 7)); + addbyte(8); + } + if (src_reg & 0x10) + { + addbyte(0x41); /*MOVZX EBX, src_reg*/ + addbyte(0x0f); + addbyte(0xb7); + addbyte(0xd8 | (src_reg & 7)); + addbyte(0xc1); /*SHR EBX, 8*/ + addbyte(0xeb); + addbyte(8); + addbyte(0x28); /*SUBB dst_reg, EBX*/ + addbyte(0xd8 | (dst_reg & 7)); + } + else + { + addbyte(0x44); /*SUBB dst_reg, src_reg*/ + addbyte(0x28); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + else + { + if (dst_reg & 0x10) + { + addbyte(0xc1); /*SHR dst_reg, 8*/ + addbyte(0xe8 | (dst_reg & 7)); + addbyte(8); + } + if (src_reg & 0x10) + { + addbyte(0x0f); /*MOVZX EBX, src_reg*/ + addbyte(0xb7); + addbyte(0xd8 | (src_reg & 7)); + addbyte(0xc1); /*SHR EBX, 8*/ + addbyte(0xeb); + addbyte(8); + addbyte(0x28); /*SUBB dst_reg, EBX*/ + addbyte(0xd8 | (dst_reg & 7)); + } + else + { + addbyte(0x28); /*SUBB dst_reg, src_reg*/ + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + } + +// fatal("!(dst_reg & src_reg & 8) subb %i %i\n", dst_reg, src_reg); +} +static void SUB_HOST_REG_W(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + addbyte(0x66); /*SUBW dst_reg, src_reg*/ + addbyte(0x45); + addbyte(0x29); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (dst_reg & 8) + { + addbyte(0x66); /*SUBW dst_reg, src_reg*/ + addbyte(0x41); + addbyte(0x29); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (src_reg & 8) + { + addbyte(0x66); /*SUBW dst_reg, src_reg*/ + addbyte(0x44); + addbyte(0x29); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x66); /*SUBW dst_reg, src_reg*/ + addbyte(0x29); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } +} +static void SUB_HOST_REG_L(int dst_reg, int src_reg) +{ + if (dst_reg & src_reg & 8) + { + addbyte(0x45); /*SUBL dst_reg, src_reg*/ + addbyte(0x29); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (dst_reg & 8) + { + addbyte(0x41); /*SUBL dst_reg, src_reg*/ + addbyte(0x29); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else if (src_reg & 8) + { + addbyte(0x44); /*SUBL dst_reg, src_reg*/ + addbyte(0x29); + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } + else + { + addbyte(0x29); /*SUBL dst_reg, src_reg*/ + addbyte(0xc0 | (dst_reg & 7) | ((src_reg & 7) << 3)); + } +} + +static int CMP_HOST_REG_B(int dst_reg, int src_reg) +{ + if (dst_reg & 8) + { + addbyte(0x44); /*MOV EDX, dst_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((dst_reg & 7) << 3) | REG_EDX); + + dst_reg = (dst_reg & 0x10) | REG_EDX; + } + + SUB_HOST_REG_B(dst_reg, src_reg); + + return dst_reg & ~0x10; +} +static int CMP_HOST_REG_W(int dst_reg, int src_reg) +{ + if (dst_reg & 8) + { + addbyte(0x44); /*MOV EDX, dst_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((dst_reg & 7) << 3) | REG_EDX); + + dst_reg = REG_EDX; + } + + SUB_HOST_REG_W(dst_reg, src_reg); + + return dst_reg; +} +static int CMP_HOST_REG_L(int dst_reg, int src_reg) +{ + if (dst_reg & 8) + { + addbyte(0x44); /*MOV EDX, dst_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((dst_reg & 7) << 3) | REG_EDX); + + dst_reg = REG_EDX; + } + + SUB_HOST_REG_L(dst_reg, src_reg); + + return dst_reg; +} + +static void ADD_HOST_REG_IMM_B(int host_reg, uint8_t imm) +{ + if (host_reg & 0x10) + { + addbyte(0x66); /*ADDW host_reg, imm*/ + addbyte(0x41); + addbyte(0x81); + addbyte(0xC0 | (host_reg & 7)); + addword(imm << 8); + } + else + { + addbyte(0x41); /*ADDB host_reg, imm*/ + addbyte(0x80); + addbyte(0xC0 | (host_reg & 7)); + addbyte(imm); + } +} +static void ADD_HOST_REG_IMM_W(int host_reg, uint16_t imm) +{ + addbyte(0x66); /*ADDW host_reg, imm*/ + addbyte(0x41); + addbyte(0x81); + addbyte(0xC0 | (host_reg & 7)); + addword(imm); +} +static void ADD_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + addbyte(0x41); /*ADDL host_reg, imm*/ + addbyte(0x81); + addbyte(0xC0 | (host_reg & 7)); + addlong(imm); +} + +static void SUB_HOST_REG_IMM_B(int host_reg, uint8_t imm) +{ + if (host_reg & 0x10) + { + addbyte(0x66); /*SUBW host_reg, imm*/ + if (host_reg & 8) + addbyte(0x41); + addbyte(0x81); + addbyte(0xE8 | (host_reg & 7)); + addword(imm << 8); + } + else + { + if (host_reg & 8) + addbyte(0x41); + addbyte(0x80); /*SUBB host_reg, imm*/ + addbyte(0xE8 | (host_reg & 7)); + addbyte(imm); + } +} +static void SUB_HOST_REG_IMM_W(int host_reg, uint16_t imm) +{ + addbyte(0x66); /*SUBW host_reg, imm*/ + if (host_reg & 8) + addbyte(0x41); + addbyte(0x81); + addbyte(0xE8 | (host_reg & 7)); + addword(imm); +} +static void SUB_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + if (host_reg & 8) + addbyte(0x41); + addbyte(0x81); /*SUBL host_reg, imm*/ + addbyte(0xE8 | (host_reg & 7)); + addlong(imm); +} + +static int CMP_HOST_REG_IMM_B(int host_reg, uint8_t imm) +{ + if (host_reg & 8) + { + addbyte(0x44); /*MOV EDX, dst_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((host_reg & 7) << 3) | REG_EDX); + + host_reg = (host_reg & 0x10) | REG_EDX; + } + + SUB_HOST_REG_IMM_B(host_reg, imm); + + return host_reg;// & ~0x10; +} +static int CMP_HOST_REG_IMM_W(int host_reg, uint16_t imm) +{ + if (host_reg & 8) + { + addbyte(0x44); /*MOV EDX, dst_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((host_reg & 7) << 3) | REG_EDX); + + host_reg = REG_EDX; + } + + SUB_HOST_REG_IMM_W(host_reg, imm); + + return host_reg; +} +static int CMP_HOST_REG_IMM_L(int host_reg, uint32_t imm) +{ + if (host_reg & 8) + { + addbyte(0x44); /*MOV EDX, dst_reg*/ + addbyte(0x89); + addbyte(0xc0 | ((host_reg & 7) << 3) | REG_EDX); + + host_reg = REG_EDX; + } + + SUB_HOST_REG_IMM(host_reg, imm); + + return host_reg; +} + +static void LOAD_STACK_TO_EA(int off) +{ + if (stack32) + { + addbyte(0x8b); /*MOVL EAX,[ESP]*/ + addbyte(0x45 | (REG_EAX << 3)); + addbyte((uint32_t)&ESP - (uint32_t)&EAX); + if (off) + { + addbyte(0x83); /*ADD EAX, off*/ + addbyte(0xc0 | (0 << 3) | REG_EAX); + addbyte(off); + } + } + else + { + addbyte(0x0f); /*MOVZX EAX,W[ESP]*/ + addbyte(0xb7); + addbyte(0x45 | (REG_EAX << 3)); + addbyte((uint32_t)&ESP - (uint32_t)&EAX); + if (off) + { + addbyte(0x66); /*ADD AX, off*/ + addbyte(0x05); + addword(off); + } + } +} +static void LOAD_EBP_TO_EA(int off) +{ + if (stack32) + { + addbyte(0x8b); /*MOVL EAX,[EBP]*/ + addbyte(0x45 | (REG_EAX << 3)); + addbyte((uint32_t)&EBP - (uint32_t)&EAX); + if (off) + { + addbyte(0x83); /*ADD EAX, off*/ + addbyte(0xc0 | (0 << 3) | REG_EAX); + addbyte(off); + } + } + else + { + addbyte(0x0f); /*MOVZX EAX,W[EBP]*/ + addbyte(0xb7); + addbyte(0x45 | (REG_EAX << 3)); + addbyte((uint32_t)&EBP - (uint32_t)&EAX); + if (off) + { + addbyte(0x66); /*ADD AX, off*/ + addbyte(0x05); + addword(off); + } + } +} + +static void SP_MODIFY(int off) +{ + if (stack32) + { + if (off < 0x80) + { + addbyte(0x83); /*ADD [ESP], off*/ + addbyte(0x45); + addbyte((uint32_t)&ESP - (uint32_t)&EAX); + addbyte(off); + } + else + { + addbyte(0x81); /*ADD [ESP], off*/ + addbyte(0x45); + addbyte((uint32_t)&ESP - (uint32_t)&EAX); + addlong(off); + } + } + else + { + if (off < 0x80) + { + addbyte(0x66); /*ADD [SP], off*/ + addbyte(0x83); + addbyte(0x45); + addbyte((uint32_t)&SP - (uint32_t)&EAX); + addbyte(off); + } + else + { + addbyte(0x66); /*ADD [SP], off*/ + addbyte(0x81); + addbyte(0x45); + addbyte((uint32_t)&SP - (uint32_t)&EAX); + addword(off); + } + } +} + +static void TEST_ZERO_JUMP_W(int host_reg, uint32_t new_pc, int taken_cycles) +{ + addbyte(0x66); /*CMPW host_reg, 0*/ + if (host_reg & 8) + addbyte(0x41); + addbyte(0x83); + addbyte(0xc0 | 0x38 | (host_reg & 7)); + addbyte(0); + addbyte(0x75); /*JNZ +*/ + addbyte(7+5+(taken_cycles ? 8 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.pc - (uintptr_t)&cpu_state); + addlong(new_pc); + if (taken_cycles) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2c); + addbyte(0x25); + addlong((uintptr_t)&cycles); + addbyte(taken_cycles); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} +static void TEST_ZERO_JUMP_L(int host_reg, uint32_t new_pc, int taken_cycles) +{ + if (host_reg & 8) + addbyte(0x41); + addbyte(0x83); /*CMPW host_reg, 0*/ + addbyte(0xc0 | 0x38 | (host_reg & 7)); + addbyte(0); + addbyte(0x75); /*JNZ +*/ + addbyte(7+5+(taken_cycles ? 8 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.pc - (uintptr_t)&cpu_state); + addlong(new_pc); + if (taken_cycles) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2c); + addbyte(0x25); + addlong((uintptr_t)&cycles); + addbyte(taken_cycles); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} + +static void TEST_NONZERO_JUMP_W(int host_reg, uint32_t new_pc, int taken_cycles) +{ + addbyte(0x66); /*CMPW host_reg, 0*/ + if (host_reg & 8) + addbyte(0x41); + addbyte(0x83); + addbyte(0xc0 | 0x38 | (host_reg & 7)); + addbyte(0); + addbyte(0x74); /*JZ +*/ + addbyte(7+5+(taken_cycles ? 8 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.pc - (uintptr_t)&cpu_state); + addlong(new_pc); + if (taken_cycles) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2c); + addbyte(0x25); + addlong((uintptr_t)&cycles); + addbyte(taken_cycles); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} +static void TEST_NONZERO_JUMP_L(int host_reg, uint32_t new_pc, int taken_cycles) +{ + if (host_reg & 8) + addbyte(0x41); + addbyte(0x83); /*CMPW host_reg, 0*/ + addbyte(0xc0 | 0x38 | (host_reg & 7)); + addbyte(0); + addbyte(0x74); /*JZ +*/ + addbyte(7+5+(taken_cycles ? 8 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.pc - (uintptr_t)&cpu_state); + addlong(new_pc); + if (taken_cycles) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2c); + addbyte(0x25); + addlong((uintptr_t)&cycles); + addbyte(taken_cycles); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} + +static int BRANCH_COND_BE(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + if (codegen_flags_changed && cpu_state.flags_op != FLAGS_UNKNOWN) + { + addbyte(0x83); /*CMP flags_res, 0*/ + addbyte(0x7d); + addbyte((uintptr_t)&cpu_state.flags_res - (uintptr_t)&cpu_state); + addbyte(0); + addbyte(0x74); /*JZ +*/ + } + else + { + CALL_FUNC(ZF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x75); /*JNZ +*/ + } + if (not) + addbyte(12+2+2+7+5+(timing_bt ? 8 : 0)); + else + addbyte(12+2+2); + CALL_FUNC(CF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + if (not) + addbyte(0x75); /*JNZ +*/ + else + addbyte(0x74); /*JZ +*/ + addbyte(7+5+(timing_bt ? 8 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.pc - (uintptr_t)&cpu_state); + addlong(op_pc+pc_offset+offset); + if (timing_bt) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2c); + addbyte(0x25); + addlong((uintptr_t)&cycles); + addbyte(timing_bt); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} + +static int BRANCH_COND_L(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + CALL_FUNC(NF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*SETNE BL*/ + addbyte(0x95); + addbyte(0xc3); + CALL_FUNC(VF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*SETNE AL*/ + addbyte(0x95); + addbyte(0xc0); + addbyte(0x38); /*CMP AL, BL*/ + addbyte(0xd8); + if (not) + addbyte(0x75); /*JNZ +*/ + else + addbyte(0x74); /*JZ +*/ + addbyte(7+5+(timing_bt ? 8 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.pc - (uintptr_t)&cpu_state); + addlong(op_pc+pc_offset+offset); + if (timing_bt) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2c); + addbyte(0x25); + addlong((uintptr_t)&cycles); + addbyte(timing_bt); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} + +static int BRANCH_COND_LE(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + if (codegen_flags_changed && cpu_state.flags_op != FLAGS_UNKNOWN) + { + addbyte(0x83); /*CMP flags_res, 0*/ + addbyte(0x7d); + addbyte((uintptr_t)&cpu_state.flags_res - (uintptr_t)&cpu_state); + addbyte(0); + addbyte(0x74); /*JZ +*/ + } + else + { + CALL_FUNC(ZF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x75); /*JNZ +*/ + } + if (not) + addbyte(12+2+3+12+2+3+2+2+7+5+(timing_bt ? 8 : 0)); + else + addbyte(12+2+3+12+2+3+2+2); + + CALL_FUNC(NF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*SETNE BL*/ + addbyte(0x95); + addbyte(0xc3); + CALL_FUNC(VF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*SETNE AL*/ + addbyte(0x95); + addbyte(0xc0); + addbyte(0x38); /*CMP AL, BL*/ + addbyte(0xd8); + if (not) + addbyte(0x75); /*JNZ +*/ + else + addbyte(0x74); /*JZ +*/ + addbyte(7+5+(timing_bt ? 8 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.pc - (uintptr_t)&cpu_state); + addlong(op_pc+pc_offset+offset); + if (timing_bt) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2c); + addbyte(0x25); + addlong((uintptr_t)&cycles); + addbyte(timing_bt); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} + +static int LOAD_VAR_W(uintptr_t addr) +{ + int host_reg = REG_EBX; + + addbyte(0x0f); /*MOVZX host_reg,[reg]*/ + addbyte(0xb7); + addbyte(0x04 | (host_reg << 3)); + addbyte(0x25); + addlong((uint32_t)addr); + + return host_reg; +} +static int LOAD_VAR_L(uintptr_t addr) +{ + int host_reg = REG_EBX; + + addbyte(0x8b); /*MOVL host_reg,[reg]*/ + addbyte(0x04 | (host_reg << 3)); + addbyte(0x25); + addlong((uint32_t)addr); + + return host_reg; +} + +static int COPY_REG(int src_reg) +{ + if (src_reg & 8) + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | REG_ECX | ((src_reg & 7) << 3)); + + return REG_ECX | (src_reg & 0x10); +} + +static int LOAD_HOST_REG(int host_reg) +{ + if (host_reg & 8) + addbyte(0x44); + addbyte(0x89); + addbyte(0xc0 | REG_ECX | ((host_reg & 7) << 3)); + + return REG_ECX | (host_reg & 0x10); +} + +static int ZERO_EXTEND_W_B(int reg) +{ + if (reg & 0x10) + { + addbyte(0x44); /*MOV EAX, reg*/ + addbyte(0x89); + addbyte(0xc0 | (reg << 3)); + addbyte(0x0f); /*MOVZX EAX, AH*/ + addbyte(0xb6); + addbyte(0xc4); + + return REG_EAX; + } + + if (reg & 8) + addbyte(0x41); + addbyte(0x0f); /*MOVZX regl, regb*/ + addbyte(0xb6); + addbyte(0xc0 | (reg & 7)); + + return REG_EAX; +} +static int ZERO_EXTEND_L_B(int reg) +{ + if (reg & 0x10) + { + addbyte(0x44); /*MOV EAX, reg*/ + addbyte(0x89); + addbyte(0xc0 | (reg << 3)); + addbyte(0x0f); /*MOVZX EAX, AH*/ + addbyte(0xb6); + addbyte(0xc4); + + return REG_EAX; + } + + if (reg & 8) + addbyte(0x41); + addbyte(0x0f); /*MOVZX regl, regb*/ + addbyte(0xb6); + addbyte(0xc0 | (reg & 7)); + + return REG_EAX; +} +static int ZERO_EXTEND_L_W(int reg) +{ + if (reg & 8) + addbyte(0x41); + addbyte(0x0f); /*MOVZX regl, regw*/ + addbyte(0xb7); + addbyte(0xc0 | (reg & 7)); + + return REG_EAX; +} + +static int SIGN_EXTEND_W_B(int reg) +{ + if (reg & 0x10) + { + addbyte(0x44); /*MOV EAX, reg*/ + addbyte(0x89); + addbyte(0xc0 | (reg << 3)); + addbyte(0x0f); /*MOVSX EAX, AH*/ + addbyte(0xbe); + addbyte(0xc4); + + return REG_EAX; + } + + if (reg & 8) + addbyte(0x41); + addbyte(0x0f); /*MOVSX regl, regb*/ + addbyte(0xbe); + addbyte(0xc0 | (reg & 7)); + + return REG_EAX; +} +static int SIGN_EXTEND_L_B(int reg) +{ + if (reg & 0x10) + { + addbyte(0x44); /*MOV EAX, reg*/ + addbyte(0x89); + addbyte(0xc0 | (reg << 3)); + addbyte(0x0f); /*MOVSX EAX, AH*/ + addbyte(0xbe); + addbyte(0xc4); + + return REG_EAX; + } + + if (reg & 8) + addbyte(0x41); + addbyte(0x0f); /*MOVSX regl, regb*/ + addbyte(0xbe); + addbyte(0xc0 | (reg & 7)); + + return REG_EAX; +} +static int SIGN_EXTEND_L_W(int reg) +{ + if (reg & 8) + addbyte(0x41); + addbyte(0x0f); /*MOVSX regl, regw*/ + addbyte(0xbf); + addbyte(0xc0 | (reg & 7)); + + return REG_EAX; +} + +static void SHL_B_IMM(int reg, int count) +{ + if (reg & 0x10) + { + addbyte(0x44); /*MOV EAX, reg*/ + addbyte(0x89); + addbyte(0xc0 | REG_EAX | ((reg & 7) << 3)); + addbyte(0xc0); /*SHL AH, count*/ + addbyte(0xe0 | REG_AH); + addbyte(count); + addbyte(0x41); /*MOV reg, EAX*/ + addbyte(0x89); + addbyte(0xc0 | (REG_EAX << 3) | (reg & 7)); + } + else + { + if (reg & 8) + addbyte(0x41); + addbyte(0xc0); /*SHL reg, count*/ + addbyte(0xc0 | (reg & 7) | 0x20); + addbyte(count); + } +} +static void SHL_W_IMM(int reg, int count) +{ + addbyte(0x66); /*SHL reg, count*/ + if (reg & 8) + addbyte(0x41); + addbyte(0xc1); + addbyte(0xc0 | (reg & 7) | 0x20); + addbyte(count); +} +static void SHL_L_IMM(int reg, int count) +{ + if (reg & 8) + addbyte(0x41); + addbyte(0xc1); /*SHL reg, count*/ + addbyte(0xc0 | (reg & 7) | 0x20); + addbyte(count); +} +static void SHR_B_IMM(int reg, int count) +{ + if (reg & 0x10) + { + addbyte(0x44); /*MOV EAX, reg*/ + addbyte(0x89); + addbyte(0xc0 | REG_EAX | ((reg & 7) << 3)); + addbyte(0xc0); /*SHR AH, count*/ + addbyte(0xe8 | REG_AH); + addbyte(count); + addbyte(0x41); /*MOV reg, EAX*/ + addbyte(0x89); + addbyte(0xc0 | (REG_EAX << 3) | (reg & 7)); + } + else + { + if (reg & 8) + addbyte(0x41); + addbyte(0xc0); /*SHR reg, count*/ + addbyte(0xc0 | (reg & 7) | 0x28); + addbyte(count); + } +} +static void SHR_W_IMM(int reg, int count) +{ + addbyte(0x66); /*SHR reg, count*/ + if (reg & 8) + addbyte(0x41); + addbyte(0xc1); + addbyte(0xc0 | (reg & 7) | 0x28); + addbyte(count); +} +static void SHR_L_IMM(int reg, int count) +{ + if (reg & 8) + addbyte(0x41); + addbyte(0xc1); /*SHR reg, count*/ + addbyte(0xc0 | (reg & 7) | 0x28); + addbyte(count); +} +static void SAR_B_IMM(int reg, int count) +{ + if (reg & 0x10) + { + addbyte(0x44); /*MOV EAX, reg*/ + addbyte(0x89); + addbyte(0xc0 | REG_EAX | ((reg & 7) << 3)); + addbyte(0xc0); /*SAR AH, count*/ + addbyte(0xf8 | REG_AH); + addbyte(count); + addbyte(0x41); /*MOV reg, EAX*/ + addbyte(0x89); + addbyte(0xc0 | (REG_EAX << 3) | (reg & 7)); + } + else + { + if (reg & 8) + addbyte(0x41); + addbyte(0xc0); /*SAR reg, count*/ + addbyte(0xc0 | (reg & 7) | 0x38); + addbyte(count); + } +} +static void SAR_W_IMM(int reg, int count) +{ + addbyte(0x66); /*SAR reg, count*/ + if (reg & 8) + addbyte(0x41); + addbyte(0xc1); + addbyte(0xc0 | (reg & 7) | 0x38); + addbyte(count); +} +static void SAR_L_IMM(int reg, int count) +{ + if (reg & 8) + addbyte(0x41); + addbyte(0xc1); /*SAR reg, count*/ + addbyte(0xc0 | (reg & 7) | 0x38); + addbyte(count); +} + +static void NEG_HOST_REG_B(int reg) +{ + if (reg & 0x10) + { + if (reg & 8) + addbyte(0x44); + addbyte(0x89); /*MOV BX, reg*/ + addbyte(0xc3 | ((reg & 7) << 3)); + addbyte(0xf6); /*NEG BH*/ + addbyte(0xdf); + if (reg & 8) + addbyte(0x41); + addbyte(0x89); /*MOV reg, BX*/ + addbyte(0xd8 | (reg & 7)); + } + else + { + if (reg & 8) + addbyte(0x41); + addbyte(0xf6); + addbyte(0xd8 | (reg & 7)); + } +} +static void NEG_HOST_REG_W(int reg) +{ + addbyte(0x66); + if (reg & 8) + addbyte(0x41); + addbyte(0xf7); + addbyte(0xd8 | (reg & 7)); +} +static void NEG_HOST_REG_L(int reg) +{ + if (reg & 8) + addbyte(0x41); + addbyte(0xf7); + addbyte(0xd8 | (reg & 7)); +} + + +static void FP_ENTER() +{ + if (codegen_fpu_entered) + return; + + addbyte(0xf6); /*TEST cr0, 0xc*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&cr0); + addbyte(0xc); + addbyte(0x74); /*JZ +*/ + addbyte(11+5+12+5); + addbyte(0xC7); /*MOVL [oldpc],op_old_pc*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&oldpc); + addlong(op_old_pc); + load_param_1_32(&codeblock[block_current], 7); + CALL_FUNC(x86_int); + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + + codegen_fpu_entered = 1; +} + +static void FP_FXCH(int reg) +{ + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x48); /*MOV RSI, ST*/ + addbyte(0xbe); + addquad((uint64_t)ST); + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + addbyte(0x83); /*ADD EAX, reg*/ + addbyte(0xc0); + addbyte(reg); + + addbyte(0x48); /*MOV RDX, [RSI + RBX*8]*/ + addbyte(0x8b); + addbyte(0x14); + addbyte(0xde); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(0x07); + addbyte(0x48); /*MOV RCX, [RSI + RAX*8]*/ + addbyte(0x8b); + addbyte(0x0c); + addbyte(0xc6); + addbyte(0x48); /*MOV [RSI + RAX*8], RDX*/ + addbyte(0x89); + addbyte(0x14); + addbyte(0xc6); + addbyte(0x48); /*MOV [RSI + RBX*8], RCX*/ + addbyte(0x89); + addbyte(0x0c); + addbyte(0xde); + + addbyte(0x48); /*MOVL ESI, tag*/ + addbyte(0xbe); + addquad((uintptr_t)tag); + addbyte(0x8a); /*MOV CL, tag[EAX]*/ + addbyte(0x14); + addbyte(0x1e); + addbyte(0x8a); /*MOV DL, tag[EBX]*/ + addbyte(0x0c); + addbyte(0x06); + addbyte(0x88); /*MOV tag[EBX], CL*/ + addbyte(0x14); + addbyte(0x06); + addbyte(0x88); /*MOV tag[EAX], DL*/ + addbyte(0x0c); + addbyte(0x1e); + + addbyte(0x48); /*MOV RSI, ST_i64*/ + addbyte(0xbe); + addquad((uint64_t)ST_i64); + addbyte(0x48); /*MOV RDX, [RSI + RBX*8]*/ + addbyte(0x8b); + addbyte(0x14); + addbyte(0xde); + addbyte(0x48); /*MOV RCX, [RSI + RAX*8]*/ + addbyte(0x8b); + addbyte(0x0c); + addbyte(0xc6); + addbyte(0x48); /*MOV [RSI + RAX*8], RDX*/ + addbyte(0x89); + addbyte(0x14); + addbyte(0xc6); + addbyte(0x48); /*MOV [RSI + RBX*8], RCX*/ + addbyte(0x89); + addbyte(0x0c); + addbyte(0xde); + reg = reg; +} + + + +static void FP_FLD(int reg) +{ + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + if (reg) + { + addbyte(0x83); /*ADD EAX, reg*/ + addbyte(0xc0); + addbyte(reg); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(0x01); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(0x07); + } + else + { + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(0x01); + } + + addbyte(0x48); /*MOV RCX, ST[EAX*8]*/ + addbyte(0x8b); + addbyte(0x0c); + addbyte(0xc5); + addlong((uintptr_t)ST); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(0x07); + addbyte(0x48); /*MOV RDX, ST_i64[EAX*8]*/ + addbyte(0x8b); + addbyte(0x14); + addbyte(0xc5); + addlong((uintptr_t)ST_i64); + addbyte(0x8a); /*MOV AL, [tag+EAX]*/ + addbyte(0x80); + addlong((uintptr_t)tag); + addbyte(0x48); /*MOV ST[EBX*8], RCX*/ + addbyte(0x89); + addbyte(0x0c); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x48); /*MOV ST_i64[EBX*8], RDX*/ + addbyte(0x89); + addbyte(0x14); + addbyte(0xdd); + addlong((uintptr_t)ST_i64); + addbyte(0x88); /*MOV [tag+EBX], AL*/ + addbyte(0x83); + addlong((uintptr_t)tag); + + addbyte(0x89); /*MOV [TOP], EBX*/ + addbyte(0x1c); + addbyte(0x25); + addlong((uintptr_t)&TOP); +} + +static void FP_FST(int reg) +{ + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x48); /*MOV RCX, ST[EAX*8]*/ + addbyte(0x8b); + addbyte(0x0c); + addbyte(0xc5); + addlong((uintptr_t)ST); + addbyte(0x8a); /*MOV BL, [tag+EAX]*/ + addbyte(0x98); + addlong((uintptr_t)tag); + + if (reg) + { + addbyte(0x83); /*ADD EAX, reg*/ + addbyte(0xc0); + addbyte(reg); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(0x07); + } + + addbyte(0x48); /*MOV ST[EAX*8], RCX*/ + addbyte(0x89); + addbyte(0x0c); + addbyte(0xc5); + addlong((uintptr_t)ST); + addbyte(0x88); /*MOV [tag+EAX], BL*/ + addbyte(0x98); + addlong((uintptr_t)tag); +} + +static void FP_POP() +{ + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0xc6); /*MOVB tag[EAX], 3*/ + addbyte(0x80); + addlong((uintptr_t)tag); + addbyte(3); + addbyte(0x83); /*ADD AL, 1*/ + addbyte(0xc0); + addbyte(1); + addbyte(0x83); /*AND AL, 7*/ + addbyte(0xe0); + addbyte(7); + addbyte(0x89); /*MOV [TOP], EAX*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&TOP); +} + +static void FP_LOAD_S() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1c); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x66); /*MOVD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(0x01); + addbyte(0xf3); /*CVTSS2SD XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x5a); + addbyte(0xc0); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + addbyte(0x85); /*TEST EAX, EAX*/ + addbyte(0xc0); + addbyte(0x89); /*MOV TOP, EBX*/ + addbyte(0x1c); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x66); /*MOVQ [ST+EBX*8], XMM0*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x0f); /*SETE [tag+EBX]*/ + addbyte(0x94); + addbyte(0x83); + addlong((uintptr_t)tag); +} +static void FP_LOAD_D() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1c); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(0x01); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + addbyte(0x48); /*TEST RAX, RAX*/ + addbyte(0x85); + addbyte(0xc0); + addbyte(0x89); /*MOV TOP, EBX*/ + addbyte(0x1c); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x48); /*MOVQ [ST+EBX*8], RAX*/ + addbyte(0x89); + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x0f); /*SETE [tag+EBX]*/ + addbyte(0x94); + addbyte(0x83); + addlong((uintptr_t)tag); +} + +static void FP_LOAD_IW() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1c); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x0f); /*MOVSX EAX, AX*/ + addbyte(0xbf); + addbyte(0xc0); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(0x01); + addbyte(0xf2); /*CVTSI2SD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x2a); + addbyte(0xc0); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + addbyte(0x85); /*TEST EAX, EAX*/ + addbyte(0xc0); + addbyte(0x89); /*MOV TOP, EBX*/ + addbyte(0x1c); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x66); /*MOVQ [ST+EBX*8], XMM0*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x0f); /*SETE [tag+EBX]*/ + addbyte(0x94); + addbyte(0x83); + addlong((uintptr_t)tag); +} +static void FP_LOAD_IL() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1c); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(0x01); + addbyte(0xf2); /*CVTSI2SD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x2a); + addbyte(0xc0); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + addbyte(0x85); /*TEST EAX, EAX*/ + addbyte(0xc0); + addbyte(0x89); /*MOV TOP, EBX*/ + addbyte(0x1c); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x66); /*MOVQ [ST+EBX*8], XMM0*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x0f); /*SETE [tag+EBX]*/ + addbyte(0x94); + addbyte(0x83); + addlong((uintptr_t)tag); +} +static void FP_LOAD_IQ() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1c); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(0x01); + addbyte(0xf2); /*CVTSI2SDQ XMM0, RAX*/ + addbyte(0x48); + addbyte(0x0f); + addbyte(0x2a); + addbyte(0xc0); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + addbyte(0x48); /*TEST RAX, RAX*/ + addbyte(0x85); + addbyte(0xc0); + addbyte(0x48); /*MOV [ST_i64+EBX*8], RAX*/ + addbyte(0x89); + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST_i64); + addbyte(0x89); /*MOV TOP, EBX*/ + addbyte(0x1c); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x0f); /*SETE AL*/ + addbyte(0x94); + addbyte(0xc0); + addbyte(0x66); /*MOVQ [ST+EBX*8], XMM0*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x0c); /*OR AL, TAG_UINT64*/ + addbyte(TAG_UINT64); + addbyte(0x88); /*MOV [tag+EBX], AL*/ + addbyte(0x83); + addlong((uintptr_t)tag); +} + +static int FP_LOAD_REG(int reg) +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1c); + addbyte(0x25); + addlong((uintptr_t)&TOP); + if (reg) + { + addbyte(0x83); /*ADD EBX, reg*/ + addbyte(0xc0 | REG_EBX); + addbyte(reg); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe0 | REG_EBX); + addbyte(0x07); + } + addbyte(0xf3); /*MOVQ XMM0, ST[EBX*8]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0xf2); /*CVTSD2SS XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x5a); + addbyte(0xc0); + addbyte(0x66); /*MOVD EBX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0 | REG_EBX); + + return REG_EBX; +} +static void FP_LOAD_REG_D(int reg, int *host_reg1, int *host_reg2) +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1c); + addbyte(0x25); + addlong((uintptr_t)&TOP); + if (reg) + { + addbyte(0x83); /*ADD EBX, reg*/ + addbyte(0xc0 | REG_EBX); + addbyte(reg); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe0 | REG_EBX); + addbyte(0x07); + } + addbyte(0x48); /*MOV RBX, ST[EBX*8]*/ + addbyte(0x8b); + addbyte(0x1c); + addbyte(0xdd); + addlong((uintptr_t)ST); + + *host_reg1 = REG_EBX; +} +static int64_t x87_fround(double b) +{ + int64_t a, c; + + switch ((npxc>>10)&3) + { + case 0: /*Nearest*/ + a = (int64_t)floor(b); + c = (int64_t)floor(b + 1.0); + if ((b - a) < (c - b)) + return a; + else if ((b - a) > (c - b)) + return c; + else + return (a & 1) ? c : a; + case 1: /*Down*/ + return (int64_t)floor(b); + case 2: /*Up*/ + return (int64_t)ceil(b); + case 3: /*Chop*/ + return (int64_t)b; + } +} +static int FP_LOAD_REG_INT_W(int reg) +{ + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&TOP); + if (reg) + { + addbyte(0x83); /*ADD EAX, reg*/ + addbyte(0xc0); + addbyte(reg); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(7); + } + addbyte(0xf3); /*MOVQ XMM0, ST[EAX*8]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x04); + addbyte(0xc5); + addlong((uintptr_t)ST); + + CALL_FUNC(x87_fround); + + addbyte(0x93); /*XCHG EBX, EAX*/ + + return REG_EBX; +} +static int FP_LOAD_REG_INT(int reg) +{ + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&TOP); + if (reg) + { + addbyte(0x83); /*ADD EAX, reg*/ + addbyte(0xc0); + addbyte(reg); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(7); + } + addbyte(0xf3); /*MOVQ XMM0, ST[EAX*8]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x04); + addbyte(0xc5); + addlong((uintptr_t)ST); + + CALL_FUNC(x87_fround); + + addbyte(0x93); /*XCHG EBX, EAX*/ + + return REG_EBX; +} +static void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2) +{ + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&TOP); + if (reg) + { + addbyte(0x83); /*ADD EAX, reg*/ + addbyte(0xc0); + addbyte(reg); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(7); + } + + if (codegen_fpu_loaded_iq[TOP] && (tag[TOP] & TAG_UINT64)) + { + /*If we know the register was loaded with FILDq in this block and + has not been modified, then we can skip most of the conversion + and just load the 64-bit integer representation directly */ + addbyte(0x48); /*MOV RAX, [ST_i64+EAX*8]*/ + addbyte(0x8b); + addbyte(0x04); + addbyte(0xc5); + addlong((uint32_t)ST_i64); + + addbyte(0x48); /*XCHG RBX, RAX*/ + addbyte(0x93); + + *host_reg1 = REG_EBX; + + return; + } + + addbyte(0xf6); /*TEST TAG[EBX], TAG_UINT64*/ + addbyte(0x80); + addlong((uintptr_t)tag); + addbyte(TAG_UINT64); + + addbyte(0x74); /*JZ +*/ + addbyte(8+2); + + addbyte(0x48); /*MOV RAX, [ST_i64+EAX*8]*/ + addbyte(0x8b); + addbyte(0x04); + addbyte(0xc5); + addlong((uint32_t)ST_i64); + + addbyte(0xeb); /*JMP done*/ + addbyte(9+12); + + addbyte(0xf3); /*MOVQ XMM0, ST[EAX*8]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x04); + addbyte(0xc5); + addlong((uintptr_t)ST); + + CALL_FUNC(x87_fround); + + addbyte(0x48); /*XCHG RBX, RAX*/ + addbyte(0x93); + + *host_reg1 = REG_EBX; +} + +#define FPU_ADD 0 +#define FPU_DIV 4 +#define FPU_DIVR 5 +#define FPU_MUL 1 +#define FPU_SUB 2 +#define FPU_SUBR 3 + +static void FP_OP_REG(int op, int dst, int src) +{ + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x48); /*MOV RSI, ST*/ + addbyte(0xbe); + addquad((uint64_t)ST); + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + if (dst) + { + addbyte(0x83); /*ADD EAX, reg*/ + addbyte(0xc0); + addbyte(dst); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(0x07); + } + if (src) + { + addbyte(0x83); /*ADD EBX, reg*/ + addbyte(0xc0 | REG_EBX); + addbyte(src); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe0 | REG_EBX); + addbyte(0x07); + } + if (op == FPU_DIVR || op == FPU_SUBR) + { + addbyte(0xf3); /*MOVQ XMM0, [RSI+RBX*8]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x04); + addbyte(0xde); + } + else + { + addbyte(0xf3); /*MOVQ XMM0, [RSI+RAX*8]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x04); + addbyte(0xc6); + } + switch (op) + { + case FPU_ADD: + addbyte(0xf2); /*ADDSD XMM0, [RSI+RBX*8]*/ + addbyte(0x0f); + addbyte(0x58); + addbyte(0x04); + addbyte(0xde); + break; + case FPU_DIV: + addbyte(0xf2); /*DIVSD XMM0, [RSI+RBX*8]*/ + addbyte(0x0f); + addbyte(0x5e); + addbyte(0x04); + addbyte(0xde); + break; + case FPU_DIVR: + addbyte(0xf2); /*DIVSD XMM0, [RSI+RAX*8]*/ + addbyte(0x0f); + addbyte(0x5e); + addbyte(0x04); + addbyte(0xc6); + break; + case FPU_MUL: + addbyte(0xf2); /*MULSD XMM0, [RSI+RBX*8]*/ + addbyte(0x0f); + addbyte(0x59); + addbyte(0x04); + addbyte(0xde); + break; + case FPU_SUB: + addbyte(0xf2); /*SUBSD XMM0, [RSI+RBX*8]*/ + addbyte(0x0f); + addbyte(0x5c); + addbyte(0x04); + addbyte(0xde); + break; + case FPU_SUBR: + addbyte(0xf2); /*SUBSD XMM0, [RSI+RAX*8]*/ + addbyte(0x0f); + addbyte(0x5c); + addbyte(0x04); + addbyte(0xc6); + break; + } + addbyte(0x66); /*MOVQ [RSI+RAX*8], XMM0*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x04); + addbyte(0xc6); +} + +static void FP_OP_MEM(int op) +{ + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x48); /*MOV RSI, ST*/ + addbyte(0xbe); + addquad((uint64_t)ST); + addbyte(0xf3); /*MOVQ XMM0, [RSI+RAX*8]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x04); + addbyte(0xc6); + addbyte(0x80); /*AND tag[EAX], ~TAG_UINT64*/ + addbyte(0xa0 | REG_EAX); + addlong((uintptr_t)tag); + addbyte(~TAG_UINT64); + + switch (op) + { + case FPU_ADD: + addbyte(0xf2); /*ADDSD XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0x58); + addbyte(0xc1); + break; + case FPU_DIV: + addbyte(0xf2); /*DIVSD XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0x5e); + addbyte(0xc1); + break; + case FPU_DIVR: + addbyte(0xf2); /*DIVSD XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0x5e); + addbyte(0xc8); + break; + case FPU_MUL: + addbyte(0xf2); /*MULSD XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0x59); + addbyte(0xc1); + break; + case FPU_SUB: + addbyte(0xf2); /*SUBSD XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0x5c); + addbyte(0xc1); + break; + case FPU_SUBR: + addbyte(0xf2); /*SUBSD XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0x5c); + addbyte(0xc8); + break; + } + if (op == FPU_DIVR || op == FPU_SUBR) + { + addbyte(0x66); /*MOVQ [RSI+RAX*8], XMM1*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x0c); + addbyte(0xc6); + } + else + { + addbyte(0x66); /*MOVQ [RSI+RAX*8], XMM0*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x04); + addbyte(0xc6); + } +} + +static void FP_OP_S(int op) +{ + addbyte(0x66); /*MOVD XMM1, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc8); + addbyte(0xf3); /*CVTSS2SD XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x5a); + addbyte(0xc9); + FP_OP_MEM(op); +} +static void FP_OP_D(int op) +{ + addbyte(0x66); /*MOVQ XMM1, RAX*/ + addbyte(0x48); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc8); + if (((npxc >> 10) & 3) && op == FPU_ADD) + { + addbyte(0x0f); /*STMXCSR [ESP+8]*/ + addbyte(0xae); + addbyte(0x5c); + addbyte(0x24); + addbyte(0x08); + addbyte(0x8b); /*MOV EAX, [ESP+8]*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x08); + addbyte(0x25); /*AND EAX, ~(3 << 13)*/ + addlong(~(3 << 10)); + addbyte(0x0d); /*OR EAX, (npxc & (3 << 10)) << 3*/ + addlong((npxc & (3 << 10)) << 3); + addbyte(0x89); /*MOV [RSP+12], EAX*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x0c); + addbyte(0x0f); /*LDMXCSR [RSP+12]*/ + addbyte(0xae); + addbyte(0x54); + addbyte(0x24); + addbyte(0x0c); + } + FP_OP_MEM(op); + if (((npxc >> 10) & 3) && op == FPU_ADD) + { + addbyte(0x0f); /*LDMXCSR [RSP+8]*/ + addbyte(0xae); + addbyte(0x54); + addbyte(0x24); + addbyte(0x08); + } +} +static void FP_OP_IW(int op) +{ + addbyte(0x0f); /*MOVSX EAX, AX*/ + addbyte(0xbf); + addbyte(0xc0); + addbyte(0xf2); /*CVTSI2SD XMM1, EAX*/ + addbyte(0x0f); + addbyte(0x2a); + addbyte(0xc8); + FP_OP_MEM(op); +} +static void FP_OP_IL(int op) +{ + addbyte(0xf2); /*CVTSI2SD XMM1, EAX*/ + addbyte(0x0f); + addbyte(0x2a); + addbyte(0xc8); + FP_OP_MEM(op); +} + +#define C0 (1<<8) +#define C1 (1<<9) +#define C2 (1<<10) +#define C3 (1<<14) + +static void FP_COMPARE_REG(int dst, int src) +{ + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x48); /*MOV RSI, ST*/ + addbyte(0xbe); + addquad((uint64_t)ST); + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + if (src || dst) + { + addbyte(0x83); /*ADD EAX, 1*/ + addbyte(0xc0); + addbyte(src ? src : dst); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(7); + } + + addbyte(0x8a); /*MOV CL, [npxs+1]*/ + addbyte(0x0c); + addbyte(0x25); + addlong(((uintptr_t)&npxs) + 1); +// addbyte(0xdb); /*FCLEX*/ +// addbyte(0xe2); + addbyte(0x80); /*AND CL, ~(C0|C2|C3)*/ + addbyte(0xe1); + addbyte((~(C0|C2|C3)) >> 8); + + if (src) + { + addbyte(0xf3); /*MOVQ XMM0, [RSI+RBX*8]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x04); + addbyte(0xde); + addbyte(0x66); /*COMISD XMM0, [RSI+RAX*8]*/ + addbyte(0x0f); + addbyte(0x2f); + addbyte(0x04); + addbyte(0xc6); + } + else + { + addbyte(0xf3); /*MOVQ XMM0, [RSI+RAX*8]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x04); + addbyte(0xc6); + addbyte(0x66); /*COMISD XMM0, [RSI+RBX*8]*/ + addbyte(0x0f); + addbyte(0x2f); + addbyte(0x04); + addbyte(0xde); + } + + addbyte(0x9f); /*LAHF*/ + addbyte(0x80); /*AND AH, (C0|C2|C3)*/ + addbyte(0xe4); + addbyte((C0|C2|C3) >> 8); + addbyte(0x08); /*OR CL, AH*/ + addbyte(0xe1); + addbyte(0x88); /*MOV [npxs+1], CL*/ + addbyte(0x0c); + addbyte(0x25); + addlong(((uintptr_t)&npxs) + 1); +} + +static void FP_COMPARE_MEM() +{ + addbyte(0x8b); /*MOV EAX, [TOP]*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&TOP); + addbyte(0x48); /*MOV RSI, ST*/ + addbyte(0xbe); + addquad((uint64_t)ST); + + addbyte(0x8a); /*MOV CL, [npxs+1]*/ + addbyte(0x0c); + addbyte(0x25); + addlong(((uintptr_t)&npxs) + 1); +// addbyte(0xdb); /*FCLEX*/ +// addbyte(0xe2); + addbyte(0xf3); /*MOVQ XMM0, [RSI+RAX*8]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x04); + addbyte(0xc6); + addbyte(0x80); /*AND CL, ~(C0|C2|C3)*/ + addbyte(0xe1); + addbyte((~(C0|C2|C3)) >> 8); + addbyte(0x66); /*COMISD XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0x2f); + addbyte(0xc1); + addbyte(0x9f); /*LAHF*/ + addbyte(0x80); /*AND AH, (C0|C2|C3)*/ + addbyte(0xe4); + addbyte((C0|C2|C3) >> 8); + addbyte(0x08); /*OR CL, AH*/ + addbyte(0xe1); + addbyte(0x88); /*MOV [npxs+1], CL*/ + addbyte(0x0c); + addbyte(0x25); + addlong(((uintptr_t)&npxs) + 1); +} +static void FP_COMPARE_S() +{ + addbyte(0x66); /*MOVD XMM1, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc8); + addbyte(0xf3); /*CVTSS2SD XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x5a); + addbyte(0xc9); + FP_COMPARE_MEM(); +} +static void FP_COMPARE_D() +{ + addbyte(0x66); /*MOVQ XMM1, RAX*/ + addbyte(0x48); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc8); + FP_COMPARE_MEM(); +} +static void FP_COMPARE_IW() +{ + addbyte(0x0f); /*MOVSX EAX, AX*/ + addbyte(0xbf); + addbyte(0xc0); + addbyte(0xf2); /*CVTSI2SD XMM1, EAX*/ + addbyte(0x0f); + addbyte(0x2a); + addbyte(0xc8); + FP_COMPARE_MEM(); +} +static void FP_COMPARE_IL() +{ + addbyte(0xf2); /*CVTSI2SD XMM1, EAX*/ + addbyte(0x0f); + addbyte(0x2a); + addbyte(0xc8); + FP_COMPARE_MEM(); +} + +static void SET_BITS(uintptr_t addr, uint32_t val) +{ + if (val & ~0xff) + { + addbyte(0x81); + addbyte(0x0c); + addbyte(0x25); + addlong(addr); + addlong(val); + } + else + { + addbyte(0x80); + addbyte(0x0c); + addbyte(0x25); + addlong(addr); + addbyte(val); + } +} +static void CLEAR_BITS(uintptr_t addr, uint32_t val) +{ + if (val & ~0xff) + { + addbyte(0x81); + addbyte(0x24); + addbyte(0x25); + addlong(addr); + addlong(~val); + } + else + { + addbyte(0x80); + addbyte(0x24); + addbyte(0x25); + addlong(addr); + addbyte(~val); + } +} + +#define LOAD_Q_REG_1 REG_EAX +#define LOAD_Q_REG_2 REG_EDX + +static void MMX_ENTER() +{ + if (codegen_mmx_entered) + return; + + addbyte(0xf6); /*TEST cr0, 0xc*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&cr0); + addbyte(0xc); + addbyte(0x74); /*JZ +*/ + addbyte(11+5+12+5); + addbyte(0xC7); /*MOVL [oldpc],op_old_pc*/ + addbyte(0x04); + addbyte(0x25); + addlong((uintptr_t)&oldpc); + addlong(op_old_pc); + load_param_1_32(&codeblock[block_current], 7); + CALL_FUNC(x86_int); + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + + + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + addbyte(0xc7); /*MOV ISMMX, 1*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&ismmx); + addlong(1); + addbyte(0x89); /*MOV TOP, EAX*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&TOP); + addbyte(0x89); /*MOV tag, EAX*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&tag[0]); + addbyte(0x89); /*MOV tag+4, EAX*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&tag[4]); + + codegen_mmx_entered = 1; +} + +extern int mmx_ebx_ecx_loaded; + +static int LOAD_MMX_D(int guest_reg) +{ + int host_reg = REG_EBX; + + addbyte(0x8b); /*MOV EBX, reg*/ + addbyte(0x04 | (host_reg << 3)); + addbyte(0x25); + addlong((uint32_t)&MM[guest_reg].l[0]); + + return host_reg; +} +static void LOAD_MMX_Q(int guest_reg, int *host_reg1, int *host_reg2) +{ + int host_reg = REG_EBX; + + if (host_reg & 8) + addbyte(0x4c); + else + addbyte(0x48); + addbyte(0x8b); /*MOV RBX, reg*/ + addbyte(0x04 | ((host_reg & 7) << 3)); + addbyte(0x25); + addlong((uint32_t)&MM[guest_reg].q); + + *host_reg1 = host_reg; +} +static int LOAD_MMX_Q_MMX(int guest_reg) +{ + int dst_reg = find_host_xmm_reg(); + host_reg_xmm_mapping[dst_reg] = 100; + + addbyte(0xf3); /*MOV XMMx, reg*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x04 | ((dst_reg & 7) << 3)); + addbyte(0x25); + addlong((uint32_t)&MM[guest_reg].q); + + return dst_reg; +} + +static int LOAD_INT_TO_MMX(int src_reg1, int src_reg2) +{ + int dst_reg = find_host_xmm_reg(); + host_reg_xmm_mapping[dst_reg] = 100; + + addbyte(0x66); /*MOVQ host_reg, src_reg1*/ + if (src_reg1 & 8) + addbyte(0x49); + else + addbyte(0x48); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0 | (dst_reg << 3) | (src_reg1 & 7)); + + return dst_reg; +} + +static void STORE_MMX_LQ(int guest_reg, int host_reg1) +{ + addbyte(0xC7); /*MOVL [reg],0*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&MM[guest_reg].l[1]); + addlong(0); + if (host_reg1 & 8) + addbyte(0x44); + addbyte(0x89); /*MOVL [reg],host_reg*/ + addbyte(0x04 | ((host_reg1 & 7) << 3)); + addbyte(0x25); + addlong((uint32_t)&MM[guest_reg].l[0]); +} +static void STORE_MMX_Q(int guest_reg, int host_reg1, int host_reg2) +{ + if (host_reg1 & 8) + addbyte(0x4c); + else + addbyte(0x48); + addbyte(0x89); /*MOV [reg],host_reg*/ + addbyte(0x04 | ((host_reg1 & 7) << 3)); + addbyte(0x25); + addlong((uint32_t)&MM[guest_reg].l[0]); +} +static void STORE_MMX_Q_MMX(int guest_reg, int host_reg) +{ + addbyte(0x66); /*MOVQ [guest_reg],host_reg*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x04 | (host_reg << 3)); + addbyte(0x25); + addlong((uint32_t)&MM[guest_reg].q); +} + +#define MMX_x86_OP(name, opcode) \ +static void MMX_ ## name(int dst_reg, int src_reg) \ +{ \ + addbyte(0x66); /*op dst_reg, src_reg*/ \ + addbyte(0x0f); \ + addbyte(opcode); \ + addbyte(0xc0 | (dst_reg << 3) | src_reg); \ +} + +MMX_x86_OP(AND, 0xdb) +MMX_x86_OP(ANDN, 0xdf) +MMX_x86_OP(OR, 0xeb) +MMX_x86_OP(XOR, 0xef) + +MMX_x86_OP(ADDB, 0xfc) +MMX_x86_OP(ADDW, 0xfd) +MMX_x86_OP(ADDD, 0xfe) +MMX_x86_OP(ADDSB, 0xec) +MMX_x86_OP(ADDSW, 0xed) +MMX_x86_OP(ADDUSB, 0xdc) +MMX_x86_OP(ADDUSW, 0xdd) + +MMX_x86_OP(SUBB, 0xf8) +MMX_x86_OP(SUBW, 0xf9) +MMX_x86_OP(SUBD, 0xfa) +MMX_x86_OP(SUBSB, 0xe8) +MMX_x86_OP(SUBSW, 0xe9) +MMX_x86_OP(SUBUSB, 0xd8) +MMX_x86_OP(SUBUSW, 0xd9) + +MMX_x86_OP(PUNPCKLBW, 0x60); +MMX_x86_OP(PUNPCKLWD, 0x61); +MMX_x86_OP(PUNPCKLDQ, 0x62); +MMX_x86_OP(PCMPGTB, 0x64); +MMX_x86_OP(PCMPGTW, 0x65); +MMX_x86_OP(PCMPGTD, 0x66); + +MMX_x86_OP(PCMPEQB, 0x74); +MMX_x86_OP(PCMPEQW, 0x75); +MMX_x86_OP(PCMPEQD, 0x76); + +MMX_x86_OP(PSRLW, 0xd1); +MMX_x86_OP(PSRLD, 0xd2); +MMX_x86_OP(PSRLQ, 0xd3); +MMX_x86_OP(PSRAW, 0xe1); +MMX_x86_OP(PSRAD, 0xe2); +MMX_x86_OP(PSLLW, 0xf1); +MMX_x86_OP(PSLLD, 0xf2); +MMX_x86_OP(PSLLQ, 0xf3); + +MMX_x86_OP(PMULLW, 0xd5); +MMX_x86_OP(PMULHW, 0xe5); +MMX_x86_OP(PMADDWD, 0xf5); + +static void MMX_PACKSSWB(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PACKSSWB dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x63); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x08); +} +static void MMX_PACKUSWB(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PACKUSWB dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x08); +} +static void MMX_PACKSSDW(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PACKSSDW dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x08); +} +static void MMX_PUNPCKHBW(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PUNPCKLBW dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x0e); +} +static void MMX_PUNPCKHWD(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PUNPCKLWD dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x61); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x0e); +} +static void MMX_PUNPCKHDQ(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PUNPCKLDQ dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x62); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x0e); +} + +static void MMX_PSRLW_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRLW dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xc0 | dst_reg | 0x10); + addbyte(amount); +} +static void MMX_PSRAW_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRAW dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xc0 | dst_reg | 0x20); + addbyte(amount); +} +static void MMX_PSLLW_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSLLW dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xc0 | dst_reg | 0x30); + addbyte(amount); +} + +static void MMX_PSRLD_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRLD dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xc0 | dst_reg | 0x10); + addbyte(amount); +} +static void MMX_PSRAD_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRAD dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xc0 | dst_reg | 0x20); + addbyte(amount); +} +static void MMX_PSLLD_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSLLD dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xc0 | dst_reg | 0x30); + addbyte(amount); +} + +static void MMX_PSRLQ_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRLQ dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x73); + addbyte(0xc0 | dst_reg | 0x10); + addbyte(amount); +} +static void MMX_PSRAQ_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRAQ dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x73); + addbyte(0xc0 | dst_reg | 0x20); + addbyte(amount); +} +static void MMX_PSLLQ_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSLLQ dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x73); + addbyte(0xc0 | dst_reg | 0x30); + addbyte(amount); +} diff --git a/src/codegen_ops_x86.h b/src/codegen_ops_x86.h new file mode 100644 index 000000000..3e077f24a --- /dev/null +++ b/src/codegen_ops_x86.h @@ -0,0 +1,3393 @@ +/*Register allocation : + EBX, ECX, EDX - emulated registers + EAX - work register, EA storage + ESI, EDI - work registers + EBP - points at emulated register array +*/ +#define HOST_REG_START 1 +#define HOST_REG_END 4 +#define HOST_REG_XMM_START 0 +#define HOST_REG_XMM_END 7 +static inline int find_host_reg() +{ + int c; + for (c = HOST_REG_START; c < HOST_REG_END; c++) + { + if (host_reg_mapping[c] == -1) + break; + } + + if (c == NR_HOST_REGS) + fatal("Out of host regs!\n"); + return c; +} +static inline int find_host_xmm_reg() +{ + int c; + for (c = HOST_REG_XMM_START; c < HOST_REG_XMM_END; c++) + { + if (host_reg_xmm_mapping[c] == -1) + break; + } + + if (c == HOST_REG_XMM_END) + fatal("Out of host XMM regs!\n"); + return c; +} + +static void STORE_IMM_ADDR_B(uintptr_t addr, uint8_t val) +{ + addbyte(0xC6); /*MOVB [addr],val*/ + addbyte(0x05); + addlong(addr); + addbyte(val); +} +static void STORE_IMM_ADDR_W(uintptr_t addr, uint16_t val) +{ + addbyte(0x66); /*MOVW [addr],val*/ + addbyte(0xC7); + addbyte(0x05); + addlong(addr); + addword(val); +} +static void STORE_IMM_ADDR_L(uintptr_t addr, uint32_t val) +{ + if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x80) + { + addbyte(0xC7); /*MOVL [addr],val*/ + addbyte(0x45); + addbyte(addr - (uint32_t)&cpu_state); + addlong(val); + } + else + { + addbyte(0xC7); /*MOVL [addr],val*/ + addbyte(0x05); + addlong(addr); + addlong(val); + } +} + +static void STORE_IMM_REG_B(int reg, uint8_t val) +{ + addbyte(0xC6); /*MOVB [addr],val*/ + addbyte(0x45); + if (reg & 4) + addbyte((uint32_t)&cpu_state.regs[reg & 3].b.h - (uint32_t)&EAX); + else + addbyte((uint32_t)&cpu_state.regs[reg & 3].b.l - (uint32_t)&EAX); + addbyte(val); +} +static void STORE_IMM_REG_W(int reg, uint16_t val) +{ + addbyte(0x66); /*MOVW [addr],val*/ + addbyte(0xC7); + addbyte(0x45); + addbyte((uint32_t)&cpu_state.regs[reg & 7].w - (uint32_t)&EAX); + addword(val); +} +static void STORE_IMM_REG_L(int reg, uint32_t val) +{ + addbyte(0xC7); /*MOVL [addr],val*/ + addbyte(0x45); + addbyte((uint32_t)&cpu_state.regs[reg & 7].l - (uint32_t)&EAX); + addlong(val); +} + +static int LOAD_REG_B(int reg) +{ + int host_reg = find_host_reg(); + host_reg_mapping[host_reg] = reg; + + addbyte(0x0f); /*MOVZX B[reg],host_reg*/ + addbyte(0xb6); + addbyte(0x45 | (host_reg << 3)); + if (reg & 4) + addbyte((uint32_t)&cpu_state.regs[reg & 3].b.h - (uint32_t)&EAX); + else + addbyte((uint32_t)&cpu_state.regs[reg & 3].b.l - (uint32_t)&EAX); + + return host_reg; +} +static int LOAD_REG_W(int reg) +{ + int host_reg = find_host_reg(); + host_reg_mapping[host_reg] = reg; + + addbyte(0x0f); /*MOVZX W[reg],host_reg*/ + addbyte(0xb7); + addbyte(0x45 | (host_reg << 3)); + addbyte((uint32_t)&cpu_state.regs[reg & 7].w - (uint32_t)&EAX); + + return host_reg; +} +static int LOAD_REG_L(int reg) +{ + int host_reg = find_host_reg(); + host_reg_mapping[host_reg] = reg; + + addbyte(0x8b); /*MOVL host_reg,[reg]*/ + addbyte(0x45 | (host_reg << 3)); + addbyte((uint32_t)&cpu_state.regs[reg & 7].l - (uint32_t)&EAX); + + return host_reg; +} + +static int LOAD_VAR_W(uintptr_t addr) +{ + int host_reg = find_host_reg(); + host_reg_mapping[host_reg] = reg; + + addbyte(0x66); /*MOVL host_reg,[reg]*/ + addbyte(0x8b); + addbyte(0x05 | (host_reg << 3)); + addlong((uint32_t)addr); + + return host_reg; +} +static int LOAD_VAR_L(uintptr_t addr) +{ + int host_reg = find_host_reg(); + host_reg_mapping[host_reg] = reg; + + addbyte(0x8b); /*MOVL host_reg,[reg]*/ + addbyte(0x05 | (host_reg << 3)); + addlong((uint32_t)addr); + + return host_reg; +} + +static int LOAD_REG_IMM(uint32_t imm) +{ + int host_reg = find_host_reg(); + host_reg_mapping[host_reg] = reg; + + addbyte(0xc7); /*MOVL host_reg, imm*/ + addbyte(0xc0 | host_reg); + addlong(imm); + + return host_reg; +} + +static int LOAD_HOST_REG(int host_reg) +{ + int new_host_reg = find_host_reg(); + host_reg_mapping[new_host_reg] = reg; + + addbyte(0x89); /*MOV new_host_reg, host_reg*/ + addbyte(0xc0 | (host_reg << 3) | new_host_reg); + + return new_host_reg; +} + +static void STORE_REG_B_RELEASE(int host_reg) +{ + addbyte(0x88); /*MOVB [reg],host_reg*/ + addbyte(0x45 | (host_reg << 3)); + if (host_reg_mapping[host_reg] & 4) + addbyte((uint32_t)&cpu_state.regs[host_reg_mapping[host_reg] & 3].b.h - (uint32_t)&EAX); + else + addbyte((uint32_t)&cpu_state.regs[host_reg_mapping[host_reg] & 3].b.l - (uint32_t)&EAX); + host_reg_mapping[host_reg] = -1; +} +static void STORE_REG_W_RELEASE(int host_reg) +{ + addbyte(0x66); /*MOVW [reg],host_reg*/ + addbyte(0x89); + addbyte(0x45 | (host_reg << 3)); + addbyte((uint32_t)&cpu_state.regs[host_reg_mapping[host_reg]].w - (uint32_t)&EAX); + host_reg_mapping[host_reg] = -1; +} +static void STORE_REG_L_RELEASE(int host_reg) +{ + addbyte(0x89); /*MOVL [reg],host_reg*/ + addbyte(0x45 | (host_reg << 3)); + addbyte((uint32_t)&cpu_state.regs[host_reg_mapping[host_reg]].l - (uint32_t)&EAX); + host_reg_mapping[host_reg] = -1; +} + +static void STORE_REG_TARGET_B_RELEASE(int host_reg, int guest_reg) +{ + addbyte(0x88); /*MOVB [guest_reg],host_reg*/ + addbyte(0x45 | (host_reg << 3)); + if (guest_reg & 4) + addbyte((uint32_t)&cpu_state.regs[guest_reg & 3].b.h - (uint32_t)&EAX); + else + addbyte((uint32_t)&cpu_state.regs[guest_reg & 3].b.l - (uint32_t)&EAX); + host_reg_mapping[host_reg] = -1; +} +static void STORE_REG_TARGET_W_RELEASE(int host_reg, int guest_reg) +{ + addbyte(0x66); /*MOVW [guest_reg],host_reg*/ + addbyte(0x89); + addbyte(0x45 | (host_reg << 3)); + addbyte((uint32_t)&cpu_state.regs[guest_reg & 7].w - (uint32_t)&EAX); + host_reg_mapping[host_reg] = -1; +} +static void STORE_REG_TARGET_L_RELEASE(int host_reg, int guest_reg) +{ + addbyte(0x89); /*MOVL [guest_reg],host_reg*/ + addbyte(0x45 | (host_reg << 3)); + addbyte((uint32_t)&cpu_state.regs[guest_reg & 7].l - (uint32_t)&EAX); + host_reg_mapping[host_reg] = -1; +} + +static void RELEASE_REG(int host_reg) +{ + host_reg_mapping[host_reg] = -1; +} + +static void STORE_HOST_REG_ADDR_W(uintptr_t addr, int host_reg) +{ + if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x80) + { + addbyte(0x66); /*MOVW [addr],host_reg*/ + addbyte(0x89); + addbyte(0x45 | (host_reg << 3)); + addbyte((uint32_t)addr - (uint32_t)&cpu_state); + } + else + { + addbyte(0x66); /*MOVL [reg],host_reg*/ + addbyte(0x89); + addbyte(0x05 | (host_reg << 3)); + addlong(addr); + } +} +static void STORE_HOST_REG_ADDR(uintptr_t addr, int host_reg) +{ + if (addr >= (uintptr_t)&cpu_state && addr < ((uintptr_t)&cpu_state)+0x80) + { + addbyte(0x89); /*MOVL [addr],host_reg*/ + addbyte(0x45 | (host_reg << 3)); + addbyte((uint32_t)addr - (uint32_t)&cpu_state); + } + else + { + addbyte(0x89); /*MOVL [reg],host_reg*/ + addbyte(0x05 | (host_reg << 3)); + addlong(addr); + } +} +#define STORE_HOST_REG_ADDR_BL STORE_HOST_REG_ADDR +#define STORE_HOST_REG_ADDR_WL STORE_HOST_REG_ADDR + +static void ADD_HOST_REG_B(int dst_reg, int src_reg) +{ + addbyte(0x00); /*ADDB dst_reg, src_reg*/ + addbyte(0xc0 | dst_reg | (src_reg << 3)); +} +static void ADD_HOST_REG_W(int dst_reg, int src_reg) +{ + addbyte(0x66); /*ADDW dst_reg, src_reg*/ + addbyte(0x01); + addbyte(0xc0 | dst_reg | (src_reg << 3)); +} +static void ADD_HOST_REG_L(int dst_reg, int src_reg) +{ + addbyte(0x01); /*ADDL dst_reg, src_reg*/ + addbyte(0xc0 | dst_reg | (src_reg << 3)); +} +static void ADD_HOST_REG_IMM_B(int host_reg, uint8_t imm) +{ + addbyte(0x80); /*ADDB host_reg, imm*/ + addbyte(0xC0 | host_reg); + addbyte(imm); +} +static void ADD_HOST_REG_IMM_W(int host_reg, uint16_t imm) +{ + if (imm < 0x80 || imm >= 0xff80) + { + addbyte(0x66); /*ADDW host_reg, imm*/ + addbyte(0x83); + addbyte(0xC0 | host_reg); + addbyte(imm & 0xff); + } + else + { + addbyte(0x66); /*ADDW host_reg, imm*/ + addbyte(0x81); + addbyte(0xC0 | host_reg); + addword(imm); + } +} +static void ADD_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + if (imm < 0x80 || imm >= 0xffffff80) + { + addbyte(0x83); /*ADDL host_reg, imm*/ + addbyte(0xC0 | host_reg); + addbyte(imm & 0xff); + } + else + { + addbyte(0x81); /*ADDL host_reg, imm*/ + addbyte(0xC0 | host_reg); + addlong(imm); + } +} + +#define AND_HOST_REG_B AND_HOST_REG_L +#define AND_HOST_REG_W AND_HOST_REG_L +static void AND_HOST_REG_L(int dst_reg, int src_reg) +{ + addbyte(0x21); /*ANDL dst_reg, src_reg*/ + addbyte(0xc0 | dst_reg | (src_reg << 3)); +} +static void AND_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + if (imm < 0x80 || imm >= 0xffffff80) + { + addbyte(0x83); /*ANDL host_reg, imm*/ + addbyte(0xE0 | host_reg); + addbyte(imm & 0xff); + } + else + { + addbyte(0x81); /*ANDL host_reg, imm*/ + addbyte(0xE0 | host_reg); + addlong(imm); + } +} +static int TEST_HOST_REG_B(int dst_reg, int src_reg) +{ + AND_HOST_REG_B(dst_reg, src_reg); + + return dst_reg; +} +static int TEST_HOST_REG_W(int dst_reg, int src_reg) +{ + AND_HOST_REG_W(dst_reg, src_reg); + + return dst_reg; +} +static int TEST_HOST_REG_L(int dst_reg, int src_reg) +{ + AND_HOST_REG_L(dst_reg, src_reg); + + return dst_reg; +} +static int TEST_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + AND_HOST_REG_IMM(host_reg, imm); + + return host_reg; +} + +#define OR_HOST_REG_B OR_HOST_REG_L +#define OR_HOST_REG_W OR_HOST_REG_L +static void OR_HOST_REG_L(int dst_reg, int src_reg) +{ + addbyte(0x09); /*ORL dst_reg, src_reg*/ + addbyte(0xc0 | dst_reg | (src_reg << 3)); +} +static void OR_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + if (imm < 0x80 || imm >= 0xffffff80) + { + addbyte(0x83); /*ORL host_reg, imm*/ + addbyte(0xC8 | host_reg); + addbyte(imm & 0xff); + } + else + { + addbyte(0x81); /*ORL host_reg, imm*/ + addbyte(0xC8 | host_reg); + addlong(imm); + } +} + +static void NEG_HOST_REG_B(int reg) +{ + addbyte(0xf6); + addbyte(0xd8 | reg); +} +static void NEG_HOST_REG_W(int reg) +{ + addbyte(0x66); + addbyte(0xf7); + addbyte(0xd8 | reg); +} +static void NEG_HOST_REG_L(int reg) +{ + addbyte(0xf7); + addbyte(0xd8 | reg); +} + +static void SUB_HOST_REG_B(int dst_reg, int src_reg) +{ + addbyte(0x28); /*SUBB dst_reg, src_reg*/ + addbyte(0xc0 | dst_reg | (src_reg << 3)); +} +static void SUB_HOST_REG_W(int dst_reg, int src_reg) +{ + addbyte(0x66); /*SUBW dst_reg, src_reg*/ + addbyte(0x29); + addbyte(0xc0 | dst_reg | (src_reg << 3)); +} +static void SUB_HOST_REG_L(int dst_reg, int src_reg) +{ + addbyte(0x29); /*SUBL dst_reg, src_reg*/ + addbyte(0xc0 | dst_reg | (src_reg << 3)); +} +static void SUB_HOST_REG_IMM_B(int host_reg, uint8_t imm) +{ + addbyte(0x80); /*SUBB host_reg, imm*/ + addbyte(0xE8 | host_reg); + addbyte(imm); +} +static void SUB_HOST_REG_IMM_W(int host_reg, uint16_t imm) +{ + if (imm < 0x80 || imm >= 0xff80) + { + addbyte(0x66); /*SUBW host_reg, imm*/ + addbyte(0x83); + addbyte(0xE8 | host_reg); + addbyte(imm & 0xff); + } + else + { + addbyte(0x66); /*SUBW host_reg, imm*/ + addbyte(0x81); + addbyte(0xE8 | host_reg); + addword(imm); + } +} +static void SUB_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + if (imm < 0x80 || imm >= 0xffffff80) + { + addbyte(0x83); /*SUBL host_reg, imm*/ + addbyte(0xE8 | host_reg); + addbyte(imm); + } + else + { + addbyte(0x81); /*SUBL host_reg, imm*/ + addbyte(0xE8 | host_reg); + addlong(imm); + } +} + +static int CMP_HOST_REG_B(int dst_reg, int src_reg) +{ + SUB_HOST_REG_B(dst_reg, src_reg); + + return dst_reg; +} +static int CMP_HOST_REG_W(int dst_reg, int src_reg) +{ + SUB_HOST_REG_W(dst_reg, src_reg); + + return dst_reg; +} +static int CMP_HOST_REG_L(int dst_reg, int src_reg) +{ + SUB_HOST_REG_L(dst_reg, src_reg); + + return dst_reg; +} +static int CMP_HOST_REG_IMM_B(int host_reg, uint8_t imm) +{ + SUB_HOST_REG_IMM_B(host_reg, imm); + + return host_reg; +} +static int CMP_HOST_REG_IMM_W(int host_reg, uint16_t imm) +{ + SUB_HOST_REG_IMM_W(host_reg, imm); + + return host_reg; +} +static int CMP_HOST_REG_IMM_L(int host_reg, uint32_t imm) +{ + SUB_HOST_REG_IMM(host_reg, imm); + + return host_reg; +} + +#define XOR_HOST_REG_B XOR_HOST_REG_L +#define XOR_HOST_REG_W XOR_HOST_REG_L +static void XOR_HOST_REG_L(int dst_reg, int src_reg) +{ + addbyte(0x31); /*XORL dst_reg, src_reg*/ + addbyte(0xc0 | dst_reg | (src_reg << 3)); +} +static void XOR_HOST_REG_IMM(int host_reg, uint32_t imm) +{ + if (imm < 0x80 || imm >= 0xffffff80) + { + addbyte(0x83); /*XORL host_reg, imm*/ + addbyte(0xF0 | host_reg); + addbyte(imm & 0xff); + } + else + { + addbyte(0x81); /*XORL host_reg, imm*/ + addbyte(0xF0 | host_reg); + addlong(imm); + } +} + +static void CALL_FUNC(void *dest) +{ + addbyte(0xE8); /*CALL*/ + addlong(((uint8_t *)dest - (uint8_t *)(&codeblock[block_current].data[block_pos + 4]))); +} + +static void SHL_B_IMM(int reg, int count) +{ + addbyte(0xc0); /*SHL reg, count*/ + addbyte(0xc0 | reg | 0x20); + addbyte(count); +} +static void SHL_W_IMM(int reg, int count) +{ + addbyte(0x66); /*SHL reg, count*/ + addbyte(0xc1); + addbyte(0xc0 | reg | 0x20); + addbyte(count); +} +static void SHL_L_IMM(int reg, int count) +{ + addbyte(0xc1); /*SHL reg, count*/ + addbyte(0xc0 | reg | 0x20); + addbyte(count); +} +static void SHR_B_IMM(int reg, int count) +{ + addbyte(0xc0); /*SHR reg, count*/ + addbyte(0xc0 | reg | 0x28); + addbyte(count); +} +static void SHR_W_IMM(int reg, int count) +{ + addbyte(0x66); /*SHR reg, count*/ + addbyte(0xc1); + addbyte(0xc0 | reg | 0x28); + addbyte(count); +} +static void SHR_L_IMM(int reg, int count) +{ + addbyte(0xc1); /*SHR reg, count*/ + addbyte(0xc0 | reg | 0x28); + addbyte(count); +} +static void SAR_B_IMM(int reg, int count) +{ + addbyte(0xc0); /*SAR reg, count*/ + addbyte(0xc0 | reg | 0x38); + addbyte(count); +} +static void SAR_W_IMM(int reg, int count) +{ + addbyte(0x66); /*SAR reg, count*/ + addbyte(0xc1); + addbyte(0xc0 | reg | 0x38); + addbyte(count); +} +static void SAR_L_IMM(int reg, int count) +{ + addbyte(0xc1); /*SAR reg, count*/ + addbyte(0xc0 | reg | 0x38); + addbyte(count); +} + + +static void CHECK_SEG_READ(x86seg *seg) +{ + /*Segments always valid in real/V86 mode*/ + if (!(cr0 & 1) || (eflags & VM_FLAG)) + return; + /*CS and SS must always be valid*/ + if (seg == &_cs || seg == &_ss) + return; + if (seg->checked) + return; + + addbyte(0x83); /*CMP seg->base, -1*/ + addbyte(0x05|0x38); + addlong((uint32_t)&seg->base); + addbyte(-1); + addbyte(0x0f); + addbyte(0x84); /*JE end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + + seg->checked = 1; +} +static void CHECK_SEG_WRITE(x86seg *seg) +{ + /*Segments always valid in real/V86 mode*/ + if (!(cr0 & 1) || (eflags & VM_FLAG)) + return; + /*CS and SS must always be valid*/ + if (seg == &_cs || seg == &_ss) + return; + if (seg->checked) + return; + + addbyte(0x83); /*CMP seg->base, -1*/ + addbyte(0x05|0x38); + addlong((uint32_t)&seg->base); + addbyte(-1); + addbyte(0x0f); + addbyte(0x84); /*JE end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + + seg->checked = 1; +} +static void CHECK_SEG_LIMITS(x86seg *seg, int end_offset) +{ + addbyte(0x3b); /*CMP EAX, seg->limit_low*/ + addbyte(0x05); + addlong((uint32_t)&seg->limit_low); + addbyte(0x0f); /*JB BLOCK_GPF_OFFSET*/ + addbyte(0x82); + addlong(BLOCK_GPF_OFFSET - (block_pos + 4)); + if (end_offset) + { + addbyte(0x83); /*ADD EAX, end_offset*/ + addbyte(0xc0); + addbyte(end_offset); + addbyte(0x3b); /*CMP EAX, seg->limit_high*/ + addbyte(0x05); + addlong((uint32_t)&seg->limit_high); + addbyte(0x0f); /*JNBE BLOCK_GPF_OFFSET*/ + addbyte(0x87); + addlong(BLOCK_GPF_OFFSET - (block_pos + 4)); + addbyte(0x83); /*SUB EAX, end_offset*/ + addbyte(0xe8); + addbyte(end_offset); + } +} + +static void MEM_LOAD_ADDR_EA_B(x86seg *seg) +{ + addbyte(0x8b); /*MOVL EDX, seg->base*/ + addbyte(0x05 | (REG_EDX << 3)); + addlong((uint32_t)&seg->base); + addbyte(0x89); /*MOV ESI, EDX*/ + addbyte(0xd6); + addbyte(0x01); /*ADDL EDX, EAX*/ + addbyte(0xc2); + addbyte(0x89); /*MOV EDI, EDX*/ + addbyte(0xd7); + addbyte(0xc1); /*SHR EDX, 12*/ + addbyte(0xea); + addbyte(12); + addbyte(0x8b); /*MOV EDX, readlookup2[EDX*4]*/ + addbyte(0x14); + addbyte(0x95); + addlong((uint32_t)readlookup2); + addbyte(0x83); /*CMP EDX, -1*/ + addbyte(0xfa); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(4+2); + addbyte(0x0f); /*MOVZX EAX, B[EDX+EDI]*/ + addbyte(0xb6); + addbyte(0x04); + addbyte(0x3a); + addbyte(0xeb); /*JMP done*/ + addbyte(4+3+5+7+6+3); + addbyte(0x89); /*slowpath: MOV [ESP+4], EAX*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x04); + addbyte(0x89); /*MOV [ESP], ESI*/ + addbyte(0x34); + addbyte(0x24); + addbyte(0xe8); /*CALL readmemb386l*/ + addlong((uint32_t)readmemb386l - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*CMP abrt, 0*/ + addbyte(0x3d); + addlong((uint32_t)&abrt); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + addbyte(0x0f); /*MOVZX EAX, AL*/ + addbyte(0xb6); + addbyte(0xc0); + /*done:*/ + host_reg_mapping[0] = 8; +} +static void MEM_LOAD_ADDR_EA_W(x86seg *seg) +{ + addbyte(0x8b); /*MOVL EDX, seg->base*/ + addbyte(0x05 | (REG_EDX << 3)); + addlong((uint32_t)&seg->base); + addbyte(0x89); /*MOV ESI, EDX*/ + addbyte(0xd6); + addbyte(0x01); /*ADDL EDX, EAX*/ + addbyte(0xc2); + addbyte(0x8d); /*LEA EDI, 1[EDX]*/ + addbyte(0x7a); + addbyte(0x01); + addbyte(0xc1); /*SHR EDX, 12*/ + addbyte(0xea); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 0xfff*/ + addbyte(0xc7); + addlong(0xfff); + addbyte(0x8b); /*MOV EDX, readlookup2[EDX*4]*/ + addbyte(0x14); + addbyte(0x95); + addlong((uint32_t)readlookup2); + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2+5+2); + addbyte(0x83); /*CMP EDX, -1*/ + addbyte(0xfa); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(5+2); + addbyte(0x0f); /*MOVZX EAX, -1[EDX+EDI]W*/ + addbyte(0xb7); + addbyte(0x44); + addbyte(0x3a); + addbyte(-1); + addbyte(0xeb); /*JMP done*/ + addbyte(4+3+5+7+6+3); + addbyte(0x89); /*slowpath: MOV [ESP+4], EAX*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x04); + addbyte(0x89); /*MOV [ESP], ESI*/ + addbyte(0x34); + addbyte(0x24); + addbyte(0xe8); /*CALL readmemwl*/ + addlong((uint32_t)readmemwl - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*CMP abrt, 0*/ + addbyte(0x3d); + addlong((uint32_t)&abrt); + addbyte(0); + addbyte(0x0f); + addbyte(0x85); /*JNE end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + addbyte(0x0f); /*MOVZX EAX, AX*/ + addbyte(0xb7); + addbyte(0xc0); + /*done:*/ + host_reg_mapping[0] = 8; +} +static void MEM_LOAD_ADDR_EA_L(x86seg *seg) +{ + addbyte(0x8b); /*MOVL EDX, seg->base*/ + addbyte(0x05 | (REG_EDX << 3)); + addlong((uint32_t)&seg->base); + addbyte(0x89); /*MOV ESI, EDX*/ + addbyte(0xd6); + addbyte(0x01); /*ADDL EDX, EAX*/ + addbyte(0xc2); + addbyte(0x8d); /*LEA EDI, 3[EDX]*/ + addbyte(0x7a); + addbyte(0x03); + addbyte(0xc1); /*SHR EDX, 12*/ + addbyte(0xea); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 0xffc*/ + addbyte(0xc7); + addlong(0xffc); + addbyte(0x8b); /*MOV EDX, readlookup2[EDX*4]*/ + addbyte(0x14); + addbyte(0x95); + addlong((uint32_t)readlookup2); + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2+4+2); + addbyte(0x83); /*CMP EDX, -1*/ + addbyte(0xfa); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(4+2); + addbyte(0x8b); /*MOV EAX, -3[EDX+EDI]*/ + addbyte(0x44); + addbyte(0x3a); + addbyte(-3); + addbyte(0xeb); /*JMP done*/ + addbyte(4+3+5+7+6); + addbyte(0x89); /*slowpath: MOV [ESP+4], EAX*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x04); + addbyte(0x89); /*MOV [ESP], ESI*/ + addbyte(0x34); + addbyte(0x24); + addbyte(0xe8); /*CALL readmemll*/ + addlong((uint32_t)readmemll - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*CMP abrt, 0*/ + addbyte(0x3d); + addlong((uint32_t)&abrt); + addbyte(0); + addbyte(0x0f); + addbyte(0x85); /*JNE end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ + host_reg_mapping[0] = 8; +} + +static void MEM_LOAD_ADDR_EA_Q(x86seg *seg) +{ + addbyte(0x8b); /*MOVL EDX, seg->base*/ + addbyte(0x05 | (REG_EDX << 3)); + addlong((uint32_t)&seg->base); + addbyte(0x89); /*MOV ESI, EDX*/ + addbyte(0xd6); + addbyte(0x01); /*ADDL EDX, EAX*/ + addbyte(0xc2); + addbyte(0x8d); /*LEA EDI, 7[EDX]*/ + addbyte(0x7a); + addbyte(0x07); + addbyte(0xc1); /*SHR EDX, 12*/ + addbyte(0xea); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 0xff8*/ + addbyte(0xc7); + addlong(0xff8); + addbyte(0x8b); /*MOV EDX, readlookup2[EDX*4]*/ + addbyte(0x14); + addbyte(0x95); + addlong((uint32_t)readlookup2); + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2+4+4+2); + addbyte(0x83); /*CMP EDX, -1*/ + addbyte(0xfa); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(4+4+2); + addbyte(0x8b); /*MOV EAX, [EDX+EDI]*/ + addbyte(0x44); + addbyte(0x3a); + addbyte(-7); + addbyte(0x8b); /*MOV EDX, [EDX+EDI+4]*/ + addbyte(0x54); + addbyte(0x3a); + addbyte(-7+4); + addbyte(0xeb); /*JMP done*/ + addbyte(4+3+5+7+6); + addbyte(0x89); /*slowpath: MOV [ESP+4], EAX*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x04); + addbyte(0x89); /*MOV [ESP], ESI*/ + addbyte(0x34); + addbyte(0x24); + addbyte(0xe8); /*CALL readmemql*/ + addlong((uint32_t)readmemql - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*CMP abrt, 0*/ + addbyte(0x3d); + addlong((uint32_t)&abrt); + addbyte(0); + addbyte(0x0f); + addbyte(0x85); /*JNE end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ + host_reg_mapping[0] = 8; +} + +static void MEM_LOAD_ADDR_IMM_B(x86seg *seg, uint32_t addr) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_LOAD_ADDR_EA_B(seg); +} +static void MEM_LOAD_ADDR_IMM_W(x86seg *seg, uint32_t addr) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_LOAD_ADDR_EA_W(seg); +} +static void MEM_LOAD_ADDR_IMM_L(x86seg *seg, uint32_t addr) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_LOAD_ADDR_EA_L(seg); +} + +static void MEM_STORE_ADDR_EA_B(x86seg *seg, int host_reg) +{ + addbyte(0x8b); /*MOVL ESI, seg->base*/ + addbyte(0x05 | (REG_ESI << 3)); + addlong((uint32_t)&seg->base); + addbyte(0x01); /*ADDL ESI, EAX*/ + addbyte(0xc0 | (REG_EAX << 3) | REG_ESI); + addbyte(0x89); /*MOV EDI, ESI*/ + addbyte(0xc0 | (REG_ESI << 3) | REG_EDI); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0x8b); /*MOV ESI, readlookup2[ESI*4]*/ + addbyte(0x04 | (REG_ESI << 3)); + addbyte(0x85 | (REG_ESI << 3)); + addlong((uint32_t)writelookup2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2); + addbyte(0x88); /*MOV [EDI+ESI],host_reg*/ + addbyte(0x04 | (host_reg << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(0xeb); /*JMP done*/ + addbyte(4+5+4+3+5+7+6); + addbyte(0x89); /*slowpath: MOV [ESP+4], EAX*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x04); + addbyte(0xa1); /*MOV EAX, seg->base*/ + addlong((uint32_t)&seg->base); + addbyte(0x89); /*MOV [ESP+8], host_reg*/ + addbyte(0x44 | (host_reg << 3)); + addbyte(0x24); + addbyte(0x08); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xe8); /*CALL writememb386l*/ + addlong((uint32_t)writememb386l - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*CMP abrt, 0*/ + addbyte(0x3d); + addlong((uint32_t)&abrt); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} +static void MEM_STORE_ADDR_EA_W(x86seg *seg, int host_reg) +{ + addbyte(0x8b); /*MOVL ESI, seg->base*/ + addbyte(0x05 | (REG_ESI << 3)); + addlong((uint32_t)&seg->base); + addbyte(0x01); /*ADDL ESI, EAX*/ + addbyte(0xc0 | (REG_EAX << 3) | REG_ESI); + addbyte(0x8d); /*LEA EDI, 1[ESI]*/ + addbyte(0x7e); + addbyte(0x01); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 0xfff*/ + addbyte(0xc7); + addlong(0xfff); + addbyte(0x8b); /*MOV ESI, readlookup2[ESI*4]*/ + addbyte(0x04 | (REG_ESI << 3)); + addbyte(0x85 | (REG_ESI << 3)); + addlong((uint32_t)writelookup2); + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2+5+2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(5+2); + addbyte(0x66); /*MOV -1[EDI+ESI],host_reg*/ + addbyte(0x89); + addbyte(0x44 | (host_reg << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(-1); + addbyte(0xeb); /*JMP done*/ + addbyte(4+5+4+3+5+7+6); + addbyte(0x89); /*slowpath: MOV [ESP+4], EAX*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x04); + addbyte(0xa1); /*MOV EAX, seg->base*/ + addlong((uint32_t)&seg->base); + addbyte(0x89); /*MOV [ESP+8], host_reg*/ + addbyte(0x44 | (host_reg << 3)); + addbyte(0x24); + addbyte(0x08); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xe8); /*CALL writememwl*/ + addlong((uint32_t)writememwl - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*CMP abrt, 0*/ + addbyte(0x3d); + addlong((uint32_t)&abrt); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} +static void MEM_STORE_ADDR_EA_L(x86seg *seg, int host_reg) +{ + addbyte(0x8b); /*MOVL ESI, seg->base*/ + addbyte(0x05 | (REG_ESI << 3)); + addlong((uint32_t)&seg->base); + addbyte(0x01); /*ADDL ESI, EAX*/ + addbyte(0xc0 | (REG_EAX << 3) | REG_ESI); + addbyte(0x8d); /*LEA EDI, 3[ESI]*/ + addbyte(0x7e); + addbyte(0x03); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 0xffc*/ + addbyte(0xc7); + addlong(0xffc); + addbyte(0x8b); /*MOV ESI, readlookup2[ESI*4]*/ + addbyte(0x04 | (REG_ESI << 3)); + addbyte(0x85 | (REG_ESI << 3)); + addlong((uint32_t)writelookup2); + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2+4+2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(4+2); + addbyte(0x89); /*MOV -3[EDI+ESI],host_reg*/ + addbyte(0x44 | (host_reg << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(-3); + addbyte(0xeb); /*JMP done*/ + addbyte(4+5+4+3+5+7+6); + addbyte(0x89); /*slowpath: MOV [ESP+4], EAX*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x04); + addbyte(0xa1); /*MOV EAX, seg->base*/ + addlong((uint32_t)&seg->base); + addbyte(0x89); /*MOV [ESP+8], host_reg*/ + addbyte(0x44 | (host_reg << 3)); + addbyte(0x24); + addbyte(0x08); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xe8); /*CALL writememll*/ + addlong((uint32_t)writememll - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*CMP abrt, 0*/ + addbyte(0x3d); + addlong((uint32_t)&abrt); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} +static void MEM_STORE_ADDR_EA_Q(x86seg *seg, int host_reg, int host_reg2) +{ + addbyte(0x8b); /*MOVL ESI, seg->base*/ + addbyte(0x05 | (REG_ESI << 3)); + addlong((uint32_t)&seg->base); + addbyte(0x01); /*ADDL ESI, EAX*/ + addbyte(0xc0 | (REG_EAX << 3) | REG_ESI); + addbyte(0x8d); /*LEA EDI, 7[ESI]*/ + addbyte(0x7e); + addbyte(0x07); + addbyte(0xc1); /*SHR ESI, 12*/ + addbyte(0xe8 | REG_ESI); + addbyte(12); + addbyte(0xf7); /*TEST EDI, 0xff8*/ + addbyte(0xc7); + addlong(0xff8); + addbyte(0x8b); /*MOV ESI, readlookup2[ESI*4]*/ + addbyte(0x04 | (REG_ESI << 3)); + addbyte(0x85 | (REG_ESI << 3)); + addlong((uint32_t)writelookup2); + addbyte(0x74); /*JE slowpath*/ + addbyte(3+2+4+4+2); + addbyte(0x83); /*CMP ESI, -1*/ + addbyte(0xf8 | REG_ESI); + addbyte(-1); + addbyte(0x74); /*JE slowpath*/ + addbyte(4+4+2); + addbyte(0x89); /*MOV [EDI+ESI],host_reg*/ + addbyte(0x44 | (host_reg << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(-7); + addbyte(0x89); /*MOV [EDI+ESI+4],host_reg2*/ + addbyte(0x44 | (host_reg2 << 3)); + addbyte(REG_EDI | (REG_ESI << 3)); + addbyte(-7+0x04); + addbyte(0xeb); /*JMP done*/ + addbyte(4+5+4+4+3+5+7+6); + addbyte(0x89); /*slowpath: MOV [ESP+4], EAX*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x04); + addbyte(0xa1); /*MOV EAX, seg->base*/ + addlong((uint32_t)&seg->base); + addbyte(0x89); /*MOV [ESP+8], host_reg*/ + addbyte(0x44 | (host_reg << 3)); + addbyte(0x24); + addbyte(0x08); + addbyte(0x89); /*MOV [ESP+12], host_reg2*/ + addbyte(0x44 | (host_reg2 << 3)); + addbyte(0x24); + addbyte(0x0c); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xe8); /*CALL writememql*/ + addlong((uint32_t)writememql - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0x83); /*CMP abrt, 0*/ + addbyte(0x3d); + addlong((uint32_t)&abrt); + addbyte(0); + addbyte(0x0f); /*JNE end*/ + addbyte(0x85); + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + /*done:*/ +} + +static void MEM_STORE_ADDR_IMM_B(x86seg *seg, uint32_t addr, int host_reg) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_STORE_ADDR_EA_B(seg, host_reg); +} +static void MEM_STORE_ADDR_IMM_L(x86seg *seg, uint32_t addr, int host_reg) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_STORE_ADDR_EA_L(seg, host_reg); +} +static void MEM_STORE_ADDR_IMM_W(x86seg *seg, uint32_t addr, int host_reg) +{ + addbyte(0xb8); /*MOV EAX, addr*/ + addlong(addr); + MEM_STORE_ADDR_EA_W(seg, host_reg); +} + + +static x86seg *FETCH_EA_16(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc) +{ + int mod = (fetchdat >> 6) & 3; + int reg = (fetchdat >> 3) & 7; + int rm = fetchdat & 7; + if (!mod && rm == 6) + { + addbyte(0xb8); /*MOVL EAX, imm16*/ + addlong((fetchdat >> 8) & 0xffff); + (*op_pc) += 2; + } + else + { + switch (mod) + { + case 0: + addbyte(0xa1); /*MOVL EAX, *mod1add[0][rm]*/ + addlong((uint32_t)mod1add[0][rm]); + if (mod1add[1][rm] != &zero) + { + addbyte(0x03); /*ADDL EAX, *mod1add[1][rm]*/ + addbyte(0x05); + addlong((uint32_t)mod1add[1][rm]); + } + break; + case 1: + addbyte(0xa1); /*MOVL EAX, *mod1add[0][rm]*/ + addlong((uint32_t)mod1add[0][rm]); + addbyte(0x83); /*ADDL EAX, imm8*/ + addbyte(0xc0 | REG_EAX); + addbyte((int8_t)(rmdat >> 8)); + if (mod1add[1][rm] != &zero) + { + addbyte(0x03); /*ADDL EAX, *mod1add[1][rm]*/ + addbyte(0x05); + addlong((uint32_t)mod1add[1][rm]); + } + (*op_pc)++; + break; + case 2: + addbyte(0xb8); /*MOVL EAX, imm16*/ + addlong((fetchdat >> 8) & 0xffff);// pc++; + addbyte(0x03); /*ADDL EAX, *mod1add[0][rm]*/ + addbyte(0x05); + addlong((uint32_t)mod1add[0][rm]); + if (mod1add[1][rm] != &zero) + { + addbyte(0x03); /*ADDL EAX, *mod1add[1][rm]*/ + addbyte(0x05); + addlong((uint32_t)mod1add[1][rm]); + } + (*op_pc) += 2; + break; + } + addbyte(0x25); /*ANDL EAX, 0xffff*/ + addlong(0xffff); + + if (mod1seg[rm] == &ss && !op_ssegs) + op_ea_seg = &_ss; + } + return op_ea_seg; +} + +static x86seg *FETCH_EA_32(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, int stack_offset) +{ + uint32_t new_eaaddr; + int mod = (fetchdat >> 6) & 3; + int reg = (fetchdat >> 3) & 7; + int rm = fetchdat & 7; + + if (rm == 4) + { + uint8_t sib = fetchdat >> 8; + (*op_pc)++; + + switch (mod) + { + case 0: + if ((sib & 7) == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0xb8); /*MOVL EAX, imm32*/ + addlong(new_eaaddr);// pc++; + (*op_pc) += 4; + } + else + { + addbyte(0x8b); /*MOVL EAX, regs[sib&7].l*/ + addbyte(0x45); + addbyte((uint32_t)&cpu_state.regs[sib & 7].l - (uint32_t)&EAX); + } + break; + case 1: + addbyte(0x8b); /*MOVL EAX, regs[sib&7].l*/ + addbyte(0x45); + addbyte((uint32_t)&cpu_state.regs[sib & 7].l - (uint32_t)&EAX); + addbyte(0x83); /*ADDL EAX, imm8*/ + addbyte(0xc0 | REG_EAX); + addbyte((int8_t)(rmdat >> 16)); + (*op_pc)++; + break; + case 2: + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0xb8); /*MOVL EAX, new_eaaddr*/ + addlong(new_eaaddr); + addbyte(0x03); /*ADDL EAX, regs[sib&7].l*/ + addbyte(0x45); + addbyte((uint32_t)&cpu_state.regs[sib & 7].l - (uint32_t)&EAX); + (*op_pc) += 4; + break; + } + if (stack_offset && (sib & 7) == 4 && (mod || (sib & 7) != 5)) /*ESP*/ + { + if (stack_offset < 0x80 || stack_offset >= 0xffffff80) + { + addbyte(0x83); + addbyte(0xc0 | REG_EAX); + addbyte(stack_offset); + } + else + { + addbyte(0x05); /*ADDL EAX, stack_offset*/ + addlong(stack_offset); + } + } + if (((sib & 7) == 4 || (mod && (sib & 7) == 5)) && !op_ssegs) + op_ea_seg = &_ss; + if (((sib >> 3) & 7) != 4) + { + switch (sib >> 6) + { + case 0: + addbyte(0x03); /*ADDL EAX, regs[sib&7].l*/ + addbyte(0x45); + addbyte((uint32_t)&cpu_state.regs[(sib >> 3) & 7].l - (uint32_t)&EAX); + break; + case 1: + addbyte(0x8B); addbyte(0x45 | (REG_EDI << 3)); addbyte((uint32_t)&cpu_state.regs[(sib >> 3) & 7].l - (uint32_t)&EAX); /*MOVL EDI, reg*/ + addbyte(0x01); addbyte(0xc0 | REG_EAX | (REG_EDI << 3)); /*ADDL EAX, EDI*/ + addbyte(0x01); addbyte(0xc0 | REG_EAX | (REG_EDI << 3)); /*ADDL EAX, EDI*/ + break; + case 2: + addbyte(0x8B); addbyte(0x45 | (REG_EDI << 3)); addbyte((uint32_t)&cpu_state.regs[(sib >> 3) & 7].l - (uint32_t)&EAX); /*MOVL EDI, reg*/ + addbyte(0xC1); addbyte(0xE0 | REG_EDI); addbyte(2); /*SHL EDI, 2*/ + addbyte(0x01); addbyte(0xc0 | REG_EAX | (REG_EDI << 3)); /*ADDL EAX, EDI*/ + break; + case 3: + addbyte(0x8B); addbyte(0x45 | (REG_EDI << 3)); addbyte((uint32_t)&cpu_state.regs[(sib >> 3) & 7].l - (uint32_t)&EAX); /*MOVL EDI reg*/ + addbyte(0xC1); addbyte(0xE0 | REG_EDI); addbyte(3); /*SHL EDI, 3*/ + addbyte(0x01); addbyte(0xc0 | REG_EAX | (REG_EDI << 3)); /*ADDL EAX, EDI*/ + break; + } + } + } + else + { + if (!mod && rm == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0xb8); /*MOVL EAX, imm32*/ + addlong(new_eaaddr); + (*op_pc) += 4; + return op_ea_seg; + } + addbyte(0x8b); /*MOVL EAX, regs[rm].l*/ + addbyte(0x45); + addbyte((uint32_t)&cpu_state.regs[rm].l - (uint32_t)&EAX); + eaaddr = cpu_state.regs[rm].l; + if (mod) + { + if (rm == 5 && !op_ssegs) + op_ea_seg = &_ss; + if (mod == 1) + { + addbyte(0x83); /*ADD EAX, imm8*/ + addbyte(0xc0 | REG_EAX); + addbyte((int8_t)(fetchdat >> 8)); + (*op_pc)++; + } + else + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0x05); /*ADD EAX, imm32*/ + addlong(new_eaaddr); + (*op_pc) += 4; + } + } + } + return op_ea_seg; +} + +static x86seg *FETCH_EA(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, uint32_t op_32) +{ + if (op_32 & 0x200) + return FETCH_EA_32(op_ea_seg, fetchdat, op_ssegs, op_pc, 0); + return FETCH_EA_16(op_ea_seg, fetchdat, op_ssegs, op_pc); +} + + +static void LOAD_STACK_TO_EA(int off) +{ + if (stack32) + { + addbyte(0x8b); /*MOVL EAX,[ESP]*/ + addbyte(0x45 | (REG_EAX << 3)); + addbyte((uint32_t)&ESP - (uint32_t)&EAX); + if (off) + { + addbyte(0x83); /*ADD EAX, off*/ + addbyte(0xc0 | (0 << 3) | REG_EAX); + addbyte(off); + } + } + else + { + addbyte(0x0f); /*MOVZX EAX,W[ESP]*/ + addbyte(0xb7); + addbyte(0x45 | (REG_EAX << 3)); + addbyte((uint32_t)&ESP - (uint32_t)&EAX); + if (off) + { + addbyte(0x66); /*ADD AX, off*/ + addbyte(0x05); + addword(off); + } + } +} + +static void LOAD_EBP_TO_EA(int off) +{ + if (stack32) + { + addbyte(0x8b); /*MOVL EAX,[EBP]*/ + addbyte(0x45 | (REG_EAX << 3)); + addbyte((uint32_t)&EBP - (uint32_t)&EAX); + if (off) + { + addbyte(0x83); /*ADD EAX, off*/ + addbyte(0xc0 | (0 << 3) | REG_EAX); + addbyte(off); + } + } + else + { + addbyte(0x0f); /*MOVZX EAX,W[EBP]*/ + addbyte(0xb7); + addbyte(0x45 | (REG_EAX << 3)); + addbyte((uint32_t)&EBP - (uint32_t)&EAX); + if (off) + { + addbyte(0x66); /*ADD AX, off*/ + addbyte(0x05); + addword(off); + } + } +} + +static void SP_MODIFY(int off) +{ + if (stack32) + { + if (off < 0x80) + { + addbyte(0x83); /*ADD [ESP], off*/ + addbyte(0x45); + addbyte((uint32_t)&ESP - (uint32_t)&EAX); + addbyte(off); + } + else + { + addbyte(0x81); /*ADD [ESP], off*/ + addbyte(0x45); + addbyte((uint32_t)&ESP - (uint32_t)&EAX); + addlong(off); + } + } + else + { + if (off < 0x80) + { + addbyte(0x66); /*ADD [SP], off*/ + addbyte(0x83); + addbyte(0x45); + addbyte((uint32_t)&SP - (uint32_t)&EAX); + addbyte(off); + } + else + { + addbyte(0x66); /*ADD [SP], off*/ + addbyte(0x81); + addbyte(0x45); + addbyte((uint32_t)&SP - (uint32_t)&EAX); + addword(off); + } + } +} + + +static void TEST_ZERO_JUMP_W(int host_reg, uint32_t new_pc, int taken_cycles) +{ + addbyte(0x66); /*CMPW host_reg, 0*/ + addbyte(0x83); + addbyte(0xc0 | 0x38 | host_reg); + addbyte(0); + addbyte(0x75); /*JNZ +*/ + addbyte(7+5+(taken_cycles ? 7 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.pc - (uintptr_t)&cpu_state); + addlong(new_pc); + if (taken_cycles) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2d); + addlong((uintptr_t)&cycles); + addbyte(taken_cycles); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} +static void TEST_ZERO_JUMP_L(int host_reg, uint32_t new_pc, int taken_cycles) +{ + addbyte(0x83); /*CMPW host_reg, 0*/ + addbyte(0xc0 | 0x38 | host_reg); + addbyte(0); + addbyte(0x75); /*JNZ +*/ + addbyte(7+5+(taken_cycles ? 7 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.pc - (uintptr_t)&cpu_state); + addlong(new_pc); + if (taken_cycles) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2d); + addlong((uintptr_t)&cycles); + addbyte(taken_cycles); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} + +static void TEST_NONZERO_JUMP_W(int host_reg, uint32_t new_pc, int taken_cycles) +{ + addbyte(0x66); /*CMPW host_reg, 0*/ + addbyte(0x83); + addbyte(0xc0 | 0x38 | host_reg); + addbyte(0); + addbyte(0x74); /*JZ +*/ + addbyte(7+5+(taken_cycles ? 7 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.pc - (uintptr_t)&cpu_state); + addlong(new_pc); + if (taken_cycles) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2d); + addlong((uintptr_t)&cycles); + addbyte(taken_cycles); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} +static void TEST_NONZERO_JUMP_L(int host_reg, uint32_t new_pc, int taken_cycles) +{ + addbyte(0x83); /*CMPW host_reg, 0*/ + addbyte(0xc0 | 0x38 | host_reg); + addbyte(0); + addbyte(0x74); /*JZ +*/ + addbyte(7+5+(taken_cycles ? 7 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.pc - (uintptr_t)&cpu_state); + addlong(new_pc); + if (taken_cycles) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2d); + addlong((uintptr_t)&cycles); + addbyte(taken_cycles); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} + +static int BRANCH_COND_BE(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_SUB8: + addbyte(0x8a); /*MOV AL, flags_op1*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op1 - (uintptr_t)&cpu_state); + addbyte(0x3a); /*CMP AL, flags_op2*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op2 - (uintptr_t)&cpu_state); + if (not) + addbyte(0x76); /*JBE*/ + else + addbyte(0x77); /*JNBE*/ + break; + case FLAGS_SUB16: + addbyte(0x66); /*MOV AX, flags_op1*/ + addbyte(0x8b); + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op1 - (uintptr_t)&cpu_state); + addbyte(0x66); /*CMP AX, flags_op2*/ + addbyte(0x3b); + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op2 - (uintptr_t)&cpu_state); + if (not) + addbyte(0x76); /*JBE*/ + else + addbyte(0x77); /*JNBE*/ + break; + case FLAGS_SUB32: + addbyte(0x8b); /*MOV EAX, flags_op1*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op1 - (uintptr_t)&cpu_state); + addbyte(0x3b); /*CMP EAX, flags_op2*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op2 - (uintptr_t)&cpu_state); + if (not) + addbyte(0x76); /*JBE*/ + else + addbyte(0x77); /*JNBE*/ + break; + + default: + if (codegen_flags_changed && cpu_state.flags_op != FLAGS_UNKNOWN) + { + addbyte(0x83); /*CMP flags_res, 0*/ + addbyte(0x7d); + addbyte((uintptr_t)&cpu_state.flags_res - (uintptr_t)&cpu_state); + addbyte(0); + addbyte(0x74); /*JZ +*/ + } + else + { + CALL_FUNC(ZF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x75); /*JNZ +*/ + } + if (not) + addbyte(5+2+2+7+5+(timing_bt ? 7 : 0)); + else + addbyte(5+2+2); + CALL_FUNC(CF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + if (not) + addbyte(0x75); /*JNZ +*/ + else + addbyte(0x74); /*JZ +*/ + break; + } + addbyte(7+5+(timing_bt ? 7 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.pc - (uintptr_t)&cpu_state); + addlong(op_pc+pc_offset+offset); + if (timing_bt) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2d); + addlong((uintptr_t)&cycles); + addbyte(timing_bt); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} + +static int BRANCH_COND_L(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_SUB8: + addbyte(0x8a); /*MOV AL, flags_op1*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op1 - (uintptr_t)&cpu_state); + addbyte(0x3a); /*CMP AL, flags_op2*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op2 - (uintptr_t)&cpu_state); + if (not) + addbyte(0x7c); /*JL*/ + else + addbyte(0x7d); /*JNL*/ + break; + case FLAGS_SUB16: + addbyte(0x66); /*MOV AX, flags_op1*/ + addbyte(0x8b); + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op1 - (uintptr_t)&cpu_state); + addbyte(0x66); /*CMP AX, flags_op2*/ + addbyte(0x3b); + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op2 - (uintptr_t)&cpu_state); + if (not) + addbyte(0x7c); /*JL*/ + else + addbyte(0x7d); /*JNL*/ + break; + case FLAGS_SUB32: + addbyte(0x8b); /*MOV EAX, flags_op1*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op1 - (uintptr_t)&cpu_state); + addbyte(0x3b); /*CMP EAX, flags_op2*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op2 - (uintptr_t)&cpu_state); + if (not) + addbyte(0x7c); /*JL*/ + else + addbyte(0x7d); /*JNL*/ + break; + + default: + CALL_FUNC(NF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*SETNE BL*/ + addbyte(0x95); + addbyte(0xc3); + CALL_FUNC(VF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*SETNE AL*/ + addbyte(0x95); + addbyte(0xc0); + addbyte(0x38); /*CMP AL, BL*/ + addbyte(0xd8); + if (not) + addbyte(0x75); /*JNZ +*/ + else + addbyte(0x74); /*JZ +*/ + break; + } + addbyte(7+5+(timing_bt ? 7 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.pc - (uintptr_t)&cpu_state); + addlong(op_pc+pc_offset+offset); + if (timing_bt) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2d); + addlong((uintptr_t)&cycles); + addbyte(timing_bt); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} + +static int BRANCH_COND_LE(int pc_offset, uint32_t op_pc, uint32_t offset, int not) +{ + switch (codegen_flags_changed ? cpu_state.flags_op : FLAGS_UNKNOWN) + { + case FLAGS_SUB8: + addbyte(0x8a); /*MOV AL, flags_op1*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op1 - (uintptr_t)&cpu_state); + addbyte(0x3a); /*CMP AL, flags_op2*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op2 - (uintptr_t)&cpu_state); + if (not) + addbyte(0x7e); /*JLE*/ + else + addbyte(0x7f); /*JNLE*/ + break; + case FLAGS_SUB16: + addbyte(0x66); /*MOV AX, flags_op1*/ + addbyte(0x8b); + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op1 - (uintptr_t)&cpu_state); + addbyte(0x66); /*CMP AX, flags_op2*/ + addbyte(0x3b); + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op2 - (uintptr_t)&cpu_state); + if (not) + addbyte(0x7e); /*JLE*/ + else + addbyte(0x7f); /*JNLE*/ + break; + case FLAGS_SUB32: + addbyte(0x8b); /*MOV EAX, flags_op1*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op1 - (uintptr_t)&cpu_state); + addbyte(0x3b); /*CMP EAX, flags_op2*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.flags_op2 - (uintptr_t)&cpu_state); + if (not) + addbyte(0x7e); /*JLE*/ + else + addbyte(0x7f); /*JNLE*/ + break; + + default: + if (codegen_flags_changed && cpu_state.flags_op != FLAGS_UNKNOWN) + { + addbyte(0x83); /*CMP flags_res, 0*/ + addbyte(0x7d); + addbyte((uintptr_t)&cpu_state.flags_res - (uintptr_t)&cpu_state); + addbyte(0); + addbyte(0x74); /*JZ +*/ + } + else + { + CALL_FUNC(ZF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x75); /*JNZ +*/ + } + if (not) + addbyte(5+2+3+5+2+3+2+2+7+5+(timing_bt ? 7 : 0)); + else + addbyte(5+2+3+5+2+3+2+2); + + CALL_FUNC(NF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*SETNE BL*/ + addbyte(0x95); + addbyte(0xc3); + CALL_FUNC(VF_SET); + addbyte(0x85); /*TEST EAX,EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*SETNE AL*/ + addbyte(0x95); + addbyte(0xc0); + addbyte(0x38); /*CMP AL, BL*/ + addbyte(0xd8); + if (not) + addbyte(0x75); /*JNZ +*/ + else + addbyte(0x74); /*JZ +*/ + break; + } + addbyte(7+5+(timing_bt ? 7 : 0)); + addbyte(0xC7); /*MOVL [pc], new_pc*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.pc - (uintptr_t)&cpu_state); + addlong(op_pc+pc_offset+offset); + if (timing_bt) + { + addbyte(0x83); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2d); + addlong((uintptr_t)&cycles); + addbyte(timing_bt); + } + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); +} + + +static void FP_ENTER() +{ + if (codegen_fpu_entered) + return; + + addbyte(0xf6); /*TEST cr0, 0xc*/ + addbyte(0x05); + addlong((uintptr_t)&cr0); + addbyte(0xc); + addbyte(0x74); /*JZ +*/ + addbyte(10+7+5+5); + addbyte(0xC7); /*MOVL [oldpc],op_old_pc*/ + addbyte(0x05); + addlong((uintptr_t)&oldpc); + addlong(op_old_pc); + addbyte(0xc7); /*MOV [ESP], 7*/ + addbyte(0x04); + addbyte(0x24); + addlong(7); + addbyte(0xe8); /*CALL x86_int*/ + addlong((uint32_t)x86_int - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + + codegen_fpu_entered = 1; +} + +static void FP_FLD(int reg) +{ + addbyte(0xa1); /*MOV EAX, [TOP]*/ + addlong((uintptr_t)&TOP); + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + if (reg) + { + addbyte(0x83); /*ADD EAX, reg*/ + addbyte(0xc0); + addbyte(reg); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(0x01); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(0x07); + } + else + { + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(0x01); + } + + addbyte(0xdd); /*FLD [ST+EAX*8]*/ + addbyte(0x04); + addbyte(0xc5); + addlong((uintptr_t)ST); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(0x07); + addbyte(0x8b); /*MOV EDX, [ST_i64+EAX]*/ + addbyte(0x14); + addbyte(0xc5); + addlong((uintptr_t)ST_i64); + addbyte(0x8b); /*MOV ECX, [ST_i64+4+EAX]*/ + addbyte(0x0c); + addbyte(0xc5); + addlong(((uintptr_t)ST_i64) + 4); + addbyte(0x8a); /*MOV AL, [tag+EAX]*/ + addbyte(0x80); + addlong((uintptr_t)tag); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x1c); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x88); /*MOV [tag+EBX], AL*/ + addbyte(0x83); + addlong((uintptr_t)tag); + addbyte(0x89); /*MOV [ST_i64+EBX], EDX*/ + addbyte(0x14); + addbyte(0xdd); + addlong((uintptr_t)ST_i64); + addbyte(0x89); /*MOV [ST_i64+EBX+4], ECX*/ + addbyte(0x0c); + addbyte(0xdd); + addlong(((uintptr_t)ST_i64) + 4); + + addbyte(0x89); /*MOV [TOP], EBX*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); +} + +static void FP_FST(int reg) +{ + addbyte(0xa1); /*MOV EAX, [TOP]*/ + addlong((uintptr_t)&TOP); + addbyte(0xdd); /*FLD [ST+EAX*8]*/ + addbyte(0x04); + addbyte(0xc5); + addlong((uintptr_t)ST); + addbyte(0x88); /*MOV BL, [tag+EAX]*/ + addbyte(0x98); + addlong((uintptr_t)tag); + + if (reg) + { + addbyte(0x83); /*ADD EAX, reg*/ + addbyte(0xc0); + addbyte(reg); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(0x07); + } + + addbyte(0xdd); /*FSTP [ST+EAX*8]*/ + addbyte(0x1c); + addbyte(0xc5); + addlong((uintptr_t)ST); + addbyte(0x8a); /*MOV [tag+EAX], BL*/ + addbyte(0x98); + addlong((uintptr_t)tag); +} + +static void FP_FXCH(int reg) +{ + addbyte(0xa1); /*MOV EAX, [TOP]*/ + addlong((uintptr_t)&TOP); + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + addbyte(0x83); /*ADD EAX, reg*/ + addbyte(0xc0); + addbyte(reg); +//#if 0 + addbyte(0xdd); /*FLD [ST+EBX*8]*/ + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(0x07); + addbyte(0xdd); /*FLD [ST+EAX*8]*/ + addbyte(0x04); + addbyte(0xc5); + addlong((uintptr_t)ST); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x1c); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0xdd); /*FSTP [ST+EAX*8]*/ + addbyte(0x1c); + addbyte(0xc5); + addlong((uintptr_t)ST); + addbyte(0xbe); /*MOVL ESI, tag*/ + addlong((uintptr_t)tag); + addbyte(0x8a); /*MOV CL, tag[EAX]*/ + addbyte(0x0c); + addbyte(0x06); + addbyte(0x8a); /*MOV DL, tag[EBX]*/ + addbyte(0x14); + addbyte(0x1e); + addbyte(0x88); /*MOV tag[EBX], CL*/ + addbyte(0x0c); + addbyte(0x1e); + addbyte(0x88); /*MOV tag[EAX], DL*/ + addbyte(0x14); + addbyte(0x06); + addbyte(0xbe); /*MOVL ESI, ST_int64*/ + addlong((uintptr_t)ST_i64); + addbyte(0x8b); /*MOV ECX, ST_int64[EAX*8]*/ + addbyte(0x0c); + addbyte(0xc6); + addbyte(0x8b); /*MOV EDX, ST_int64[EBX*8]*/ + addbyte(0x14); + addbyte(0xde); + addbyte(0x89); /*MOV ST_int64[EBX*8], ECX*/ + addbyte(0x0c); + addbyte(0xde); + addbyte(0x89); /*MOV ST_int64[EAX*8], EDX*/ + addbyte(0x14); + addbyte(0xc6); + addbyte(0x8b); /*MOV ECX, ST_int64[EAX*8]+4*/ + addbyte(0x4c); + addbyte(0xc6); + addbyte(0x04); + addbyte(0x8b); /*MOV EDX, ST_int64[EBX*8]+4*/ + addbyte(0x54); + addbyte(0xde); + addbyte(0x04); + addbyte(0x89); /*MOV ST_int64[EBX*8]+4, ECX*/ + addbyte(0x4c); + addbyte(0xde); + addbyte(0x04); + addbyte(0x89); /*MOV ST_int64[EAX*8]+4, EDX*/ + addbyte(0x54); + addbyte(0xc6); + addbyte(0x04); + reg = reg; +//#endif +#if 0 + addbyte(0xbe); /*MOVL ESI, ST*/ + addlong((uintptr_t)ST); + + addbyte(0x8b); /*MOVL EDX, [ESI+EBX*8]*/ + addbyte(0x14); + addbyte(0xde); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(0x07); + addbyte(0x8b); /*MOVL ECX, [ESI+EAX*8]*/ + addbyte(0x0c); + addbyte(0xc6); + addbyte(0x89); /*MOVL [ESI+EBX*8], ECX*/ + addbyte(0x0c); + addbyte(0xde); + addbyte(0x89); /*MOVL [ESI+EAX*8], EDX*/ + addbyte(0x14); + addbyte(0xc6); + + addbyte(0x8b); /*MOVL ECX, [4+ESI+EAX*8]*/ + addbyte(0x4c); + addbyte(0xc6); + addbyte(0x04); + addbyte(0x8b); /*MOVL EDX, [4+ESI+EBX*8]*/ + addbyte(0x54); + addbyte(0xde); + addbyte(0x04); + addbyte(0x89); /*MOVL [4+ESI+EBX*8], ECX*/ + addbyte(0x4c); + addbyte(0xde); + addbyte(0x04); + addbyte(0x89); /*MOVL [4+ESI+EAX*8], EDX*/ + addbyte(0x54); + addbyte(0xc6); + addbyte(0x04); +#endif +} + + +static void FP_LOAD_S() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(1); + addbyte(0xd9); /*FLD [ESP]*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + addbyte(0x83); /*CMP EAX, 0*/ + addbyte(0xf8); + addbyte(0); + addbyte(0x89); /*MOV TOP, EBX*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x1c); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x0f); /*SETE [tag+EBX]*/ + addbyte(0x94); + addbyte(0x83); + addlong((uintptr_t)tag); +} +static void FP_LOAD_D() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x89); /*MOV [ESP+4], EDX*/ + addbyte(0x54); + addbyte(0x24); + addbyte(0x04); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(1); + addbyte(0x09); /*OR EAX, EDX*/ + addbyte(0xd0); + addbyte(0xdd); /*FLD [ESP]*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + addbyte(0x83); /*CMP EAX, 0*/ + addbyte(0xf8); + addbyte(0); + addbyte(0x89); /*MOV TOP, EBX*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x1c); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x0f); /*SETE [tag+EBX]*/ + addbyte(0x94); + addbyte(0x83); + addlong((uintptr_t)tag); +} +static void FP_LOAD_IW() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(1); + addbyte(0xdf); /*FILDw [ESP]*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + addbyte(0x83); /*CMP EAX, 0*/ + addbyte(0xf8); + addbyte(0); + addbyte(0x89); /*MOV TOP, EBX*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x1c); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x0f); /*SETE [tag+EBX]*/ + addbyte(0x94); + addbyte(0x83); + addlong((uintptr_t)tag); +} +static void FP_LOAD_IL() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(1); + addbyte(0xdb); /*FILDl [ESP]*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + addbyte(0x83); /*CMP EAX, 0*/ + addbyte(0xf8); + addbyte(0); + addbyte(0x89); /*MOV TOP, EBX*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x1c); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x0f); /*SETE [tag+EBX]*/ + addbyte(0x94); + addbyte(0x83); + addlong((uintptr_t)tag); +} +static void FP_LOAD_IQ() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0x83); /*SUB EBX, 1*/ + addbyte(0xeb); + addbyte(1); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + addbyte(0x89); /*MOV [ST_i64+EBX*8], EAX*/ + addbyte(0x04); + addbyte(0xdd); + addlong((uint32_t)ST_i64); + addbyte(0x09); /*OR EAX, EDX*/ + addbyte(0xd0); + addbyte(0x89); /*MOV [ST_i64+4+EBX*8], EDX*/ + addbyte(0x14); + addbyte(0xdd); + addlong(((uint32_t)ST_i64) + 4); + addbyte(0x83); /*CMP EAX, 0*/ + addbyte(0xf8); + addbyte(0); + addbyte(0xdf); /*FILDl [ST_i64+EBX*8]*/ + addbyte(0x2c); + addbyte(0xdd); + addlong((uint32_t)ST_i64); + addbyte(0x0f); /*SETE AL*/ + addbyte(0x94); + addbyte(0xc0); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x1c); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x0c); /*OR AL, TAG_UINT64*/ + addbyte(TAG_UINT64); + addbyte(0x89); /*MOV TOP, EBX*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0x88); /*MOV [tag+EBX], AL*/ + addbyte(0x83); + addlong((uint32_t)tag); +} + +static int FP_LOAD_REG(int reg) +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + if (reg) + { + addbyte(0x83); /*ADD EBX, reg*/ + addbyte(0xc3); + addbyte(reg); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + } + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0xd9); /*FSTP [ESP]*/ + addbyte(0x1c); + addbyte(0x24); + addbyte(0x8b); /*MOV EAX, [ESP]*/ + addbyte(0x04 | (REG_EBX << 3)); + addbyte(0x24); + + return REG_EBX; +} + +static void FP_LOAD_REG_D(int reg, int *host_reg1, int *host_reg2) +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + if (reg) + { + addbyte(0x83); /*ADD EBX, reg*/ + addbyte(0xc3); + addbyte(reg); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + } + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0xdd); /*FSTP [ESP]*/ + addbyte(0x1c); + addbyte(0x24); + addbyte(0x8b); /*MOV EBX, [ESP]*/ + addbyte(0x04 | (REG_EBX << 3)); + addbyte(0x24); + addbyte(0x8b); /*MOV ECX, [ESP+4]*/ + addbyte(0x44 | (REG_ECX << 3)); + addbyte(0x24); + addbyte(0x04); + + *host_reg1 = REG_EBX; + *host_reg2 = REG_ECX; +} + + +static double _fp_half = 0.5; + +static void FP_LOAD_ROUNDING() +{ + pclog("npxc %04x\n", npxc); + addbyte(0x8b); /*MOV EDX, npxc*/ + addbyte(0x15); + addlong((uintptr_t)&npxc); + addbyte(0xd9); /*FSTCW [ESP+8]*/ + addbyte(0x7c); + addbyte(0x24); + addbyte(0x08); + addbyte(0x89); /*MOV [ESP+12],EDX*/ + addbyte(0x54); + addbyte(0x24); + addbyte(0x0c); + addbyte(0xd9); /*FLDCW [ESP+12]*/ + addbyte(0x6c); + addbyte(0x24); + addbyte(0x0c); +} +static void FP_RESTORE_ROUNDING() +{ + addbyte(0xd9); /*FLDCW [ESP+8]*/ + addbyte(0x6c); + addbyte(0x24); + addbyte(0x08); +} + +static int32_t x87_fround32(double b) +{ + int64_t a, c; + + switch ((npxc>>10)&3) + { + case 0: /*Nearest*/ + a = (int64_t)floor(b); + c = (int64_t)floor(b + 1.0); + if ((b - a) < (c - b)) + return a; + else if ((b - a) > (c - b)) + return c; + else + return (a & 1) ? c : a; + case 1: /*Down*/ + return (int32_t)floor(b); + case 2: /*Up*/ + return (int32_t)ceil(b); + case 3: /*Chop*/ + return (int32_t)b; + } +} +static int64_t x87_fround64(double b) +{ + int64_t a, c; + + switch ((npxc>>10)&3) + { + case 0: /*Nearest*/ + a = (int64_t)floor(b); + c = (int64_t)floor(b + 1.0); + if ((b - a) < (c - b)) + return a; + else if ((b - a) > (c - b)) + return c; + else + return (a & 1) ? c : a; + case 1: /*Down*/ + return (int64_t)floor(b); + case 2: /*Up*/ + return (int64_t)ceil(b); + case 3: /*Chop*/ + return (int64_t)b; + } +} +static int FP_LOAD_REG_INT_W(int reg) +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + if (reg) + { + addbyte(0x83); /*ADD EBX, reg*/ + addbyte(0xc3); + addbyte(reg); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + } + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + + addbyte(0x89); /*MOV [ESP+8], EAX*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x08); + + addbyte(0xdd); /*FSTP [ESP]*/ + addbyte(0x1c); + addbyte(0x24); + + CALL_FUNC(x87_fround32); + + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + + addbyte(0x8b); /*MOV EAX, [ESP+8]*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x08); + + return REG_EBX; +} +static int FP_LOAD_REG_INT(int reg) +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + if (reg) + { + addbyte(0x83); /*ADD EBX, reg*/ + addbyte(0xc3); + addbyte(reg); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + } + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + + addbyte(0x89); /*MOV [ESP+8], EAX*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x08); + + addbyte(0xdd); /*FSTP [ESP]*/ + addbyte(0x1c); + addbyte(0x24); + + CALL_FUNC(x87_fround32); + + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + + addbyte(0x8b); /*MOV EAX, [ESP+8]*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x08); + + return REG_EBX; +} +static void FP_LOAD_REG_INT_Q(int reg, int *host_reg1, int *host_reg2) +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + if (reg) + { + addbyte(0x83); /*ADD EBX, reg*/ + addbyte(0xc3); + addbyte(reg); + addbyte(0x83); /*AND EBX, 7*/ + addbyte(0xe3); + addbyte(7); + } + if (codegen_fpu_loaded_iq[TOP] && (tag[TOP] & TAG_UINT64)) + { + /*If we know the register was loaded with FILDq in this block and + has not been modified, then we can skip most of the conversion + and just load the 64-bit integer representation directly */ + addbyte(0x8b); /*MOV ECX, [ST_i64+EBX*8]*/ + addbyte(0x0c); + addbyte(0xdd); + addlong((uint32_t)ST_i64+4); + addbyte(0x8b); /*MOV EBX, [ST_i64+EBX*8]*/ + addbyte(0x1c); + addbyte(0xdd); + addlong((uint32_t)ST_i64); + + return; + } + + addbyte(0xf6); /*TEST TAG[EBX], TAG_UINT64*/ + addbyte(0x83); + addlong((uintptr_t)tag); + addbyte(TAG_UINT64); + addbyte(0x74); /*JZ +*/ + addbyte(7+7+2); + + addbyte(0x8b); /*MOV ECX, [ST_i64+EBX*8]*/ + addbyte(0x0c); + addbyte(0xdd); + addlong((uint32_t)ST_i64+4); + addbyte(0x8b); /*MOV EBX, [ST_i64+EBX*8]*/ + addbyte(0x1c); + addbyte(0xdd); + addlong((uint32_t)ST_i64); + + addbyte(0xeb); /*JMP done*/ + addbyte(7+4+3+5+2+2+4); + + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + + addbyte(0x89); /*MOV [ESP+8], EAX*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x08); + + addbyte(0xdd); /*FSTP [ESP]*/ + addbyte(0x1c); + addbyte(0x24); + + CALL_FUNC(x87_fround64); + + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + + addbyte(0x89); /*MOV ECX, EDX*/ + addbyte(0xd1); + + addbyte(0x8b); /*MOV EAX, [ESP+8]*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x08); + + *host_reg1 = REG_EBX; + *host_reg2 = REG_ECX; +} + +static void FP_POP() +{ + addbyte(0xa1); /*MOV EAX, TOP*/ + addlong((uintptr_t)&TOP); + addbyte(0xc6); /*MOVB tag[EAX], 3*/ + addbyte(0x80); + addlong((uintptr_t)tag); + addbyte(3); + addbyte(0x04); /*ADD AL, 1*/ + addbyte(1); + addbyte(0x24); /*AND AL, 7*/ + addbyte(7); + addbyte(0xa2); /*MOV TOP, AL*/ + addlong((uintptr_t)&TOP); +} + +#define FPU_ADD 0x00 +#define FPU_DIV 0x30 +#define FPU_DIVR 0x38 +#define FPU_MUL 0x08 +#define FPU_SUB 0x20 +#define FPU_SUBR 0x28 + +static void FP_OP_S(int op) +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x80); /*AND tag[EBX], ~TAG_UINT64*/ + addbyte(0xa3); + addlong((uintptr_t)tag); + addbyte(~TAG_UINT64); + addbyte(0xd8); /*FADD [ESP]*/ + addbyte(0x04 | op); + addbyte(0x24); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x1c); + addbyte(0xdd); + addlong((uintptr_t)ST); +} +static void FP_OP_D(int op) +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + if (((npxc >> 10) & 3) && op == FPU_ADD) + { + addbyte(0x9b); /*FSTCW [ESP+8]*/ + addbyte(0xd9); + addbyte(0x7c); + addbyte(0x24); + addbyte(0x08); + addbyte(0x66); /*MOV AX, [ESP+8]*/ + addbyte(0x8b); + addbyte(0x44); + addbyte(0x24); + addbyte(0x08); + addbyte(0x66); /*AND AX, ~(3 << 10)*/ + addbyte(0x25); + addword(~(3 << 10)); + addbyte(0x66); /*OR AX, npxc & (3 << 10)*/ + addbyte(0x0d); + addword(npxc & (3 << 10)); + addbyte(0x66); /*MOV [ESP+12], AX*/ + addbyte(0x89); + addbyte(0x44); + addbyte(0x24); + addbyte(0x0c); + addbyte(0xd9); /*FLDCW [ESP+12]*/ + addbyte(0x6c); + addbyte(0x24); + addbyte(0x0c); + } + addbyte(0x89); /*MOV [ESP+4], EDX*/ + addbyte(0x54); + addbyte(0x24); + addbyte(0x04); + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x80); /*AND tag[EBX], ~TAG_UINT64*/ + addbyte(0xa3); + addlong((uintptr_t)tag); + addbyte(~TAG_UINT64); + addbyte(0xdc); /*FADD [ESP]*/ + addbyte(0x04 | op); + addbyte(0x24); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x1c); + addbyte(0xdd); + addlong((uintptr_t)ST); + if (((npxc >> 10) & 3) && op == FPU_ADD) + { + addbyte(0xd9); /*FLDCW [ESP+8]*/ + addbyte(0x6c); + addbyte(0x24); + addbyte(0x08); + } +} +static void FP_OP_IW(int op) +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x80); /*AND tag[EBX], ~TAG_UINT64*/ + addbyte(0xa3); + addlong((uintptr_t)tag); + addbyte(~TAG_UINT64); + addbyte(0xde); /*FADD [ESP]*/ + addbyte(0x04 | op); + addbyte(0x24); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x1c); + addbyte(0xdd); + addlong((uintptr_t)ST); +} +static void FP_OP_IL(int op) +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x80); /*AND tag[EBX], ~TAG_UINT64*/ + addbyte(0xa3); + addlong((uintptr_t)tag); + addbyte(~TAG_UINT64); + addbyte(0xda); /*FADD [ESP]*/ + addbyte(0x04 | op); + addbyte(0x24); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x1c); + addbyte(0xdd); + addlong((uintptr_t)ST); +} +static void FP_OP_IQ(int op) +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x89); /*MOV [ESP+4], EDX*/ + addbyte(0x54); + addbyte(0x24); + addbyte(0x04); + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x80); /*AND tag[EBX], ~TAG_UINT64*/ + addbyte(0xa3); + addlong((uintptr_t)tag); + addbyte(~TAG_UINT64); + addbyte(0xdc); /*FADD [ESP]*/ + addbyte(0x04 | op); + addbyte(0x24); + addbyte(0xdd); /*FSTP [ST+EBX*8]*/ + addbyte(0x1c); + addbyte(0xdd); + addlong((uintptr_t)ST); +} + +#define C0 (1<<8) +#define C1 (1<<9) +#define C2 (1<<10) +#define C3 (1<<14) + +static void FP_COMPARE_S() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x8a); /*MOV BL, [npxs+1]*/ + addbyte(0x1d); + addlong(((uintptr_t)&npxs) + 1); + addbyte(0xdb); /*FCLEX*/ + addbyte(0xe2); + addbyte(0x80); /*AND BL, ~(C0|C2|C3)*/ + addbyte(0xe3); + addbyte((~(C0|C2|C3)) >> 8); + addbyte(0xd8); /*FCOMP [ESP]*/ + addbyte(0x04 | 0x18); + addbyte(0x24); + addbyte(0xdf); /*FSTSW AX*/ + addbyte(0xe0); + addbyte(0x80); /*AND AH, (C0|C2|C3)*/ + addbyte(0xe4); + addbyte((C0|C2|C3) >> 8); + addbyte(0x08); /*OR BL, AH*/ + addbyte(0xe3); + addbyte(0x88); /*MOV [npxs+1], BL*/ + addbyte(0x1d); + addlong(((uintptr_t)&npxs) + 1); +} +static void FP_COMPARE_D() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0x89); /*MOV [ESP+4], EDX*/ + addbyte(0x54); + addbyte(0x24); + addbyte(0x04); + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x8a); /*MOV BL, [npxs+1]*/ + addbyte(0x1d); + addlong(((uintptr_t)&npxs) + 1); + addbyte(0xdb); /*FCLEX*/ + addbyte(0xe2); + addbyte(0x80); /*AND BL, ~(C0|C2|C3)*/ + addbyte(0xe3); + addbyte((~(C0|C2|C3)) >> 8); + addbyte(0xdc); /*FCOMP [ESP]*/ + addbyte(0x04 | 0x18); + addbyte(0x24); + addbyte(0xdf); /*FSTSW AX*/ + addbyte(0xe0); + addbyte(0x80); /*AND AH, (C0|C2|C3)*/ + addbyte(0xe4); + addbyte((C0|C2|C3) >> 8); + addbyte(0x08); /*OR BL, AH*/ + addbyte(0xe3); + addbyte(0x88); /*MOV [npxs+1], BL*/ + addbyte(0x1d); + addlong(((uintptr_t)&npxs) + 1); +} +static void FP_COMPARE_IW() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x8a); /*MOV BL, [npxs+1]*/ + addbyte(0x1d); + addlong(((uintptr_t)&npxs) + 1); + addbyte(0xdb); /*FCLEX*/ + addbyte(0xe2); + addbyte(0x80); /*AND BL, ~(C0|C2|C3)*/ + addbyte(0xe3); + addbyte((~(C0|C2|C3)) >> 8); + addbyte(0xde); /*FCOMP [ESP]*/ + addbyte(0x04 | 0x18); + addbyte(0x24); + addbyte(0xdf); /*FSTSW AX*/ + addbyte(0xe0); + addbyte(0x80); /*AND AH, (C0|C2|C3)*/ + addbyte(0xe4); + addbyte((C0|C2|C3) >> 8); + addbyte(0x08); /*OR BL, AH*/ + addbyte(0xe3); + addbyte(0x88); /*MOV [npxs+1], BL*/ + addbyte(0x1d); + addlong(((uintptr_t)&npxs) + 1); +} +static void FP_COMPARE_IL() +{ + addbyte(0x8b); /*MOV EBX, TOP*/ + addbyte(0x1d); + addlong((uintptr_t)&TOP); + addbyte(0x89); /*MOV [ESP], EAX*/ + addbyte(0x04); + addbyte(0x24); + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x04); + addbyte(0xdd); + addlong((uintptr_t)ST); + addbyte(0x8a); /*MOV BL, [npxs+1]*/ + addbyte(0x1d); + addlong(((uintptr_t)&npxs) + 1); + addbyte(0xdb); /*FCLEX*/ + addbyte(0xe2); + addbyte(0x80); /*AND BL, ~(C0|C2|C3)*/ + addbyte(0xe3); + addbyte((~(C0|C2|C3)) >> 8); + addbyte(0xda); /*FCOMP [ESP]*/ + addbyte(0x04 | 0x18); + addbyte(0x24); + addbyte(0xdf); /*FSTSW AX*/ + addbyte(0xe0); + addbyte(0x80); /*AND AH, (C0|C2|C3)*/ + addbyte(0xe4); + addbyte((C0|C2|C3) >> 8); + addbyte(0x08); /*OR BL, AH*/ + addbyte(0xe3); + addbyte(0x88); /*MOV [npxs+1], BL*/ + addbyte(0x1d); + addlong(((uintptr_t)&npxs) + 1); +} + +static void FP_OP_REG(int op, int dst, int src) +{ + addbyte(0xa1); /*MOV EAX, TOP*/ + addlong((uintptr_t)&TOP); + addbyte(0xbe); /*MOVL ESI, ST*/ + addlong((uintptr_t)ST); + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + if (src || dst) + { + addbyte(0x83); /*ADD EAX, 1*/ + addbyte(0xc0); + addbyte(src ? src : dst); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(7); + } + + if (src) + { + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x04); + addbyte(0xde); + addbyte(0x80); /*AND tag[EBX], ~TAG_UINT64*/ + addbyte(0xa3); + addlong((uintptr_t)tag); + addbyte(~TAG_UINT64); + addbyte(0xdc); /*FADD ST[EAX*8]*/ + addbyte(0x04 | op); + addbyte(0xc6); + addbyte(0xdd); /*FSTP ST[EBX*8]*/ + addbyte(0x1c); + addbyte(0xde); + } + else + { + addbyte(0xdd); /*FLD [ESI+EAX*8]*/ + addbyte(0x04); + addbyte(0xc6); + addbyte(0x80); /*AND tag[EAX], ~TAG_UINT64*/ + addbyte(0xa0); + addlong((uintptr_t)tag); + addbyte(~TAG_UINT64); + addbyte(0xdc); /*FADD ST[EBX*8]*/ + addbyte(0x04 | op); + addbyte(0xde); + addbyte(0xdd); /*FSTP ST[EAX*8]*/ + addbyte(0x1c); + addbyte(0xc6); + } +} + +static void FP_COMPARE_REG(int dst, int src) +{ + addbyte(0xa1); /*MOV EAX, TOP*/ + addlong((uintptr_t)&TOP); + addbyte(0xbe); /*MOVL ESI, ST*/ + addlong((uintptr_t)ST); + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + if (src || dst) + { + addbyte(0x83); /*ADD EAX, 1*/ + addbyte(0xc0); + addbyte(src ? src : dst); + addbyte(0x83); /*AND EAX, 7*/ + addbyte(0xe0); + addbyte(7); + } + + addbyte(0x8a); /*MOV CL, [npxs+1]*/ + addbyte(0x0d); + addlong(((uintptr_t)&npxs) + 1); + addbyte(0xdb); /*FCLEX*/ + addbyte(0xe2); + addbyte(0x80); /*AND CL, ~(C0|C2|C3)*/ + addbyte(0xe1); + addbyte((~(C0|C2|C3)) >> 8); + + if (src) + { + addbyte(0xdd); /*FLD ST[EBX*8]*/ + addbyte(0x04); + addbyte(0xde); + addbyte(0xdc); /*FCOMP ST[EAX*8]*/ + addbyte(0x04 | 0x18); + addbyte(0xc6); + } + else + { + addbyte(0xdd); /*FLD [ESI+EAX*8]*/ + addbyte(0x04); + addbyte(0xc6); + addbyte(0xdc); /*FCOMP ST[EBX*8]*/ + addbyte(0x04 | 0x18); + addbyte(0xde); + } + + addbyte(0xdf); /*FSTSW AX*/ + addbyte(0xe0); + addbyte(0x80); /*AND AH, (C0|C2|C3)*/ + addbyte(0xe4); + addbyte((C0|C2|C3) >> 8); + addbyte(0x08); /*OR CL, AH*/ + addbyte(0xe1); + addbyte(0x88); /*MOV [npxs+1], CL*/ + addbyte(0x0d); + addlong(((uintptr_t)&npxs) + 1); +} + +static int ZERO_EXTEND_W_B(int reg) +{ + addbyte(0x0f); /*MOVZX regl, regb*/ + addbyte(0xb6); + addbyte(0xc0 | reg | (reg << 3)); + return reg; +} +static int ZERO_EXTEND_L_B(int reg) +{ + addbyte(0x0f); /*MOVZX regl, regb*/ + addbyte(0xb6); + addbyte(0xc0 | reg | (reg << 3)); + return reg; +} +static int ZERO_EXTEND_L_W(int reg) +{ + addbyte(0x0f); /*MOVZX regl, regw*/ + addbyte(0xb7); + addbyte(0xc0 | reg | (reg << 3)); + return reg; +} + +static int SIGN_EXTEND_W_B(int reg) +{ + addbyte(0x0f); /*MOVSX regl, regb*/ + addbyte(0xbe); + addbyte(0xc0 | reg | (reg << 3)); + return reg; +} +static int SIGN_EXTEND_L_B(int reg) +{ + addbyte(0x0f); /*MOVSX regl, regb*/ + addbyte(0xbe); + addbyte(0xc0 | reg | (reg << 3)); + return reg; +} +static int SIGN_EXTEND_L_W(int reg) +{ + addbyte(0x0f); /*MOVSX regl, regw*/ + addbyte(0xbf); + addbyte(0xc0 | reg | (reg << 3)); + return reg; +} + +static int COPY_REG(int src_reg) +{ + return src_reg; +} + +static void SET_BITS(uintptr_t addr, uint32_t val) +{ + if (val & ~0xff) + { + addbyte(0x81); + addbyte(0x0d); + addlong(addr); + addlong(val); + } + else + { + addbyte(0x80); + addbyte(0x0d); + addlong(addr); + addbyte(val); + } +} +static void CLEAR_BITS(uintptr_t addr, uint32_t val) +{ + if (val & ~0xff) + { + addbyte(0x81); + addbyte(0x25); + addlong(addr); + addlong(~val); + } + else + { + addbyte(0x80); + addbyte(0x25); + addlong(addr); + addbyte(~val); + } +} + +#define LOAD_Q_REG_1 REG_EAX +#define LOAD_Q_REG_2 REG_EDX + +static void MMX_ENTER() +{ + if (codegen_mmx_entered) + return; + + addbyte(0xf6); /*TEST cr0, 0xc*/ + addbyte(0x05); + addlong((uintptr_t)&cr0); + addbyte(0xc); + addbyte(0x74); /*JZ +*/ + addbyte(10+7+5+5); + addbyte(0xC7); /*MOVL [oldpc],op_old_pc*/ + addbyte(0x05); + addlong((uintptr_t)&oldpc); + addlong(op_old_pc); + addbyte(0xc7); /*MOV [ESP], 7*/ + addbyte(0x04); + addbyte(0x24); + addlong(7); + addbyte(0xe8); /*CALL x86_int*/ + addlong((uint32_t)x86_int - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + addbyte(0xe9); /*JMP end*/ + addlong(BLOCK_EXIT_OFFSET - (block_pos + 4)); + + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + addbyte(0xc7); /*MOV ISMMX, 1*/ + addbyte(0x05); + addlong((uint32_t)&ismmx); + addlong(1); + addbyte(0xa3); /*MOV TOP, EAX*/ + addlong((uint32_t)&TOP); + addbyte(0xa3); /*MOV tag, EAX*/ + addlong((uint32_t)&tag[0]); + addbyte(0xa3); /*MOV tag+4, EAX*/ + addlong((uint32_t)&tag[4]); + + codegen_mmx_entered = 1; +} + +extern int mmx_ebx_ecx_loaded; + +static int LOAD_MMX_D(int guest_reg) +{ + int host_reg = find_host_reg(); + host_reg_mapping[host_reg] = 100; + + addbyte(0x8b); /*MOV EBX, reg*/ + addbyte(0x05 | (host_reg << 3)); + addlong((uint32_t)&MM[guest_reg].l[0]); + + return host_reg; +} +static int LOAD_MMX_Q(int guest_reg, int *host_reg1, int *host_reg2) +{ + if (!mmx_ebx_ecx_loaded) + { + *host_reg1 = REG_EBX; + *host_reg2 = REG_ECX; + mmx_ebx_ecx_loaded = 1; + } + else + { + *host_reg1 = REG_EAX; + *host_reg2 = REG_EDX; + } + + addbyte(0x8b); /*MOV EBX, reg*/ + addbyte(0x05 | ((*host_reg1) << 3)); + addlong((uint32_t)&MM[guest_reg].l[0]); + addbyte(0x8b); /*MOV ECX, reg+4*/ + addbyte(0x05 | ((*host_reg2) << 3)); + addlong((uint32_t)&MM[guest_reg].l[1]); +} +static int LOAD_MMX_Q_MMX(int guest_reg) +{ + int dst_reg = find_host_xmm_reg(); + host_reg_xmm_mapping[dst_reg] = guest_reg; + + addbyte(0xf3); /*MOVQ dst_reg,[reg]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x05 | (dst_reg << 3)); + addlong((uint32_t)&MM[guest_reg].q); + + return dst_reg; +} + +static int LOAD_INT_TO_MMX(int src_reg1, int src_reg2) +{ + int dst_reg = find_host_xmm_reg(); + host_reg_xmm_mapping[dst_reg] = 100; + + addbyte(0x66); /*MOVD dst_reg, src_reg1*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0 | (dst_reg << 3) | src_reg1); + addbyte(0x66); /*MOVD XMM7, src_reg2*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0 | (7 << 3) | src_reg2); + addbyte(0x66); /*PUNPCKLDQ dst_reg, XMM7*/ + addbyte(0x0f); + addbyte(0x62); + addbyte(0xc0 | 7 | (dst_reg << 3)); + + return dst_reg; +} + +static void STORE_MMX_LQ(int guest_reg, int host_reg1) +{ + addbyte(0xC7); /*MOVL [reg],0*/ + addbyte(0x05); + addlong((uint32_t)&MM[guest_reg].l[1]); + addlong(0); + addbyte(0x89); /*MOVL [reg],host_reg*/ + addbyte(0x05 | (host_reg1 << 3)); + addlong((uint32_t)&MM[guest_reg].l[0]); +} +static void STORE_MMX_Q(int guest_reg, int host_reg1, int host_reg2) +{ + addbyte(0x89); /*MOVL [reg],host_reg*/ + addbyte(0x05 | (host_reg1 << 3)); + addlong((uint32_t)&MM[guest_reg].l[0]); + addbyte(0x89); /*MOVL [reg],host_reg*/ + addbyte(0x05 | (host_reg2 << 3)); + addlong((uint32_t)&MM[guest_reg].l[1]); +} +static void STORE_MMX_Q_MMX(int guest_reg, int host_reg) +{ + addbyte(0x66); /*MOVQ [guest_reg],host_reg*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x05 | (host_reg << 3)); + addlong((uint32_t)&MM[guest_reg].q); +} + +#define MMX_x86_OP(name, opcode) \ +static void MMX_ ## name(int dst_reg, int src_reg) \ +{ \ + addbyte(0x66); /*op dst_reg, src_reg*/ \ + addbyte(0x0f); \ + addbyte(opcode); \ + addbyte(0xc0 | (dst_reg << 3) | src_reg); \ +} + +MMX_x86_OP(AND, 0xdb) +MMX_x86_OP(ANDN, 0xdf) +MMX_x86_OP(OR, 0xeb) +MMX_x86_OP(XOR, 0xef) + +MMX_x86_OP(ADDB, 0xfc) +MMX_x86_OP(ADDW, 0xfd) +MMX_x86_OP(ADDD, 0xfe) +MMX_x86_OP(ADDSB, 0xec) +MMX_x86_OP(ADDSW, 0xed) +MMX_x86_OP(ADDUSB, 0xdc) +MMX_x86_OP(ADDUSW, 0xdd) + +MMX_x86_OP(SUBB, 0xf8) +MMX_x86_OP(SUBW, 0xf9) +MMX_x86_OP(SUBD, 0xfa) +MMX_x86_OP(SUBSB, 0xe8) +MMX_x86_OP(SUBSW, 0xe9) +MMX_x86_OP(SUBUSB, 0xd8) +MMX_x86_OP(SUBUSW, 0xd9) + +MMX_x86_OP(PUNPCKLBW, 0x60); +MMX_x86_OP(PUNPCKLWD, 0x61); +MMX_x86_OP(PUNPCKLDQ, 0x62); +MMX_x86_OP(PCMPGTB, 0x64); +MMX_x86_OP(PCMPGTW, 0x65); +MMX_x86_OP(PCMPGTD, 0x66); + +MMX_x86_OP(PCMPEQB, 0x74); +MMX_x86_OP(PCMPEQW, 0x75); +MMX_x86_OP(PCMPEQD, 0x76); + +MMX_x86_OP(PSRLW, 0xd1); +MMX_x86_OP(PSRLD, 0xd2); +MMX_x86_OP(PSRLQ, 0xd3); +MMX_x86_OP(PSRAW, 0xe1); +MMX_x86_OP(PSRAD, 0xe2); +MMX_x86_OP(PSLLW, 0xf1); +MMX_x86_OP(PSLLD, 0xf2); +MMX_x86_OP(PSLLQ, 0xf3); + +MMX_x86_OP(PMULLW, 0xd5); +MMX_x86_OP(PMULHW, 0xe5); +MMX_x86_OP(PMADDWD, 0xf5); + +static void MMX_PACKSSWB(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PACKSSWB dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x63); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x08); +} +static void MMX_PACKUSWB(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PACKUSWB dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x08); +} +static void MMX_PACKSSDW(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PACKSSDW dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x08); +} +static void MMX_PUNPCKHBW(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PUNPCKLBW dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x0e); +} +static void MMX_PUNPCKHWD(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PUNPCKLWD dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x61); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x0e); +} +static void MMX_PUNPCKHDQ(int dst_reg, int src_reg) +{ + addbyte(0x66); /*PUNPCKLDQ dst_reg, src_reg*/ + addbyte(0x0f); + addbyte(0x62); + addbyte(0xc0 | (dst_reg << 3) | src_reg); + addbyte(0x66); /*PSHUFD dst_reg, dst_reg*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xc0 | (dst_reg << 3) | dst_reg); + addbyte(0x0e); +} + +static void MMX_PSRLW_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRLW dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xc0 | dst_reg | 0x10); + addbyte(amount); +} +static void MMX_PSRAW_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRAW dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xc0 | dst_reg | 0x20); + addbyte(amount); +} +static void MMX_PSLLW_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSLLW dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xc0 | dst_reg | 0x30); + addbyte(amount); +} + +static void MMX_PSRLD_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRLD dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xc0 | dst_reg | 0x10); + addbyte(amount); +} +static void MMX_PSRAD_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRAD dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xc0 | dst_reg | 0x20); + addbyte(amount); +} +static void MMX_PSLLD_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSLLD dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xc0 | dst_reg | 0x30); + addbyte(amount); +} + +static void MMX_PSRLQ_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRLQ dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x73); + addbyte(0xc0 | dst_reg | 0x10); + addbyte(amount); +} +static void MMX_PSRAQ_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSRAQ dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x73); + addbyte(0xc0 | dst_reg | 0x20); + addbyte(amount); +} +static void MMX_PSLLQ_imm(int dst_reg, int amount) +{ + addbyte(0x66); /*PSLLQ dst_reg, amount*/ + addbyte(0x0f); + addbyte(0x73); + addbyte(0xc0 | dst_reg | 0x30); + addbyte(amount); +} diff --git a/src/codegen_ops_xchg.h b/src/codegen_ops_xchg.h new file mode 100644 index 000000000..b95e82f71 --- /dev/null +++ b/src/codegen_ops_xchg.h @@ -0,0 +1,93 @@ +#define OP_XCHG_AX_(reg) \ + static uint32_t ropXCHG_AX_ ## reg(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int ax_reg, host_reg, temp_reg; \ + \ + ax_reg = LOAD_REG_W(REG_AX); \ + host_reg = LOAD_REG_W(REG_ ## reg); \ + temp_reg = COPY_REG(host_reg); \ + STORE_REG_TARGET_W_RELEASE(ax_reg, REG_ ## reg); \ + STORE_REG_TARGET_W_RELEASE(temp_reg, REG_AX); \ + \ + return op_pc; \ + } + +OP_XCHG_AX_(BX) +OP_XCHG_AX_(CX) +OP_XCHG_AX_(DX) +OP_XCHG_AX_(SI) +OP_XCHG_AX_(DI) +OP_XCHG_AX_(SP) +OP_XCHG_AX_(BP) + +#define OP_XCHG_EAX_(reg) \ + static uint32_t ropXCHG_EAX_ ## reg(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) \ + { \ + int eax_reg, host_reg, temp_reg; \ + \ + eax_reg = LOAD_REG_L(REG_EAX); \ + host_reg = LOAD_REG_L(REG_ ## reg); \ + temp_reg = COPY_REG(host_reg); \ + STORE_REG_TARGET_L_RELEASE(eax_reg, REG_ ## reg); \ + STORE_REG_TARGET_L_RELEASE(temp_reg, REG_EAX); \ + \ + return op_pc; \ + } + +OP_XCHG_EAX_(EBX) +OP_XCHG_EAX_(ECX) +OP_XCHG_EAX_(EDX) +OP_XCHG_EAX_(ESI) +OP_XCHG_EAX_(EDI) +OP_XCHG_EAX_(ESP) +OP_XCHG_EAX_(EBP) + +static uint32_t ropXCHG_b(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ +// #ifdef __amd64__ +// return 0; +// #else + int src_reg, dst_reg, temp_reg; + + if ((fetchdat & 0xc0) != 0xc0) + return 0; + + dst_reg = LOAD_REG_B(fetchdat & 7); + src_reg = LOAD_REG_B((fetchdat >> 3) & 7); + temp_reg = COPY_REG(src_reg); + STORE_REG_TARGET_B_RELEASE(dst_reg, (fetchdat >> 3) & 7); + STORE_REG_TARGET_B_RELEASE(temp_reg, fetchdat & 7); + + return op_pc + 1; +// #endif +} +static uint32_t ropXCHG_w(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg, temp_reg; + + if ((fetchdat & 0xc0) != 0xc0) + return 0; + + dst_reg = LOAD_REG_W(fetchdat & 7); + src_reg = LOAD_REG_W((fetchdat >> 3) & 7); + temp_reg = COPY_REG(src_reg); + STORE_REG_TARGET_W_RELEASE(dst_reg, (fetchdat >> 3) & 7); + STORE_REG_TARGET_W_RELEASE(temp_reg, fetchdat & 7); + + return op_pc + 1; +} +static uint32_t ropXCHG_l(uint8_t opcode, uint32_t fetchdat, uint32_t op_32, uint32_t op_pc, codeblock_t *block) +{ + int src_reg, dst_reg, temp_reg; + + if ((fetchdat & 0xc0) != 0xc0) + return 0; + + dst_reg = LOAD_REG_L(fetchdat & 7); + src_reg = LOAD_REG_L((fetchdat >> 3) & 7); + temp_reg = COPY_REG(src_reg); + STORE_REG_TARGET_L_RELEASE(dst_reg, (fetchdat >> 3) & 7); + STORE_REG_TARGET_L_RELEASE(temp_reg, fetchdat & 7); + + return op_pc + 1; +} diff --git a/src/codegen_timing_486.c b/src/codegen_timing_486.c new file mode 100644 index 000000000..0cd8c25b7 --- /dev/null +++ b/src/codegen_timing_486.c @@ -0,0 +1,375 @@ +#include "ibm.h" +#include "cpu.h" +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "mem.h" +#include "codegen.h" + +#define CYCLES(c) (int *)c +#define CYCLES2(c16, c32) (int *)((-1 & ~0xffff) | c16 | (c32 << 8)) + +static int *opcode_timings[256] = +{ +/*00*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), NULL, +/*10*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), +/*20*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), +/*30*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), + +/*40*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, +/*50*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*60*/ CYCLES(11), CYCLES(9), CYCLES(7), CYCLES(9), CYCLES(4), CYCLES(4), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES2(17,25), CYCLES(1), CYCLES2(17,20), CYCLES(17), CYCLES(17), CYCLES(17), CYCLES(17), +/*70*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, + +/*80*/ &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm, &timing_rm, CYCLES(5), CYCLES(5), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(3), CYCLES(1), CYCLES(5), CYCLES(6), +/*90*/ CYCLES(1), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(0), CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(2), CYCLES(3), +/*a0*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(7), CYCLES(7), CYCLES(8), CYCLES(8), CYCLES(1), CYCLES(1), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), +/*b0*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, + +/*c0*/ CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(1), CYCLES(1), CYCLES(14), CYCLES(5), CYCLES(0), CYCLES(0), &timing_int, &timing_int, CYCLES(3), CYCLES(0), +/*d0*/ CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(15), CYCLES(14), CYCLES(2), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(5), CYCLES(14), CYCLES(14), CYCLES(16), CYCLES(16), CYCLES(3), CYCLES(3), CYCLES(17), CYCLES(3), CYCLES(14), CYCLES(14), CYCLES(14), CYCLES(14), +/*f0*/ CYCLES(4), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(4), CYCLES(2), NULL, NULL, CYCLES(2), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(3), NULL +}; + +static int *opcode_timings_mod3[256] = +{ +/*00*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), NULL, +/*10*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), +/*20*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), +/*30*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), + +/*40*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, +/*50*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*60*/ CYCLES(11), CYCLES(9), CYCLES(7), CYCLES(9), CYCLES(4), CYCLES(4), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES2(14,25), CYCLES(1), CYCLES2(17,20), CYCLES(17), CYCLES(17), CYCLES(17), CYCLES(17), +/*70*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, + +/*80*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(5), CYCLES(5), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(1), CYCLES(2), CYCLES(1), +/*90*/ CYCLES(1), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(0), CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(2), CYCLES(3), +/*a0*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(7), CYCLES(7), CYCLES(8), CYCLES(8), CYCLES(1), CYCLES(1), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), +/*b0*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, + +/*c0*/ CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(1), CYCLES(1), CYCLES(14), CYCLES(5), CYCLES(0), CYCLES(0), &timing_int, &timing_int, CYCLES(3), CYCLES(0), +/*d0*/ CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(15), CYCLES(14), CYCLES(2), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(5), CYCLES(14), CYCLES(14), CYCLES(16), CYCLES(16), CYCLES(3), CYCLES(3), CYCLES(17), CYCLES(3), CYCLES(14), CYCLES(14), CYCLES(14), CYCLES(14), +/*f0*/ CYCLES(4), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(4), CYCLES(2), NULL, NULL, CYCLES(2), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(3), NULL +}; + +static int *opcode_timings_0f[256] = +{ +/*00*/ CYCLES(20), CYCLES(11), CYCLES(11), CYCLES(10), NULL, CYCLES(195), CYCLES(7), NULL, CYCLES(1000), CYCLES(10000), NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ CYCLES(9), CYCLES(1), CYCLES(9), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, +/*70*/ NULL, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, CYCLES(100), NULL, NULL, NULL, NULL, NULL, NULL, &timing_rm, &timing_rm, + +/*80*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, +/*90*/ CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), +/*a0*/ CYCLES(3), CYCLES(3), CYCLES(14), CYCLES(8), CYCLES(3), CYCLES(4), NULL, NULL, CYCLES(3), CYCLES(3), NULL, CYCLES(13), CYCLES(3), CYCLES(3), NULL, CYCLES2(18,30), +/*b0*/ CYCLES(10), CYCLES(10), CYCLES(6), CYCLES(13), CYCLES(6), CYCLES(6), CYCLES(3), CYCLES(3), NULL, NULL, CYCLES(6), CYCLES(13), CYCLES(7), CYCLES(7), CYCLES(3), CYCLES(3), + +/*c0*/ CYCLES(4), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*d0*/ NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, +/*e0*/ NULL, &timing_rm, &timing_rm, NULL, NULL, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, +/*f0*/ NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, +}; +static int *opcode_timings_0f_mod3[256] = +{ +/*00*/ CYCLES(20), CYCLES(11), CYCLES(11), CYCLES(10), NULL, CYCLES(195), CYCLES(7), NULL, CYCLES(1000), CYCLES(10000), NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ CYCLES(9), CYCLES(1), CYCLES(9), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, +/*70*/ NULL, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(100), NULL, NULL, NULL, NULL, NULL, NULL, &timing_rr, &timing_rr, + +/*80*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, +/*90*/ CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), +/*a0*/ CYCLES(3), CYCLES(3), CYCLES(14), CYCLES(8), CYCLES(3), CYCLES(4), NULL, NULL, CYCLES(3), CYCLES(3), NULL, CYCLES(13), CYCLES(3), CYCLES(3), NULL, CYCLES2(18,30), +/*b0*/ CYCLES(10), CYCLES(10), CYCLES(6), CYCLES(13), CYCLES(6), CYCLES(6), CYCLES(3), CYCLES(3), NULL, NULL, CYCLES(6), CYCLES(13), CYCLES(7), CYCLES(7), CYCLES(3), CYCLES(3), + +/*c0*/ CYCLES(4), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*d0*/ NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, +/*e0*/ NULL, &timing_rr, &timing_rr, NULL, NULL, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, +/*f0*/ NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, +}; + +static int *opcode_timings_shift[8] = +{ + CYCLES(7), CYCLES(7), CYCLES(10), CYCLES(10), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(7) +}; +static int *opcode_timings_shift_mod3[8] = +{ + CYCLES(3), CYCLES(3), CYCLES(9), CYCLES(9), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3) +}; + +static int *opcode_timings_f6[8] = +{ + &timing_rm, NULL, &timing_mm, &timing_mm, CYCLES(13), CYCLES(14), CYCLES(16), CYCLES(19) +}; +static int *opcode_timings_f6_mod3[8] = +{ + &timing_rr, NULL, &timing_rr, &timing_rr, CYCLES(13), CYCLES(14), CYCLES(16), CYCLES(19) +}; +static int *opcode_timings_f7[8] = +{ + &timing_rm, NULL, &timing_mm, &timing_mm, CYCLES(21), CYCLES2(22,38), CYCLES2(24,40), CYCLES2(27,43) +}; +static int *opcode_timings_f7_mod3[8] = +{ + &timing_rr, NULL, &timing_rr, &timing_rr, CYCLES(21), CYCLES2(22,38), CYCLES2(24,40), CYCLES2(27,43) +}; +static int *opcode_timings_ff[8] = +{ + &timing_mm, &timing_mm, CYCLES(5), CYCLES(0), CYCLES(5), CYCLES(0), CYCLES(5), NULL +}; +static int *opcode_timings_ff_mod3[8] = +{ + &timing_rr, &timing_rr, CYCLES(5), CYCLES(0), CYCLES(5), CYCLES(0), CYCLES(5), NULL +}; + +static int *opcode_timings_d8[8] = +{ +/* FADDil FMULil FCOMil FCOMPil FSUBil FSUBRil FDIVil FDIVRil*/ + CYCLES(8), CYCLES(11), CYCLES(4), CYCLES(4), CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; +static int *opcode_timings_d8_mod3[8] = +{ +/* FADD FMUL FCOM FCOMP FSUB FSUBR FDIV FDIVR*/ + CYCLES(8), CYCLES(16), CYCLES(4), CYCLES(4), CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; + +static int *opcode_timings_d9[8] = +{ +/* FLDs FSTs FSTPs FLDENV FLDCW FSTENV FSTCW*/ + CYCLES(3), NULL, CYCLES(7), CYCLES(7), CYCLES(34), CYCLES(4), CYCLES(67), CYCLES(3) +}; +static int *opcode_timings_d9_mod3[64] = +{ + /*FLD*/ + CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), + /*FXCH*/ + CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), + /*FNOP*/ + CYCLES(3), NULL, NULL, NULL, NULL, NULL, NULL, NULL, + /*FSTP*/ + CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), +/* opFCHS opFABS opFTST opFXAM*/ + CYCLES(6), CYCLES(3), NULL, NULL, CYCLES(4), CYCLES(8), NULL, NULL, +/* opFLD1 opFLDL2T opFLDL2E opFLDPI opFLDEG2 opFLDLN2 opFLDZ*/ + CYCLES(4), CYCLES(8), CYCLES(8), CYCLES(8), CYCLES(8), CYCLES(8), CYCLES(4), NULL, +/* opF2XM1 opFYL2X opFPTAN opFPATAN opFDECSTP opFINCSTP,*/ + CYCLES(140), CYCLES(196), CYCLES(200), CYCLES(218), NULL, NULL, CYCLES(3), CYCLES(3), +/* opFPREM opFSQRT opFSINCOS opFRNDINT opFSCALE opFSIN opFCOS*/ + CYCLES(70), NULL, CYCLES(83), CYCLES(292), CYCLES(21), CYCLES(30), CYCLES(257), CYCLES(257) +}; + +static int *opcode_timings_da[8] = +{ +/* FADDil FMULil FCOMil FCOMPil FSUBil FSUBRil FDIVil FDIVRil*/ + CYCLES(8), CYCLES(11), CYCLES(4), CYCLES(4), CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; +static int *opcode_timings_da_mod3[8] = +{ + NULL, NULL, NULL, NULL, NULL, CYCLES(5), NULL, NULL +}; + + +static int *opcode_timings_db[8] = +{ +/* FLDil FSTil FSTPil FLDe FSTPe*/ + CYCLES(9), NULL, CYCLES(28), CYCLES(28), NULL, CYCLES(5), NULL, CYCLES(6) +}; +static int *opcode_timings_db_mod3[64] = +{ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/* opFNOP opFCLEX opFINIT opFNOP opFNOP*/ + NULL, CYCLES(3), CYCLES(7), CYCLES(17), CYCLES(3), CYCLES(3), NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +static int *opcode_timings_dc[8] = +{ +/* opFADDd_a16 opFMULd_a16 opFCOMd_a16 opFCOMPd_a16 opFSUBd_a16 opFSUBRd_a16 opFDIVd_a16 opFDIVRd_a16*/ + CYCLES(8), CYCLES(11), CYCLES(4), CYCLES(4), CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; +static int *opcode_timings_dc_mod3[8] = +{ +/* opFADDr opFMULr opFSUBRr opFSUBr opFDIVRr opFDIVr*/ + CYCLES(8), CYCLES(16), NULL, NULL, CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; + +static int *opcode_timings_dd[8] = +{ +/* FLDd FSTd FSTPd FRSTOR FSAVE FSTSW*/ + CYCLES(3), NULL, CYCLES(8), CYCLES(8), CYCLES(131), NULL, CYCLES(154), CYCLES(3) +}; +static int *opcode_timings_dd_mod3[8] = +{ +/* FFFREE FST FSTP FUCOM FUCOMP*/ + CYCLES(3), NULL, CYCLES(3), CYCLES(3), CYCLES(4), CYCLES(4), NULL, NULL +}; + +static int *opcode_timings_de[8] = +{ +/* FADDiw FMULiw FCOMiw FCOMPiw FSUBil FSUBRil FDIVil FDIVRil*/ + CYCLES(8), CYCLES(11), CYCLES(4), CYCLES(4), CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; +static int *opcode_timings_de_mod3[8] = +{ +/* FADD FMUL FCOMPP FSUB FSUBR FDIV FDIVR*/ + CYCLES(8), CYCLES(16), NULL, CYCLES(5), CYCLES(8), CYCLES(8), CYCLES(73), CYCLES(73) +}; + +static int *opcode_timings_df[8] = +{ +/* FILDiw FISTiw FISTPiw FILDiq FBSTP FISTPiq*/ + CYCLES(13), NULL, CYCLES(29), CYCLES(29), NULL, CYCLES(10), CYCLES(172), CYCLES(28) +}; +static int *opcode_timings_df_mod3[8] = +{ +/* FFREE FST FSTP FUCOM FUCOMP*/ + CYCLES(3), NULL, CYCLES(3), CYCLES(3), CYCLES(4), CYCLES(4), NULL, NULL +}; + +static int *opcode_timings_8x[8] = +{ + &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm +}; + +static int timing_count; +static uint8_t last_prefix; + +static inline int COUNT(int *c, int op_32) +{ + if ((uintptr_t)c <= 10000) + return (int)c; + if (((uintptr_t)c & ~0xffff) == (-1 & ~0xffff)) + { + if (op_32 & 0x100) + return ((uintptr_t)c >> 8) & 0xff; + return (uintptr_t)c & 0xff; + } + return *c; +} + +void codegen_timing_486_block_start() +{ +} + +void codegen_timing_486_start() +{ + timing_count = 0; + last_prefix = 0; +} + +void codegen_timing_486_prefix(uint8_t prefix, uint32_t fetchdat) +{ + timing_count += COUNT(opcode_timings[prefix], 0); + last_prefix = prefix; +} + +void codegen_timing_486_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) +{ + int **timings; + int mod3 = ((fetchdat & 0xc0) == 0xc0); + + switch (last_prefix) + { + case 0x0f: + timings = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; + break; + + case 0xd8: + timings = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; + opcode = (opcode >> 3) & 7; + break; + case 0xd9: + timings = mod3 ? opcode_timings_d9_mod3 : opcode_timings_d9; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; + break; + case 0xda: + timings = mod3 ? opcode_timings_da_mod3 : opcode_timings_da; + opcode = (opcode >> 3) & 7; + break; + case 0xdb: + timings = mod3 ? opcode_timings_db_mod3 : opcode_timings_db; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; + break; + case 0xdc: + timings = mod3 ? opcode_timings_dc_mod3 : opcode_timings_dc; + opcode = (opcode >> 3) & 7; + break; + case 0xdd: + timings = mod3 ? opcode_timings_dd_mod3 : opcode_timings_dd; + opcode = (opcode >> 3) & 7; + break; + case 0xde: + timings = mod3 ? opcode_timings_de_mod3 : opcode_timings_de; + opcode = (opcode >> 3) & 7; + break; + case 0xdf: + timings = mod3 ? opcode_timings_df_mod3 : opcode_timings_df; + opcode = (opcode >> 3) & 7; + break; + + default: + switch (opcode) + { + case 0x80: case 0x81: case 0x82: case 0x83: + timings = mod3 ? opcode_timings_mod3 : opcode_timings_8x; + if (!mod3) + opcode = (fetchdat >> 3) & 7; + break; + + case 0xc0: case 0xc1: case 0xd0: case 0xd1: case 0xd2: case 0xd3: + timings = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xf6: + timings = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; + opcode = (fetchdat >> 3) & 7; + break; + case 0xf7: + timings = mod3 ? opcode_timings_f7_mod3 : opcode_timings_f7; + opcode = (fetchdat >> 3) & 7; + break; + case 0xff: + timings = mod3 ? opcode_timings_ff_mod3 : opcode_timings_ff; + opcode = (fetchdat >> 3) & 7; + break; + + default: + timings = mod3 ? opcode_timings_mod3 : opcode_timings; + break; + } + } + + timing_count += COUNT(timings[opcode], op_32); + codegen_block_cycles += timing_count; +} + +void codegen_timing_486_block_end() +{ +} + +codegen_timing_t codegen_timing_486 = +{ + codegen_timing_486_start, + codegen_timing_486_prefix, + codegen_timing_486_opcode, + codegen_timing_486_block_start, + codegen_timing_486_block_end +}; diff --git a/src/codegen_timing_686.c b/src/codegen_timing_686.c new file mode 100644 index 000000000..5b2b5eda5 --- /dev/null +++ b/src/codegen_timing_686.c @@ -0,0 +1,1052 @@ +/*Elements taken into account : + - X/Y pairing + - FPU/FXCH pairing + - Prefix decode delay + Elements not taken into account : + - Branch prediction (beyond most simplistic approximation) + - FPU queue + - Out of order execution (beyond most simplistic approximation) +*/ + +#include "ibm.h" +#include "cpu.h" +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "mem.h" +#include "codegen.h" + +/*Instruction has different execution time for 16 and 32 bit data. Does not pair */ +#define CYCLES_HAS_MULTI (1 << 31) + +#define CYCLES_MULTI(c16, c32) (CYCLES_HAS_MULTI | c16 | (c32 << 8)) + +/*Instruction lasts given number of cycles. Does not pair*/ +#define CYCLES(c) (c) + +/*Instruction follows either register timing, read-modify, or read-modify-write. + May be pairable*/ +#define CYCLES_REG (1 << 0) +#define CYCLES_RM (1 << 0) +#define CYCLES_RMW (1 << 0) +#define CYCLES_BRANCH (1 << 0) + +#define CYCLES_MASK ((1 << 7) - 1) + +/*Instruction is MMX shift or pack/unpack instruction*/ +#define MMX_SHIFTPACK (1 << 7) +/*Instruction is MMX multiply instruction*/ +#define MMX_MULTIPLY (1 << 8) + +/*Instruction does not pair*/ +#define PAIR_NP (0 << 29) +/*Instruction pairs in X pipe only*/ +#define PAIR_X (1 << 29) +/*Instruction pairs in X pipe only, and can not pair with a following instruction*/ +#define PAIR_X_BRANCH (2 << 29) +/*Instruction pairs in both X and Y pipes*/ +#define PAIR_XY (3 << 29) + +#define PAIR_MASK (3 << 29) + +/*Instruction has input dependency on register in REG field*/ +#define SRCDEP_REG (1 << 9) +/*Instruction has input dependency on register in R/M field*/ +#define SRCDEP_RM (1 << 10) +/*Instruction modifies register in REG field*/ +#define DSTDEP_REG (1 << 11) +/*Instruction modifies register in R/M field*/ +#define DSTDEP_RM (1 << 12) + +/*Instruction has input dependency on given register*/ +#define SRCDEP_EAX (1 << 13) +#define SRCDEP_ECX (1 << 14) +#define SRCDEP_EDX (1 << 15) +#define SRCDEP_EBX (1 << 16) +#define SRCDEP_ESP (1 << 17) +#define SRCDEP_EBP (1 << 18) +#define SRCDEP_ESI (1 << 19) +#define SRCDEP_EDI (1 << 20) + +/*Instruction modifies given register*/ +#define DSTDEP_EAX (1 << 21) +#define DSTDEP_ECX (1 << 22) +#define DSTDEP_EDX (1 << 23) +#define DSTDEP_EBX (1 << 24) +#define DSTDEP_ESP (1 << 25) +#define DSTDEP_EBP (1 << 26) +#define DSTDEP_ESI (1 << 27) +#define DSTDEP_EDI (1 << 28) + +#define INVALID 0 + +static int prev_full; +static uint32_t prev_opcode; +static uint32_t *prev_timings; +static uint32_t prev_op_32; +static uint32_t prev_regmask; + +#define REGMASK_MMX (1 << 8) + +static uint32_t get_srcdep_mask(uint32_t data, uint32_t fetchdat, int bit8) +{ + uint32_t mask = 0; + if (data & SRCDEP_REG) + { + int reg = (fetchdat >> 3) & 7; + if (bit8) + reg &= 3; + mask |= (1 << reg); + } + if (data & SRCDEP_RM) + { + int reg = fetchdat & 7; + if (bit8) + reg &= 3; + mask |= (1 << reg); + } + mask |= ((data >> 16) & 0xff); + if (data & (MMX_SHIFTPACK | MMX_MULTIPLY)) + mask |= REGMASK_MMX; + + return mask; +} + +static uint32_t get_dstdep_mask(uint32_t data, uint32_t fetchdat, int bit8) +{ + uint32_t mask = 0; + if (data & DSTDEP_REG) + { + int reg = (fetchdat >> 3) & 7; + if (bit8) + reg &= 3; + mask |= (1 << reg); + } + if (data & DSTDEP_RM) + { + int reg = fetchdat & 7; + if (bit8) + reg &= 3; + mask |= (1 << reg); + } + mask |= ((data >> 24) & 0xff); + if (data & (MMX_SHIFTPACK | MMX_MULTIPLY)) + mask |= REGMASK_MMX; + + return mask; +} +static uint32_t opcode_timings[256] = +{ +/* ADD ADD ADD ADD*/ +/*00*/ PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, +/* ADD ADD PUSH ES POP ES*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_NP | CYCLES(1) | SRCDEP_ESP | DSTDEP_ESP, PAIR_NP | CYCLES(3), +/* OR OR OR OR*/ + PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, +/* OR OR PUSH CS */ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_NP | CYCLES(1) | SRCDEP_ESP | DSTDEP_ESP, INVALID, + +/* ADC ADC ADC ADC*/ +/*10*/ PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, +/* ADC ADC PUSH SS POP SS*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_NP | CYCLES(1) | SRCDEP_ESP | DSTDEP_ESP, PAIR_NP | CYCLES(3), +/* SBB SBB SBB SBB*/ + PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, +/* SBB SBB PUSH DS POP DS*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_NP | CYCLES(1) | SRCDEP_ESP | DSTDEP_ESP, PAIR_NP | CYCLES(3), + +/* AND AND AND AND*/ +/*20*/ PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, +/* AND AND DAA*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, INVALID, PAIR_NP | CYCLES(7), +/* SUB SUB SUB SUB*/ + PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, +/* SUB SUB DAS*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, INVALID, PAIR_NP | CYCLES(7), + +/* XOR XOR XOR XOR*/ +/*30*/ PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, +/* XOR XOR AAA*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, INVALID, PAIR_NP | CYCLES(7), +/* CMP CMP CMP CMP*/ + PAIR_XY | CYCLES_RM | SRCDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG, +/* CMP CMP AAS*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX, INVALID, PAIR_NP | CYCLES(7), + +/* INC EAX INC ECX INC EDX INC EBX*/ +/*40*/ PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX, PAIR_XY | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX, PAIR_XY | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX, +/* INC ESP INC EBP INC ESI INC EDI*/ + PAIR_XY | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EBP | DSTDEP_EBP, PAIR_XY | CYCLES_REG | SRCDEP_ESI | DSTDEP_ESI, PAIR_XY | CYCLES_REG | SRCDEP_EDI | DSTDEP_EDI, +/* DEC EAX DEC ECX DEC EDX DEC EBX*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX, PAIR_XY | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX, PAIR_XY | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX, +/* DEC ESP DEC EBP DEC ESI DEC EDI*/ + PAIR_XY | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EBP | DSTDEP_EBP, PAIR_XY | CYCLES_REG | SRCDEP_ESI | DSTDEP_ESI, PAIR_XY | CYCLES_REG | SRCDEP_EDI | DSTDEP_EDI, + +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/*50*/ PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX | SRCDEP_ESP | DSTDEP_ESP, +/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ + PAIR_XY | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EBP | DSTDEP_EBP | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_ESI | DSTDEP_ESI | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EDI | DSTDEP_EDI | SRCDEP_ESP | DSTDEP_ESP, +/* POP EAX POP ECX POP EDX POP EBX*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX | SRCDEP_ESP | DSTDEP_ESP, +/* POP ESP POP EBP POP ESI POP EDI*/ + PAIR_XY | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EBP | DSTDEP_EBP | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_ESI | DSTDEP_ESI | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EDI | DSTDEP_EDI | SRCDEP_ESP | DSTDEP_ESP, + +/* PUSHA POPA BOUND ARPL*/ +/*60*/ PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(9), + INVALID, INVALID, INVALID, INVALID, +/* PUSH imm IMUL PUSH imm IMUL*/ + PAIR_XY | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_NP | CYCLES(10), PAIR_XY | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_NP | CYCLES(10), +/* INSB INSW OUTSB OUTSW*/ + PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), + +/* Jxx*/ +/*70*/ PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + +/*80*/ INVALID, INVALID, INVALID, INVALID, +/* TEST TEST XCHG XCHG*/ + PAIR_XY | CYCLES_RM | SRCDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG, PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), +/* MOV MOV MOV MOV*/ + PAIR_XY | CYCLES_REG | SRCDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG, PAIR_XY | CYCLES_REG | DSTDEP_REG, PAIR_XY | CYCLES_REG | DSTDEP_REG, +/* MOV from seg LEA MOV to seg POP*/ + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES_REG | DSTDEP_REG, CYCLES(3), PAIR_XY | CYCLES(1), + +/* NOP XCHG XCHG XCHG*/ +/*90*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), +/* XCHG XCHG XCHG XCHG*/ + PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), +/* CBW CWD CALL far WAIT*/ + PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(2), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), +/* PUSHF POPF SAHF LAHF*/ + PAIR_XY | CYCLES(2) | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES(9) | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(2), + +/* MOV MOV MOV MOV*/ +/*a0*/ PAIR_XY | CYCLES_REG | DSTDEP_EAX, PAIR_XY | CYCLES_REG | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX, +/* MOVSB MOVSW CMPSB CMPSW*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), +/* TEST TEST STOSB STOSW*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX, PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), +/* LODSB LODSW SCASB SCASW*/ + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + +/* MOV*/ +/*b0*/ PAIR_XY | CYCLES_REG | DSTDEP_EAX, PAIR_XY | CYCLES_REG | DSTDEP_ECX, PAIR_XY | CYCLES_REG | DSTDEP_EDX, PAIR_XY | CYCLES_REG | DSTDEP_EBX, + PAIR_XY | CYCLES_REG | DSTDEP_EAX, PAIR_XY | CYCLES_REG | DSTDEP_ECX, PAIR_XY | CYCLES_REG | DSTDEP_EDX, PAIR_XY | CYCLES_REG | DSTDEP_EBX, + PAIR_XY | CYCLES_REG | DSTDEP_EAX, PAIR_XY | CYCLES_REG | DSTDEP_ECX, PAIR_XY | CYCLES_REG | DSTDEP_EDX, PAIR_XY | CYCLES_REG | DSTDEP_EBX, + PAIR_XY | CYCLES_REG | DSTDEP_ESP, PAIR_XY | CYCLES_REG | DSTDEP_EBP, PAIR_XY | CYCLES_REG | DSTDEP_ESI, PAIR_XY | CYCLES_REG | DSTDEP_EDI, + +/* RET imm RET*/ +/*c0*/ INVALID, INVALID, PAIR_X_BRANCH | CYCLES(3), PAIR_X_BRANCH | CYCLES(2), +/* LES LDS MOV MOV*/ + PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* ENTER LEAVE RETF RETF*/ + PAIR_XY | CYCLES(10), PAIR_XY | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), +/* INT3 INT INTO IRET*/ + PAIR_NP | CYCLES(13), PAIR_NP | CYCLES(16), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(10), + + +/*d0*/ INVALID, INVALID, INVALID, INVALID, +/* AAM AAD SETALC XLAT*/ + PAIR_XY | CYCLES(18), PAIR_XY | CYCLES(7), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(4), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, +/* LOOPNE LOOPE LOOP JCXZ*/ +/*e0*/ PAIR_X_BRANCH| CYCLES_BRANCH | SRCDEP_ECX, PAIR_X_BRANCH | CYCLES_BRANCH | SRCDEP_ECX, PAIR_X_BRANCH | CYCLES_BRANCH | SRCDEP_ECX, PAIR_X_BRANCH | CYCLES_BRANCH | SRCDEP_ECX, +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), +/* CALL JMP JMP JMP*/ + PAIR_X_BRANCH | CYCLES_REG, PAIR_X_BRANCH | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_X_BRANCH | CYCLES_REG, +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), + +/* REPNE REPE*/ +/*f0*/ INVALID, INVALID, PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(0), +/* HLT CMC*/ + PAIR_NP | CYCLES(5), PAIR_XY | CYCLES(2), INVALID, INVALID, +/* CLC STC CLI STI*/ + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(7), PAIR_XY | CYCLES(7), +/* CLD STD INCDEC*/ + PAIR_XY | CYCLES(7), PAIR_XY | CYCLES(7), PAIR_XY | CYCLES_RMW, INVALID +}; + +static uint32_t opcode_timings_mod3[256] = +{ +/* ADD ADD ADD ADD*/ +/*00*/ PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, +/* ADD ADD PUSH ES POP ES*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_XY | CYCLES(1) | SRCDEP_ESP | DSTDEP_ESP, PAIR_NP | CYCLES(3), +/* OR OR OR OR*/ + PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, +/* OR OR PUSH CS */ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_XY | CYCLES(1) | SRCDEP_ESP | DSTDEP_ESP, INVALID, + +/* ADC ADC ADC ADC*/ +/*10*/ PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, +/* ADC ADC PUSH SS POP SS*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_XY | CYCLES(1) | SRCDEP_ESP | DSTDEP_ESP, PAIR_NP | CYCLES(3), +/* SBB SBB SBB SBB*/ + PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, +/* SBB SBB PUSH DS POP DS*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_XY | CYCLES(1) | SRCDEP_ESP | DSTDEP_ESP, PAIR_NP | CYCLES(3), + +/* AND AND AND AND*/ +/*20*/ PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, +/* AND AND DAA*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, INVALID, PAIR_NP | CYCLES(9), +/* SUB SUB SUB SUB*/ + PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, +/* SUB SUB DAS*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, INVALID, PAIR_NP | CYCLES(9), + +/* XOR XOR XOR XOR*/ +/*30*/ PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, +/* XOR XOR AAA*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, INVALID, PAIR_NP | CYCLES(7), +/* CMP CMP CMP CMP*/ + PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM, PAIR_XY | CYCLES_REG | SRCDEP_RM | SRCDEP_REG, +/* CMP CMP AAS*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM, PAIR_XY | CYCLES_REG | SRCDEP_EAX, INVALID, PAIR_NP | CYCLES(7), + +/* INC EAX INC ECX INC EDX INC EBX*/ +/*40*/ PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX, PAIR_XY | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX, PAIR_XY | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX, +/* INC ESP INC EBP INC ESI INC EDI*/ + PAIR_XY | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EBP | DSTDEP_EBP, PAIR_XY | CYCLES_REG | SRCDEP_ESI | DSTDEP_ESI, PAIR_XY | CYCLES_REG | SRCDEP_EDI | DSTDEP_EDI, +/* DEC EAX DEC ECX DEC EDX DEC EBX*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX, PAIR_XY | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX, PAIR_XY | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX, +/* DEC ESP DEC EBP DEC ESI DEC EDI*/ + PAIR_XY | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EBP | DSTDEP_EBP, PAIR_XY | CYCLES_REG | SRCDEP_ESI | DSTDEP_ESI, PAIR_XY | CYCLES_REG | SRCDEP_EDI | DSTDEP_EDI, + +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/*50*/ PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX | SRCDEP_ESP | DSTDEP_ESP, +/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ + PAIR_XY | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EBP | DSTDEP_EBP | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_ESI | DSTDEP_ESI | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EDI | DSTDEP_EDI | SRCDEP_ESP | DSTDEP_ESP, +/* POP EAX POP ECX POP EDX POP EBX*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX | SRCDEP_ESP | DSTDEP_ESP, +/* POP ESP POP EBP POP ESI POP EDI*/ + PAIR_XY | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EBP | DSTDEP_EBP | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_ESI | DSTDEP_ESI | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES_REG | SRCDEP_EDI | DSTDEP_EDI | SRCDEP_ESP | DSTDEP_ESP, + +/* PUSHA POPA BOUND ARPL*/ +/*60*/ PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(9), + INVALID, INVALID, INVALID, INVALID, +/* PUSH imm IMUL PUSH imm IMUL*/ + PAIR_XY | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES(10), PAIR_XY | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES(10), +/* INSB INSW OUTSB OUTSW*/ + PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), + +/* Jxx*/ +/*70*/ PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + +/*80*/ PAIR_XY | CYCLES_REG | SRCDEP_RM | DSTDEP_RM, PAIR_XY | CYCLES_REG | SRCDEP_RM | DSTDEP_RM, PAIR_XY | CYCLES_REG | SRCDEP_RM | DSTDEP_RM, PAIR_XY | CYCLES_REG | SRCDEP_RM | DSTDEP_RM, +/* TEST TEST XCHG XCHG*/ + PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM, PAIR_XY | CYCLES_REG | SRCDEP_REG | SRCDEP_RM, PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), +/* MOV MOV MOV MOV*/ + PAIR_XY | CYCLES_REG | SRCDEP_REG | DSTDEP_RM, PAIR_XY | CYCLES_REG | SRCDEP_REG | DSTDEP_RM, PAIR_XY | CYCLES_REG | SRCDEP_RM | DSTDEP_REG, PAIR_XY | CYCLES_REG | SRCDEP_RM | DSTDEP_REG, +/* MOV from seg LEA MOV to seg POP*/ + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES_REG | DSTDEP_REG, PAIR_NP | CYCLES(3), PAIR_XY | CYCLES(1), + +/* NOP XCHG XCHG XCHG*/ +/*90*/ PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), +/* XCHG XCHG XCHG XCHG*/ + PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(2), +/* CBW CWD CALL far WAIT*/ + PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(2), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), +/* PUSHF POPF SAHF LAHF*/ + PAIR_XY | CYCLES(2) | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES(9) | SRCDEP_ESP | DSTDEP_ESP, PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(2), + +/* MOV MOV MOV MOV*/ +/*a0*/ PAIR_XY | CYCLES_REG | DSTDEP_EAX, PAIR_XY | CYCLES_REG | DSTDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX, +/* MOVSB MOVSW CMPSB CMPSW*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), +/* TEST TEST STOSB STOSW*/ + PAIR_XY | CYCLES_REG | SRCDEP_EAX, PAIR_XY | CYCLES_REG | SRCDEP_EAX, PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), +/* LODSB LODSW SCASB SCASW*/ + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + +/* MOV*/ +/*b0*/ PAIR_XY | CYCLES_REG | DSTDEP_EAX, PAIR_XY | CYCLES_REG | DSTDEP_ECX, PAIR_XY | CYCLES_REG | DSTDEP_EDX, PAIR_XY | CYCLES_REG | DSTDEP_EBX, + PAIR_XY | CYCLES_REG | DSTDEP_EAX, PAIR_XY | CYCLES_REG | DSTDEP_ECX, PAIR_XY | CYCLES_REG | DSTDEP_EDX, PAIR_XY | CYCLES_REG | DSTDEP_EBX, + PAIR_XY | CYCLES_REG | DSTDEP_EAX, PAIR_XY | CYCLES_REG | DSTDEP_ECX, PAIR_XY | CYCLES_REG | DSTDEP_EDX, PAIR_XY | CYCLES_REG | DSTDEP_EBX, + PAIR_XY | CYCLES_REG | DSTDEP_ESP, PAIR_XY | CYCLES_REG | DSTDEP_EBP, PAIR_XY | CYCLES_REG | DSTDEP_ESI, PAIR_XY | CYCLES_REG | DSTDEP_EDI, + +/* RET imm RET*/ +/*c0*/ INVALID, INVALID, PAIR_X_BRANCH | CYCLES(3), PAIR_X_BRANCH | CYCLES(2), +/* LES LDS MOV MOV*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_XY | CYCLES_REG, PAIR_XY | CYCLES_REG, +/* ENTER LEAVE RETF RETF*/ + PAIR_XY | CYCLES(13), PAIR_XY | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), +/* INT3 INT INTO IRET*/ + PAIR_NP | CYCLES(13), PAIR_NP | CYCLES(16), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(10), + + +/*d0*/ INVALID, INVALID, INVALID, INVALID, +/* AAM AAD SETALC XLAT*/ + PAIR_XY | CYCLES(18), PAIR_XY | CYCLES(7), PAIR_XY | CYCLES(2), PAIR_XY | CYCLES(4), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/* LOOPNE LOOPE LOOP JCXZ*/ +/*e0*/ PAIR_X_BRANCH| CYCLES_BRANCH | SRCDEP_ECX, PAIR_X_BRANCH | CYCLES_BRANCH | SRCDEP_ECX, PAIR_X_BRANCH | CYCLES_BRANCH | SRCDEP_ECX, PAIR_X_BRANCH | CYCLES_BRANCH | SRCDEP_ECX, +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), +/* CALL JMP JMP JMP*/ + PAIR_X_BRANCH | CYCLES_REG, PAIR_X_BRANCH | CYCLES_REG, PAIR_NP | CYCLES(1), PAIR_X_BRANCH | CYCLES_REG, +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(14), + +/* REPNE REPE*/ +/*f0*/ INVALID, INVALID, PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(0), +/* HLT CMC*/ + PAIR_NP | CYCLES(4), PAIR_XY | CYCLES(2), INVALID, INVALID, +/* CLC STC CLI STI*/ + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(7), PAIR_XY | CYCLES(7), +/* CLD STD INCDEC*/ + PAIR_XY | CYCLES(7), PAIR_XY | CYCLES(7), PAIR_XY | CYCLES_REG, INVALID +}; + +static uint32_t opcode_timings_0f[256] = +{ +/*00*/ PAIR_NP | CYCLES(20), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(10), + INVALID, PAIR_NP | CYCLES(195), PAIR_NP | CYCLES(7), INVALID, + PAIR_NP | CYCLES(1000), PAIR_NP | CYCLES(10000), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*10*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*20*/ PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), + PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*30*/ PAIR_NP | CYCLES(9), CYCLES(1), PAIR_NP | CYCLES(9), INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*40*/ PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + +/*50*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*60*/ PAIR_X | MMX_SHIFTPACK | CYCLES_RM, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, + PAIR_X | MMX_SHIFTPACK | CYCLES_RM, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, + INVALID, INVALID, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, + +/*70*/ INVALID, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES(1), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, + +/*80*/ PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + +/*90*/ PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + +/*a0*/ PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(12), PAIR_XY | CYCLES(5), + PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(5), INVALID, INVALID, + PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), INVALID, PAIR_XY | CYCLES(5), + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), INVALID, PAIR_NP | CYCLES(10), + +/*b0*/ PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(4), PAIR_XY | CYCLES(5), + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + INVALID, INVALID, PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(5), + PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), INVALID, + +/*c0*/ PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), + PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(4), + +/*d0*/ INVALID, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, + INVALID, PAIR_X | CYCLES_RM, INVALID, INVALID, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, PAIR_X | CYCLES_RM, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, PAIR_X | CYCLES_RM, + +/*e0*/ INVALID, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, INVALID, + INVALID, PAIR_X | CYCLES_RM, INVALID, INVALID, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, PAIR_X | CYCLES_RM, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, PAIR_X | CYCLES_RM, + +/*f0*/ INVALID, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, PAIR_X | MMX_SHIFTPACK | CYCLES_RM, + INVALID, PAIR_X | CYCLES_RM, INVALID, INVALID, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, + PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, PAIR_X | CYCLES_RM, INVALID, +}; +static uint32_t opcode_timings_0f_mod3[256] = +{ +/*00*/ PAIR_NP | CYCLES(20), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(10), + INVALID, PAIR_NP | CYCLES(195), PAIR_NP | CYCLES(7), INVALID, + PAIR_NP | CYCLES(1000), PAIR_NP | CYCLES(10000), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*10*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*20*/ PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), + PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*30*/ PAIR_NP | CYCLES(9), CYCLES(1), PAIR_NP | CYCLES(9), INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*40*/ PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + +/*50*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*60*/ PAIR_X | MMX_SHIFTPACK | CYCLES_REG, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, + PAIR_X | MMX_SHIFTPACK | CYCLES_REG, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, + INVALID, INVALID, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, + +/*70*/ INVALID, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES(1), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, + +/*80*/ PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, PAIR_X_BRANCH | CYCLES_BRANCH, + +/*90*/ PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + +/*a0*/ PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(12), PAIR_XY | CYCLES(5), + PAIR_XY | CYCLES(4), PAIR_XY | CYCLES(5), INVALID, INVALID, + PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), INVALID, PAIR_XY | CYCLES(5), + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), INVALID, PAIR_NP | CYCLES(10), + +/*b0*/ PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(4), PAIR_XY | CYCLES(5), + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), + INVALID, INVALID, PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(5), + PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(1), INVALID, +/*c0*/ PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), + +/*d0*/ INVALID, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, + INVALID, PAIR_X | MMX_MULTIPLY | CYCLES_REG, INVALID, INVALID, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, PAIR_X | CYCLES_REG, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, PAIR_X | CYCLES_REG, + +/*e0*/ INVALID, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, INVALID, + INVALID, PAIR_X | MMX_MULTIPLY | CYCLES_REG, INVALID, INVALID, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, PAIR_X | CYCLES_REG, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, PAIR_X | CYCLES_REG, + +/*f0*/ INVALID, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, PAIR_X | MMX_SHIFTPACK | CYCLES_REG, + INVALID, PAIR_X | MMX_MULTIPLY | CYCLES_REG, INVALID, INVALID, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, + PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, PAIR_X | CYCLES_REG, INVALID, +}; + +static uint32_t opcode_timings_shift[8] = +{ + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES(3), PAIR_XY | CYCLES(4), + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, +}; +static uint32_t opcode_timings_shift_mod3[8] = +{ + PAIR_XY | CYCLES_REG | DSTDEP_RM, PAIR_XY | CYCLES_REG | DSTDEP_RM, PAIR_XY | CYCLES(3) | DSTDEP_RM, PAIR_XY | CYCLES(4) | DSTDEP_RM, + PAIR_XY | CYCLES_REG | DSTDEP_RM, PAIR_XY | CYCLES_REG | DSTDEP_RM, PAIR_XY | CYCLES_REG | DSTDEP_RM, PAIR_XY | CYCLES_REG | DSTDEP_RM, +}; +static uint32_t opcode_timings_shift_imm[8] = +{ + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES(8), PAIR_XY | CYCLES(9), + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, +}; +static uint32_t opcode_timings_shift_imm_mod3[8] = +{ + PAIR_XY | CYCLES_REG | DSTDEP_RM, PAIR_XY | CYCLES_REG | DSTDEP_RM, PAIR_XY | CYCLES(3) | DSTDEP_RM, PAIR_XY | CYCLES(4) | DSTDEP_RM, + PAIR_XY | CYCLES_REG | DSTDEP_RM, PAIR_XY | CYCLES_REG | DSTDEP_RM, PAIR_XY | CYCLES_REG | DSTDEP_RM, PAIR_XY | CYCLES_REG | DSTDEP_RM, +}; +static uint32_t opcode_timings_shift_cl[8] = +{ + PAIR_XY | CYCLES(2) | SRCDEP_ECX, PAIR_XY | CYCLES(2) | SRCDEP_ECX, PAIR_XY | CYCLES(8) | SRCDEP_ECX, PAIR_XY | CYCLES(9) | SRCDEP_ECX, + PAIR_XY | CYCLES(2) | SRCDEP_ECX, PAIR_XY | CYCLES(2) | SRCDEP_ECX, PAIR_XY | CYCLES(2) | SRCDEP_ECX, PAIR_XY | CYCLES(2) | SRCDEP_ECX, +}; +static uint32_t opcode_timings_shift_cl_mod3[8] = +{ + PAIR_XY | CYCLES(2) | DSTDEP_RM | SRCDEP_ECX, PAIR_XY | CYCLES(2) | DSTDEP_RM | SRCDEP_ECX, PAIR_XY | CYCLES(8) | DSTDEP_RM | SRCDEP_ECX, PAIR_XY | CYCLES(9) | DSTDEP_RM | SRCDEP_ECX, + PAIR_XY | CYCLES(2) | DSTDEP_RM | SRCDEP_ECX, PAIR_XY | CYCLES(2) | DSTDEP_RM | SRCDEP_ECX, PAIR_XY | CYCLES(2) | DSTDEP_RM | SRCDEP_ECX, PAIR_XY | CYCLES(2) | DSTDEP_RM | SRCDEP_ECX, +}; + +static uint32_t opcode_timings_f6[8] = +{ +/* TST NOT NEG*/ + PAIR_XY | CYCLES_RM, INVALID, PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(18), PAIR_NP | CYCLES(18) +}; +static uint32_t opcode_timings_f6_mod3[8] = +{ +/* TST NOT NEG*/ + PAIR_XY | CYCLES_REG | SRCDEP_RM, INVALID, PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(18), PAIR_NP | CYCLES(18) +}; +static uint32_t opcode_timings_f7[8] = +{ +/* TST NOT NEG*/ + PAIR_XY | CYCLES_REG | SRCDEP_RM, INVALID, PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES_MULTI(4,10), PAIR_NP | CYCLES_MULTI(4,10), PAIR_NP | CYCLES_MULTI(19,27), PAIR_NP | CYCLES_MULTI(22,30) +}; +static uint32_t opcode_timings_f7_mod3[8] = +{ +/* TST NOT NEG*/ + PAIR_XY | CYCLES_REG | SRCDEP_RM, INVALID, PAIR_XY | CYCLES(1), PAIR_XY | CYCLES(1), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES_MULTI(4,10), PAIR_NP | CYCLES_MULTI(4,10), PAIR_NP | CYCLES_MULTI(19,27), PAIR_NP | CYCLES_MULTI(22,30) +}; +static uint32_t opcode_timings_ff[8] = +{ +/* INC DEC CALL CALL far*/ + PAIR_XY | CYCLES_RMW, PAIR_XY | CYCLES_RMW, PAIR_X_BRANCH | CYCLES(3), PAIR_NP | CYCLES(5), +/* JMP JMP far PUSH*/ + PAIR_X_BRANCH | CYCLES(3), PAIR_NP | CYCLES(5), PAIR_XY | CYCLES(1) | SRCDEP_ESP | DSTDEP_ESP, INVALID +}; +static uint32_t opcode_timings_ff_mod3[8] = +{ +/* INC DEC CALL CALL far*/ + PAIR_XY | CYCLES_REG | SRCDEP_RM | DSTDEP_RM, PAIR_XY | CYCLES_REG | SRCDEP_RM | DSTDEP_RM, PAIR_X_BRANCH | CYCLES(1), PAIR_XY | CYCLES(5), +/* JMP JMP far PUSH*/ + PAIR_X_BRANCH | CYCLES(1), PAIR_XY | CYCLES(5), PAIR_XY | CYCLES(2) | SRCDEP_ESP | DSTDEP_ESP, INVALID +}; + +static uint32_t opcode_timings_d8[8] = +{ +/* FADDs FMULs FCOMs FCOMPs*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(6), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), +/* FSUBs FSUBRs FDIVs FDIVRs*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(34), PAIR_X | CYCLES(34) +}; +static uint32_t opcode_timings_d8_mod3[8] = +{ +/* FADD FMUL FCOM FCOMP*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(6), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), +/* FSUB FSUBR FDIV FDIVR*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(34), PAIR_X | CYCLES(34) +}; + +static uint32_t opcode_timings_d9[8] = +{ +/* FLDs FSTs FSTPs*/ + PAIR_X | CYCLES(2), INVALID, PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), +/* FLDENV FLDCW FSTENV FSTCW*/ + PAIR_X | CYCLES(30), PAIR_X | CYCLES(4), PAIR_X | CYCLES(24), PAIR_X | CYCLES(5) +}; +static uint32_t opcode_timings_d9_mod3[64] = +{ + /*FLD*/ + PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), + PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), + /*FXCH*/ + PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), + PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), PAIR_X | CYCLES(3), + /*FNOP*/ + PAIR_X | CYCLES(2), INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + /*FSTP*/ + PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), + PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), +/* opFCHS opFABS*/ + PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), INVALID, INVALID, +/* opFTST opFXAM (oddly low) */ + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), INVALID, INVALID, +/* opFLD1 opFLDL2T opFLDL2E opFLDPI*/ + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), +/* opFLDEG2 opFLDLN2 opFLDZ*/ + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), INVALID, +/* opF2XM1 opFYL2X opFPTAN opFPATAN*/ + PAIR_X | CYCLES(92), PAIR_X | CYCLES(170), PAIR_X | CYCLES(129), PAIR_X | CYCLES(161), +/* opFDECSTP opFINCSTP,*/ + INVALID, INVALID, PAIR_X | CYCLES(4), PAIR_X | CYCLES(2), +/* opFPREM opFSQRT opFSINCOS*/ + PAIR_X | CYCLES(91), INVALID, PAIR_X | CYCLES(60), PAIR_X | CYCLES(161), +/* opFRNDINT opFSCALE opFSIN opFCOS*/ + PAIR_X | CYCLES(20), PAIR_X | CYCLES(14), PAIR_X | CYCLES(140), PAIR_X | CYCLES(141) +}; + +static uint32_t opcode_timings_da[8] = +{ +/* FIADDl FIMULl FICOMl FICOMPl*/ + PAIR_X | CYCLES(12), PAIR_X | CYCLES(11), PAIR_X | CYCLES(10), PAIR_X | CYCLES(10), +/* FISUBl FISUBRl FIDIVl FIDIVRl*/ + PAIR_X | CYCLES(29), PAIR_X | CYCLES(27), PAIR_X | CYCLES(38), PAIR_X | CYCLES(48) +}; +static uint32_t opcode_timings_da_mod3[8] = +{ + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + INVALID, PAIR_X | CYCLES(5), INVALID, INVALID +}; + + +static uint32_t opcode_timings_db[8] = +{ +/* FLDil FSTil FSTPil*/ + PAIR_X | CYCLES(2), INVALID, PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), +/* FLDe FSTPe*/ + INVALID, PAIR_X | CYCLES(2), INVALID, PAIR_X | CYCLES(2) +}; +static uint32_t opcode_timings_db_mod3[64] = +{ + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), + +/* opFNOP opFCLEX opFINIT*/ + INVALID, PAIR_X | CYCLES(2), PAIR_X | CYCLES(5), PAIR_X | CYCLES(8), +/* opFNOP opFNOP*/ + PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, +}; + +static uint32_t opcode_timings_dc[8] = +{ +/* FADDd FMULd FCOMd FCOMPd*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), +/* FSUBd FSUBRd FDIVd FDIVRd*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(34), PAIR_X | CYCLES(34) +}; +static uint32_t opcode_timings_dc_mod3[8] = +{ +/* opFADDr opFMULr*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), INVALID, INVALID, +/* opFSUBRr opFSUBr opFDIVRr opFDIVr*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(34), PAIR_X | CYCLES(34) +}; + +static uint32_t opcode_timings_dd[8] = +{ +/* FLDd FSTd FSTPd*/ + PAIR_X | CYCLES(2), INVALID, PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), +/* FRSTOR FSAVE FSTSW*/ + PAIR_X | CYCLES(72), INVALID, PAIR_X | CYCLES(67), PAIR_X | CYCLES(2) +}; +static uint32_t opcode_timings_dd_mod3[8] = +{ +/* FFFREE FST FSTP*/ + PAIR_X | CYCLES(3), INVALID, PAIR_X | CYCLES(2), PAIR_X | CYCLES(2), +/* FUCOM FUCOMP*/ + PAIR_X | CYCLES(4), PAIR_X | CYCLES(4), INVALID, INVALID +}; + +static uint32_t opcode_timings_de[8] = +{ +/* FIADDw FIMULw FICOMw FICOMPw*/ + PAIR_X | CYCLES(12), PAIR_X | CYCLES(11), PAIR_X | CYCLES(10), PAIR_X | CYCLES(10), +/* FISUBw FISUBRw FIDIVw FIDIVRw*/ + PAIR_X | CYCLES(27), PAIR_X | CYCLES(27), PAIR_X | CYCLES(38), PAIR_X | CYCLES(38) +}; +static uint32_t opcode_timings_de_mod3[8] = +{ +/* FADD FMUL FCOMPP*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), INVALID, PAIR_X | CYCLES(7), +/* FSUB FSUBR FDIV FDIVR*/ + PAIR_X | CYCLES(7), PAIR_X | CYCLES(7), PAIR_X | CYCLES(34), PAIR_X | CYCLES(34) +}; + +static uint32_t opcode_timings_df[8] = +{ +/* FILDiw FISTiw FISTPiw*/ + PAIR_X | CYCLES(8), INVALID, PAIR_X | CYCLES(10), PAIR_X | CYCLES(13), +/* FILDiq FBSTP FISTPiq*/ + INVALID, PAIR_X | CYCLES(8), PAIR_X | CYCLES(63), PAIR_X | CYCLES(13) +}; +static uint32_t opcode_timings_df_mod3[8] = +{ + INVALID, INVALID, INVALID, INVALID, +/* FSTSW AX*/ + PAIR_X | CYCLES(6), INVALID, INVALID, INVALID +}; + +static uint32_t opcode_timings_8x[8] = +{ + PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RMW | SRCDEP_REG, + PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RMW | SRCDEP_REG, PAIR_XY | CYCLES_RM | SRCDEP_REG +}; + +static int decode_delay; +static uint8_t last_prefix; + +static inline int COUNT(uint32_t c, int op_32) +{ + if (c & CYCLES_HAS_MULTI) + { + if (op_32 & 0x100) + return ((uintptr_t)c >> 8) & 0xff; + return (uintptr_t)c & 0xff; + } + if (!(c & PAIR_MASK)) + return c & 0xffff; + + return c & CYCLES_MASK; +} + +void codegen_timing_686_block_start() +{ + prev_full = decode_delay = 0; +} + +void codegen_timing_686_start() +{ + decode_delay = 0; + last_prefix = 0; +} + +void codegen_timing_686_prefix(uint8_t prefix, uint32_t fetchdat) +{ + /*6x86 can decode 1 prefix per instruction per clock with no penalty. If + either instruction has more than one prefix then decode is delayed by + one cycle for each additional prefix*/ + decode_delay++; + last_prefix = prefix; +} + +void codegen_timing_686_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) +{ + int *timings; + int mod3 = ((fetchdat & 0xc0) == 0xc0); + int bit8 = !(opcode & 1); + + switch (last_prefix) + { + case 0x0f: + timings = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; +// pclog("timings 0f\n"); + break; + + case 0xd8: + timings = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; + opcode = (opcode >> 3) & 7; +// pclog("timings d8\n"); + break; + case 0xd9: + timings = mod3 ? opcode_timings_d9_mod3 : opcode_timings_d9; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; +// pclog("timings d9\n"); + break; + case 0xda: + timings = mod3 ? opcode_timings_da_mod3 : opcode_timings_da; + opcode = (opcode >> 3) & 7; +// pclog("timings da\n"); + break; + case 0xdb: + timings = mod3 ? opcode_timings_db_mod3 : opcode_timings_db; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; +// pclog("timings db\n"); + break; + case 0xdc: + timings = mod3 ? opcode_timings_dc_mod3 : opcode_timings_dc; + opcode = (opcode >> 3) & 7; +// pclog("timings dc\n"); + break; + case 0xdd: + timings = mod3 ? opcode_timings_dd_mod3 : opcode_timings_dd; + opcode = (opcode >> 3) & 7; +// pclog("timings dd\n"); + break; + case 0xde: + timings = mod3 ? opcode_timings_de_mod3 : opcode_timings_de; + opcode = (opcode >> 3) & 7; +// pclog("timings de\n"); + break; + case 0xdf: + timings = mod3 ? opcode_timings_df_mod3 : opcode_timings_df; + opcode = (opcode >> 3) & 7; +// pclog("timings df\n"); + break; + + default: + switch (opcode) + { + case 0x80: case 0x81: case 0x82: case 0x83: + timings = mod3 ? opcode_timings_mod3 : opcode_timings_8x; + if (!mod3) + opcode = (fetchdat >> 3) & 7; +// pclog("timings 80 %p %p %p\n", (void *)timings, (void *)opcode_timings_mod3, (void *)opcode_timings_8x); + break; + + case 0xc0: case 0xc1: + timings = mod3 ? opcode_timings_shift_imm_mod3 : opcode_timings_shift_imm; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xd0: case 0xd1: + timings = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xd2: case 0xd3: + timings = mod3 ? opcode_timings_shift_cl_mod3 : opcode_timings_shift_cl; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xf6: + timings = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; + opcode = (fetchdat >> 3) & 7; +// pclog("timings f6\n"); + break; + case 0xf7: + timings = mod3 ? opcode_timings_f7_mod3 : opcode_timings_f7; + opcode = (fetchdat >> 3) & 7; +// pclog("timings f7\n"); + break; + case 0xff: + timings = mod3 ? opcode_timings_ff_mod3 : opcode_timings_ff; + opcode = (fetchdat >> 3) & 7; +// pclog("timings ff\n"); + break; + + default: + timings = mod3 ? opcode_timings_mod3 : opcode_timings; +// pclog("timings normal\n"); + break; + } + } + + if (decode_delay < 0) + decode_delay = 0; + + if (prev_full) + { + uint8_t regmask = get_srcdep_mask(timings[opcode], fetchdat, bit8); + + /*Second instruction in the pair*/ + if ((timings[opcode] & PAIR_MASK) == PAIR_NP) + { + /*Instruction can not pair with previous*/ + /*Run previous now*/ + codegen_block_cycles += COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay; + decode_delay = (-COUNT(prev_timings[prev_opcode], prev_op_32)) + 1; + prev_full = 0; +// pclog("Not pairable %i\n", COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay); + } + else if (((timings[opcode] & PAIR_MASK) == PAIR_X || (timings[opcode] & PAIR_MASK) == PAIR_X_BRANCH) + && (prev_timings[opcode] & PAIR_MASK) == PAIR_X) + { + /*Instruction can not pair with previous*/ + /*Run previous now*/ + codegen_block_cycles += COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay; + decode_delay = (-COUNT(prev_timings[prev_opcode], prev_op_32)) + 1; + prev_full = 0; +// pclog("Not pairable %i\n", COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay); + } + else if (prev_regmask & regmask) + { + /*Instruction can not pair with previous*/ + /*Run previous now*/ + codegen_block_cycles += COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay; + decode_delay = (-COUNT(prev_timings[prev_opcode], prev_op_32)) + 1; + prev_full = 0; +// pclog("Not pairable %i\n", COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay); + } + else + { + int t1 = COUNT(prev_timings[prev_opcode], prev_op_32); + int t2 = COUNT(timings[opcode], op_32); + int t_pair = (t1 > t2) ? t1 : t2; + + if (!t_pair) + fatal("Pairable 0 cycles! %02x %02x\n", opcode, prev_opcode); + codegen_block_cycles += t_pair; + decode_delay = (-t_pair) + 1; + + prev_full = 0; +// pclog("Pairable %i %i %i %02x %02x\n", t_pair, t1, t2, opcode, prev_opcode); + return; + } + } + + if (!prev_full) + { + /*First instruction in the pair*/ + if ((timings[opcode] & PAIR_MASK) == PAIR_NP || (timings[opcode] & PAIR_MASK) == PAIR_X_BRANCH) + { + /*Instruction not pairable*/ + codegen_block_cycles += COUNT(timings[opcode], op_32) + decode_delay; + decode_delay = (-COUNT(timings[opcode], op_32)) + 1; +// pclog("Not pairable %i\n", COUNT(timings[opcode], op_32) + decode_delay); + } + else + { + /*Instruction might pair with next*/ +// pclog("Might pair - %02x %02x %08x %08x %08x %p %p %p\n", last_prefix, opcode, timings[opcode], timings[opcode] & PAIR_MASK, PAIR_X_BRANCH, timings, opcode_timings_0f, opcode_timings_0f_mod3); + prev_full = 1; + prev_opcode = opcode; + prev_timings = timings; + prev_op_32 = op_32; + prev_regmask = get_dstdep_mask(timings[opcode], fetchdat, bit8); + return; + } + } +} + +void codegen_timing_686_block_end() +{ + if (prev_full) + { + /*Run previous now*/ + codegen_block_cycles += COUNT(prev_timings[prev_opcode], prev_op_32) + decode_delay; + prev_full = 0; + } +} + +codegen_timing_t codegen_timing_686 = +{ + codegen_timing_686_start, + codegen_timing_686_prefix, + codegen_timing_686_opcode, + codegen_timing_686_block_start, + codegen_timing_686_block_end +}; diff --git a/src/codegen_timing_pentium.c b/src/codegen_timing_pentium.c new file mode 100644 index 000000000..31d4cafe7 --- /dev/null +++ b/src/codegen_timing_pentium.c @@ -0,0 +1,1061 @@ +/*Elements taken into account : + - U/V integer pairing + - FPU/FXCH pairing + - Prefix decode delay (including shadowing) + Elements not taken into account : + - Branch prediction (beyond most simplistic approximation) + - PMMX decode queue + - FPU latencies + - MMX latencies +*/ + +#include "ibm.h" +#include "cpu.h" +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "mem.h" +#include "codegen.h" + +/*Instruction has different execution time for 16 and 32 bit data. Does not pair */ +#define CYCLES_HAS_MULTI (1 << 28) + +#define CYCLES_MULTI(c16, c32) (CYCLES_HAS_MULTI | c16 | (c32 << 8)) + +/*Instruction lasts given number of cycles. Does not pair*/ +#define CYCLES(c) (c | PAIR_NP) + + +static int pair_timings[4][4] = +{ +/* Reg RM RMW Branch*/ +/*Reg*/ {1, 2, 3, 2}, +/*RM*/ {2, 2, 3, 3}, +/*RMW*/ {3, 4, 5, 4}, +/*Branch*/ {-1, -1, -1, -1} +}; + +/*Instruction follows either register timing, read-modify, or read-modify-write. + May be pairable*/ +#define CYCLES_REG (0 << 0) +#define CYCLES_RM (1 << 0) +#define CYCLES_RMW (2 << 0) +#define CYCLES_BRANCH (3 << 0) + +#define CYCLES_MASK ((1 << 7) - 1) + +/*Instruction is MMX shift or pack/unpack instruction*/ +#define MMX_SHIFTPACK (1 << 7) +/*Instruction is MMX multiply instruction*/ +#define MMX_MULTIPLY (1 << 8) + +/*Instruction does not pair*/ +#define PAIR_NP (0 << 29) +/*Instruction pairs in U pipe only*/ +#define PAIR_U (1 << 29) +/*Instruction pairs in V pipe only*/ +#define PAIR_V (2 << 29) +/*Instruction pairs in both U and V pipes*/ +#define PAIR_UV (3 << 29) +/*Instruction pairs in U pipe only and only with FXCH*/ +#define PAIR_FX (5 << 29) +/*Instruction is FXCH and only pairs in V pipe with FX pairable instruction*/ +#define PAIR_FXCH (6 << 29) + +#define PAIR_MASK (7 << 29) + +/*Instruction has input dependency on register in REG field*/ +#define SRCDEP_REG (1 << 9) +/*Instruction has input dependency on register in R/M field*/ +#define SRCDEP_RM (1 << 10) +/*Instruction modifies register in REG field*/ +#define DSTDEP_REG (1 << 11) +/*Instruction modifies register in R/M field*/ +#define DSTDEP_RM (1 << 12) + +/*Instruction has input dependency on given register*/ +#define SRCDEP_EAX (1 << 13) +#define SRCDEP_ECX (1 << 14) +#define SRCDEP_EDX (1 << 15) +#define SRCDEP_EBX (1 << 16) +#define SRCDEP_ESP (1 << 17) +#define SRCDEP_EBP (1 << 18) +#define SRCDEP_ESI (1 << 19) +#define SRCDEP_EDI (1 << 20) + +/*Instruction modifies given register*/ +#define DSTDEP_EAX (1 << 21) +#define DSTDEP_ECX (1 << 22) +#define DSTDEP_EDX (1 << 23) +#define DSTDEP_EBX (1 << 24) +#define DSTDEP_ESP (1 << 25) +#define DSTDEP_EBP (1 << 26) +#define DSTDEP_ESI (1 << 27) +#define DSTDEP_EDI (1 << 28) + +#define INVALID 0 + +static int u_pipe_full; +static uint32_t u_pipe_opcode; +static uint32_t *u_pipe_timings; +static uint32_t u_pipe_op_32; +static uint32_t u_pipe_regmask; + +#define REGMASK_SHIFTPACK (1 << 8) +#define REGMASK_MULTIPLY (1 << 8) + +static uint32_t get_srcdep_mask(uint32_t data, uint32_t fetchdat, int bit8) +{ + uint32_t mask = 0; + if (data & SRCDEP_REG) + { + int reg = (fetchdat >> 3) & 7; + if (bit8) + reg &= 3; + mask |= (1 << reg); + } + if (data & SRCDEP_RM) + { + int reg = fetchdat & 7; + if (bit8) + reg &= 3; + mask |= (1 << reg); + } + mask |= ((data >> 16) & 0xff); + if (data & MMX_SHIFTPACK) + mask |= REGMASK_SHIFTPACK; + if (data & MMX_MULTIPLY) + mask |= REGMASK_MULTIPLY; + + return mask; +} + +static uint32_t get_dstdep_mask(uint32_t data, uint32_t fetchdat, int bit8) +{ + uint32_t mask = 0; + if (data & DSTDEP_REG) + { + int reg = (fetchdat >> 3) & 7; + if (bit8) + reg &= 3; + mask |= (1 << reg); + } + if (data & DSTDEP_RM) + { + int reg = fetchdat & 7; + if (bit8) + reg &= 3; + mask |= (1 << reg); + } + mask |= ((data >> 24) & 0xff); + if (data & MMX_SHIFTPACK) + mask |= REGMASK_SHIFTPACK; + if (data & MMX_MULTIPLY) + mask |= REGMASK_MULTIPLY; + + return mask; +} +static uint32_t opcode_timings[256] = +{ +/* ADD ADD ADD ADD*/ +/*00*/ PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, +/* ADD ADD PUSH ES POP ES*/ + PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), +/* OR OR OR OR*/ + PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, +/* OR OR PUSH CS */ + PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_NP | CYCLES(1), INVALID, + +/* ADC ADC ADC ADC*/ +/*10*/ PAIR_U | CYCLES_RMW | SRCDEP_REG, PAIR_U | CYCLES_RMW | SRCDEP_REG, PAIR_U | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, PAIR_U | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, +/* ADC ADC PUSH SS POP SS*/ + PAIR_U | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_U | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), +/* SBB SBB SBB SBB*/ + PAIR_U | CYCLES_RMW | SRCDEP_REG, PAIR_U | CYCLES_RMW | SRCDEP_REG, PAIR_U | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, PAIR_U | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, +/* SBB SBB PUSH DS POP DS*/ + PAIR_U | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_U | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), + +/* AND AND AND AND*/ +/*20*/ PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, +/* AND AND DAA*/ + PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, INVALID, PAIR_NP | CYCLES(3), +/* SUB SUB SUB SUB*/ + PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, +/* SUB SUB DAS*/ + PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, INVALID, PAIR_NP | CYCLES(3), + +/* XOR XOR XOR XOR*/ +/*30*/ PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG | DSTDEP_REG, +/* XOR XOR AAA*/ + PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, INVALID, PAIR_NP | CYCLES(3), +/* CMP CMP CMP CMP*/ + PAIR_UV | CYCLES_RM | SRCDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG, +/* CMP CMP AAS*/ + PAIR_UV | CYCLES_REG | SRCDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX, INVALID, PAIR_NP | CYCLES(3), + +/* INC EAX INC ECX INC EDX INC EBX*/ +/*40*/ PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX, PAIR_UV | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX, PAIR_UV | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX, +/* INC ESP INC EBP INC ESI INC EDI*/ + PAIR_UV | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_UV | CYCLES_REG | SRCDEP_EBP | DSTDEP_EBP, PAIR_UV | CYCLES_REG | SRCDEP_ESI | DSTDEP_ESI, PAIR_UV | CYCLES_REG | SRCDEP_EDI | DSTDEP_EDI, +/* DEC EAX DEC ECX DEC EDX DEC EBX*/ + PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX, PAIR_UV | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX, PAIR_UV | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX, +/* DEC ESP DEC EBP DEC ESI DEC EDI*/ + PAIR_UV | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_UV | CYCLES_REG | SRCDEP_EBP | DSTDEP_EBP, PAIR_UV | CYCLES_REG | SRCDEP_ESI | DSTDEP_ESI, PAIR_UV | CYCLES_REG | SRCDEP_EDI | DSTDEP_EDI, + +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/*50*/ PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX, PAIR_UV | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX, PAIR_UV | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX, +/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ + PAIR_UV | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_UV | CYCLES_REG | SRCDEP_EBP | DSTDEP_EBP, PAIR_UV | CYCLES_REG | SRCDEP_ESI | DSTDEP_ESI, PAIR_UV | CYCLES_REG | SRCDEP_EDI | DSTDEP_EDI, +/* POP EAX POP ECX POP EDX POP EBX*/ + PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX, PAIR_UV | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX, PAIR_UV | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX, +/* POP ESP POP EBP POP ESI POP EDI*/ + PAIR_UV | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_UV | CYCLES_REG | SRCDEP_EBP | DSTDEP_EBP, PAIR_UV | CYCLES_REG | SRCDEP_ESI | DSTDEP_ESI, PAIR_UV | CYCLES_REG | SRCDEP_EDI | DSTDEP_EDI, + +/* PUSHA POPA BOUND ARPL*/ +/*60*/ PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(8), PAIR_NP | CYCLES(7), + INVALID, INVALID, INVALID, INVALID, +/* PUSH imm IMUL PUSH imm IMUL*/ + PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(10), PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(10), +/* INSB INSW OUTSB OUTSW*/ + PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(13), PAIR_NP | CYCLES(13), + +/* Jxx*/ +/*70*/ PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + +/*80*/ INVALID, INVALID, INVALID, INVALID, +/* TEST TEST XCHG XCHG*/ + PAIR_UV | CYCLES_RM | SRCDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* MOV MOV MOV MOV*/ + PAIR_UV | CYCLES_REG | SRCDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG, PAIR_UV | CYCLES_REG | DSTDEP_REG, PAIR_UV | CYCLES_REG | DSTDEP_REG, +/* MOV from seg LEA MOV to seg POP*/ + PAIR_NP | CYCLES(1), PAIR_UV | CYCLES_REG | DSTDEP_REG, CYCLES(3), PAIR_NP | CYCLES(3), + +/* NOP XCHG XCHG XCHG*/ +/*90*/ PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), +/* XCHG XCHG XCHG XCHG*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), +/* CBW CWD CALL far WAIT*/ + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(1), +/* PUSHF POPF SAHF LAHF*/ + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + +/* MOV MOV MOV MOV*/ +/*a0*/ PAIR_UV | CYCLES_REG | DSTDEP_EAX, PAIR_UV | CYCLES_REG | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX, +/* MOVSB MOVSW CMPSB CMPSW*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), +/* TEST TEST STOSB STOSW*/ + PAIR_UV | CYCLES_REG | SRCDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* LODSB LODSW SCASB SCASW*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), + +/* MOV*/ +/*b0*/ PAIR_UV | CYCLES_REG | DSTDEP_EAX, PAIR_UV | CYCLES_REG | DSTDEP_ECX, PAIR_UV | CYCLES_REG | DSTDEP_EDX, PAIR_UV | CYCLES_REG | DSTDEP_EBX, + PAIR_UV | CYCLES_REG | DSTDEP_EAX, PAIR_UV | CYCLES_REG | DSTDEP_ECX, PAIR_UV | CYCLES_REG | DSTDEP_EDX, PAIR_UV | CYCLES_REG | DSTDEP_EBX, + PAIR_UV | CYCLES_REG | DSTDEP_EAX, PAIR_UV | CYCLES_REG | DSTDEP_ECX, PAIR_UV | CYCLES_REG | DSTDEP_EDX, PAIR_UV | CYCLES_REG | DSTDEP_EBX, + PAIR_UV | CYCLES_REG | DSTDEP_ESP, PAIR_UV | CYCLES_REG | DSTDEP_EBP, PAIR_UV | CYCLES_REG | DSTDEP_ESI, PAIR_UV | CYCLES_REG | DSTDEP_EDI, + +/* RET imm RET*/ +/*c0*/ INVALID, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(2), +/* LES LDS MOV MOV*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* ENTER LEAVE RETF RETF*/ + PAIR_NP | CYCLES(15), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(0), +/* INT3 INT INTO IRET*/ + PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(0), + + +/*d0*/ INVALID, INVALID, INVALID, INVALID, +/* AAM AAD SETALC XLAT*/ + PAIR_NP | CYCLES(18), PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(4), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, +/* LOOPNE LOOPE LOOP JCXZ*/ +/*e0*/ PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(12), PAIR_NP | CYCLES(12), +/* CALL JMP JMP JMP*/ + PAIR_V | CYCLES_REG, PAIR_V | CYCLES_REG, PAIR_NP | CYCLES(0), PAIR_V | CYCLES_REG, +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(12), PAIR_NP | CYCLES(12), + +/* REPNE REPE*/ +/*f0*/ INVALID, INVALID, PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(0), +/* HLT CMC*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(2), INVALID, INVALID, +/* CLC STC CLI STI*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), +/* CLD STD INCDEC*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_UV | CYCLES_RMW, INVALID +}; + +static uint32_t opcode_timings_mod3[256] = +{ +/* ADD ADD ADD ADD*/ +/*00*/ PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, +/* ADD ADD PUSH ES POP ES*/ + PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), +/* OR OR OR OR*/ + PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, +/* OR OR PUSH CS */ + PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_NP | CYCLES(1), INVALID, + +/* ADC ADC ADC ADC*/ +/*10*/ PAIR_U | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_U | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_U | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_U | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, +/* ADC ADC PUSH SS POP SS*/ + PAIR_U | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_U | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), +/* SBB SBB SBB SBB*/ + PAIR_U | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_U | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_U | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_U | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, +/* SBB SBB PUSH DS POP DS*/ + PAIR_U | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_U | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(3), + +/* AND AND AND AND*/ +/*20*/ PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, +/* AND AND DAA*/ + PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, INVALID, PAIR_NP | CYCLES(3), +/* SUB SUB SUB SUB*/ + PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, +/* SUB SUB DAS*/ + PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, INVALID, PAIR_NP | CYCLES(3), + +/* XOR XOR XOR XOR*/ +/*30*/ PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM | DSTDEP_REG, +/* XOR XOR AAA*/ + PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM | DSTDEP_EAX, INVALID, PAIR_NP | CYCLES(3), +/* CMP CMP CMP CMP*/ + PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM, PAIR_UV | CYCLES_REG | SRCDEP_RM | SRCDEP_REG, +/* CMP CMP AAS*/ + PAIR_UV | CYCLES_REG | SRCDEP_EAX | SRCDEP_RM, PAIR_UV | CYCLES_REG | SRCDEP_EAX, INVALID, PAIR_NP | CYCLES(3), + +/* INC EAX INC ECX INC EDX INC EBX*/ +/*40*/ PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX, PAIR_UV | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX, PAIR_UV | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX, +/* INC ESP INC EBP INC ESI INC EDI*/ + PAIR_UV | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_UV | CYCLES_REG | SRCDEP_EBP | DSTDEP_EBP, PAIR_UV | CYCLES_REG | SRCDEP_ESI | DSTDEP_ESI, PAIR_UV | CYCLES_REG | SRCDEP_EDI | DSTDEP_EDI, +/* DEC EAX DEC ECX DEC EDX DEC EBX*/ + PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX, PAIR_UV | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX, PAIR_UV | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX, +/* DEC ESP DEC EBP DEC ESI DEC EDI*/ + PAIR_UV | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_UV | CYCLES_REG | SRCDEP_EBP | DSTDEP_EBP, PAIR_UV | CYCLES_REG | SRCDEP_ESI | DSTDEP_ESI, PAIR_UV | CYCLES_REG | SRCDEP_EDI | DSTDEP_EDI, + +/* PUSH EAX PUSH ECX PUSH EDX PUSH EBX*/ +/*50*/ PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX, PAIR_UV | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX, PAIR_UV | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX, +/* PUSH ESP PUSH EBP PUSH ESI PUSH EDI*/ + PAIR_UV | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_UV | CYCLES_REG | SRCDEP_EBP | DSTDEP_EBP, PAIR_UV | CYCLES_REG | SRCDEP_ESI | DSTDEP_ESI, PAIR_UV | CYCLES_REG | SRCDEP_EDI | DSTDEP_EDI, +/* POP EAX POP ECX POP EDX POP EBX*/ + PAIR_UV | CYCLES_REG | SRCDEP_EAX | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_ECX | DSTDEP_ECX, PAIR_UV | CYCLES_REG | SRCDEP_EDX | DSTDEP_EDX, PAIR_UV | CYCLES_REG | SRCDEP_EBX | DSTDEP_EBX, +/* POP ESP POP EBP POP ESI POP EDI*/ + PAIR_UV | CYCLES_REG | SRCDEP_ESP | DSTDEP_ESP, PAIR_UV | CYCLES_REG | SRCDEP_EBP | DSTDEP_EBP, PAIR_UV | CYCLES_REG | SRCDEP_ESI | DSTDEP_ESI, PAIR_UV | CYCLES_REG | SRCDEP_EDI | DSTDEP_EDI, + +/* PUSHA POPA BOUND ARPL*/ +/*60*/ PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(8), PAIR_NP | CYCLES(7), + INVALID, INVALID, INVALID, INVALID, +/* PUSH imm IMUL PUSH imm IMUL*/ + PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(10), PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(10), +/* INSB INSW OUTSB OUTSW*/ + PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(13), PAIR_NP | CYCLES(13), + +/* Jxx*/ +/*70*/ PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, PAIR_V | CYCLES_BRANCH, + +/*80*/ PAIR_UV | CYCLES_REG | SRCDEP_RM | DSTDEP_RM, PAIR_UV | CYCLES_REG | SRCDEP_RM | DSTDEP_RM, PAIR_UV | CYCLES_REG | SRCDEP_RM | DSTDEP_RM, PAIR_UV | CYCLES_REG | SRCDEP_RM | DSTDEP_RM, +/* TEST TEST XCHG XCHG*/ + PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM, PAIR_UV | CYCLES_REG | SRCDEP_REG | SRCDEP_RM, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* MOV MOV MOV MOV*/ + PAIR_UV | CYCLES_REG | SRCDEP_REG | DSTDEP_RM, PAIR_UV | CYCLES_REG | SRCDEP_REG | DSTDEP_RM, PAIR_UV | CYCLES_REG | SRCDEP_RM | DSTDEP_REG, PAIR_UV | CYCLES_REG | SRCDEP_RM | DSTDEP_REG, +/* MOV from seg LEA MOV to seg POP*/ + PAIR_NP | CYCLES(1), PAIR_UV | CYCLES_REG | DSTDEP_REG, CYCLES(3), PAIR_NP | CYCLES(3), + +/* NOP XCHG XCHG XCHG*/ +/*90*/ PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), +/* XCHG XCHG XCHG XCHG*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), +/* CBW CWD CALL far WAIT*/ + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(1), +/* PUSHF POPF SAHF LAHF*/ + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + +/* MOV MOV MOV MOV*/ +/*a0*/ PAIR_UV | CYCLES_REG | DSTDEP_EAX, PAIR_UV | CYCLES_REG | DSTDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX, +/* MOVSB MOVSW CMPSB CMPSW*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), +/* TEST TEST STOSB STOSW*/ + PAIR_UV | CYCLES_REG | SRCDEP_EAX, PAIR_UV | CYCLES_REG | SRCDEP_EAX, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* LODSB LODSW SCASB SCASW*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), + +/* MOV*/ +/*b0*/ PAIR_UV | CYCLES_REG | DSTDEP_EAX, PAIR_UV | CYCLES_REG | DSTDEP_ECX, PAIR_UV | CYCLES_REG | DSTDEP_EDX, PAIR_UV | CYCLES_REG | DSTDEP_EBX, + PAIR_UV | CYCLES_REG | DSTDEP_EAX, PAIR_UV | CYCLES_REG | DSTDEP_ECX, PAIR_UV | CYCLES_REG | DSTDEP_EDX, PAIR_UV | CYCLES_REG | DSTDEP_EBX, + PAIR_UV | CYCLES_REG | DSTDEP_EAX, PAIR_UV | CYCLES_REG | DSTDEP_ECX, PAIR_UV | CYCLES_REG | DSTDEP_EDX, PAIR_UV | CYCLES_REG | DSTDEP_EBX, + PAIR_UV | CYCLES_REG | DSTDEP_ESP, PAIR_UV | CYCLES_REG | DSTDEP_EBP, PAIR_UV | CYCLES_REG | DSTDEP_ESI, PAIR_UV | CYCLES_REG | DSTDEP_EDI, + +/* RET imm RET*/ +/*c0*/ INVALID, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(2), +/* LES LDS MOV MOV*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, +/* ENTER LEAVE RETF RETF*/ + PAIR_NP | CYCLES(15), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(0), +/* INT3 INT INTO IRET*/ + PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(0), + + +/*d0*/ INVALID, INVALID, INVALID, INVALID, +/* AAM AAD SETALC XLAT*/ + PAIR_NP | CYCLES(18), PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(4), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/* LOOPNE LOOPE LOOP JCXZ*/ +/*e0*/ PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(5), PAIR_NP | CYCLES(5), +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(12), PAIR_NP | CYCLES(12), +/* CALL JMP JMP JMP*/ + PAIR_V | CYCLES_REG, PAIR_V | CYCLES_REG, PAIR_NP | CYCLES(0), PAIR_V | CYCLES_REG, +/* IN AL IN AX OUT_AL OUT_AX*/ + PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(12), PAIR_NP | CYCLES(12), + +/* REPNE REPE*/ +/*f0*/ INVALID, INVALID, PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(0), +/* HLT CMC*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(2), INVALID, INVALID, +/* CLC STC CLI STI*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), +/* CLD STD INCDEC*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_UV | CYCLES_REG, INVALID +}; + +static uint32_t opcode_timings_0f[256] = +{ +/*00*/ PAIR_NP | CYCLES(20), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(10), + INVALID, PAIR_NP | CYCLES(195), PAIR_NP | CYCLES(7), INVALID, + PAIR_NP | CYCLES(1000), PAIR_NP | CYCLES(10000), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*10*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*20*/ PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), + PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*30*/ PAIR_NP | CYCLES(9), CYCLES(1), PAIR_NP | CYCLES(9), INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*40*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*50*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*60*/ PAIR_U | MMX_SHIFTPACK | CYCLES_RM, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, + PAIR_U | MMX_SHIFTPACK | CYCLES_RM, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, + INVALID, INVALID, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, + +/*70*/ INVALID, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_NP | CYCLES(100), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, + +/*80*/ PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + +/*90*/ PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + +/*a0*/ PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(8), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(4), INVALID, INVALID, + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), INVALID, PAIR_NP | CYCLES(13), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), INVALID, PAIR_NP | CYCLES(10), + +/*b0*/ PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(13), + PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + INVALID, INVALID, PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(13), + PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + +/*c0*/ PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), + +/*d0*/ INVALID, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, + INVALID, PAIR_U | CYCLES_RM, INVALID, INVALID, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, PAIR_U | CYCLES_RM, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, PAIR_U | CYCLES_RM, + +/*e0*/ INVALID, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, INVALID, + INVALID, PAIR_U | CYCLES_RM, INVALID, INVALID, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, PAIR_U | CYCLES_RM, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, PAIR_U | CYCLES_RM, + +/*f0*/ INVALID, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, PAIR_U | MMX_SHIFTPACK | CYCLES_RM, + INVALID, PAIR_U | CYCLES_RM, INVALID, INVALID, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, + PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, PAIR_U | CYCLES_RM, INVALID, +}; +static uint32_t opcode_timings_0f_mod3[256] = +{ +/*00*/ PAIR_NP | CYCLES(20), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(10), + INVALID, PAIR_NP | CYCLES(195), PAIR_NP | CYCLES(7), INVALID, + PAIR_NP | CYCLES(1000), PAIR_NP | CYCLES(10000), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*10*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*20*/ PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), + PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*30*/ PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(9), INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*40*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*50*/ INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/*60*/ PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, + INVALID, INVALID, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + +/*70*/ INVALID, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_NP | CYCLES(100), + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, + +/*80*/ PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), + +/*90*/ PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + +/*a0*/ PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(14), PAIR_NP | CYCLES(8), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(4), INVALID, INVALID, + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), INVALID, PAIR_NP | CYCLES(13), + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), INVALID, PAIR_NP | CYCLES(10), + +/*b0*/ PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(10), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(13), + PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + INVALID, INVALID, PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(13), + PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), + +/*c0*/ PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), + +/*d0*/ INVALID, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, + INVALID, PAIR_UV | MMX_MULTIPLY | CYCLES_REG, INVALID, INVALID, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_UV | CYCLES_REG, + +/*e0*/ INVALID, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, INVALID, + INVALID, PAIR_UV | MMX_MULTIPLY | CYCLES_REG, INVALID, INVALID, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_UV | CYCLES_REG, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, PAIR_UV | CYCLES_REG, + +/*f0*/ INVALID, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, PAIR_UV | MMX_SHIFTPACK | CYCLES_REG, + INVALID, PAIR_UV | MMX_MULTIPLY | CYCLES_REG, INVALID, INVALID, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, + PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, PAIR_UV | CYCLES_REG, INVALID, +}; + +static uint32_t opcode_timings_shift[8] = +{ + PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, + PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, PAIR_U | CYCLES_RMW, +}; +static uint32_t opcode_timings_shift_mod3[8] = +{ + PAIR_U | CYCLES_REG | DSTDEP_RM, PAIR_U | CYCLES_REG | DSTDEP_RM, PAIR_U | CYCLES_REG | DSTDEP_RM, PAIR_U | CYCLES_REG | DSTDEP_RM, + PAIR_U | CYCLES_REG | DSTDEP_RM, PAIR_U | CYCLES_REG | DSTDEP_RM, PAIR_U | CYCLES_REG | DSTDEP_RM, PAIR_U | CYCLES_REG | DSTDEP_RM, +}; + +static uint32_t opcode_timings_f6[8] = +{ +/* TST NOT NEG*/ + PAIR_UV | CYCLES_RM, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(17), PAIR_NP | CYCLES(22) +}; +static uint32_t opcode_timings_f6_mod3[8] = +{ +/* TST NOT NEG*/ + PAIR_UV | CYCLES_REG | SRCDEP_RM, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(11), PAIR_NP | CYCLES(17), PAIR_NP | CYCLES(22) +}; +static uint32_t opcode_timings_f7[8] = +{ +/* TST NOT NEG*/ + PAIR_UV | CYCLES_RM, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES_MULTI(11,10), PAIR_NP | CYCLES_MULTI(11,10), PAIR_NP | CYCLES_MULTI(25,41), PAIR_NP | CYCLES_MULTI(30,46) +}; +static uint32_t opcode_timings_f7_mod3[8] = +{ +/* TST NOT NEG*/ + PAIR_UV | CYCLES_REG | SRCDEP_RM, INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* MUL IMUL DIV IDIV*/ + PAIR_NP | CYCLES_MULTI(11,10), PAIR_NP | CYCLES_MULTI(11,10), PAIR_NP | CYCLES_MULTI(25,41), PAIR_NP | CYCLES_MULTI(30,46) +}; +static uint32_t opcode_timings_ff[8] = +{ +/* INC DEC CALL CALL far*/ + PAIR_UV | CYCLES_RMW, PAIR_UV | CYCLES_RMW, PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(0), +/* JMP JMP far PUSH*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(2), INVALID +}; +static uint32_t opcode_timings_ff_mod3[8] = +{ +/* INC DEC CALL CALL far*/ + PAIR_UV | CYCLES_REG | SRCDEP_RM | DSTDEP_RM, PAIR_UV | CYCLES_REG | SRCDEP_RM | DSTDEP_RM, PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(0), +/* JMP JMP far PUSH*/ + PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(0), PAIR_NP | CYCLES(2), INVALID +}; + +static uint32_t opcode_timings_d8[8] = +{ +/* FADDs FMULs FCOMs FCOMPs*/ + PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), +/* FSUBs FSUBRs FDIVs FDIVRs*/ + PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(39), PAIR_FX | CYCLES(39) +}; +static uint32_t opcode_timings_d8_mod3[8] = +{ +/* FADD FMUL FCOM FCOMP*/ + PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), +/* FSUB FSUBR FDIV FDIVR*/ + PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(39), PAIR_FX | CYCLES(39) +}; + +static uint32_t opcode_timings_d9[8] = +{ +/* FLDs FSTs FSTPs*/ + PAIR_FX | CYCLES(1), INVALID, PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), +/* FLDENV FLDCW FSTENV FSTCW*/ + PAIR_NP | CYCLES(32), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(48), PAIR_NP | CYCLES(2) +}; +static uint32_t opcode_timings_d9_mod3[64] = +{ + /*FLD*/ + PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), + PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), + /*FXCH*/ + PAIR_V | CYCLES(0), PAIR_V | CYCLES(0), PAIR_V | CYCLES(0), PAIR_V | CYCLES(0), + PAIR_V | CYCLES(0), PAIR_V | CYCLES(0), PAIR_V | CYCLES(0), PAIR_V | CYCLES(0), + /*FNOP*/ + PAIR_NP | CYCLES(3), INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + /*FSTP*/ + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), +/* opFCHS opFABS*/ + PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(3), INVALID, INVALID, +/* opFTST opFXAM*/ + PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(21), INVALID, INVALID, +/* opFLD1 opFLDL2T opFLDL2E opFLDPI*/ + PAIR_NP | CYCLES(2), CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), +/* opFLDEG2 opFLDLN2 opFLDZ*/ + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(2), INVALID, +/* opF2XM1 opFYL2X opFPTAN opFPATAN*/ + PAIR_NP | CYCLES(13), PAIR_NP | CYCLES(22), PAIR_NP | CYCLES(100), PAIR_NP | CYCLES(100), +/* opFDECSTP opFINCSTP,*/ + INVALID, INVALID, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(1), +/* opFPREM opFSQRT opFSINCOS*/ + PAIR_NP | CYCLES(70), INVALID, PAIR_NP | CYCLES(70), PAIR_NP | CYCLES(50), +/* opFRNDINT opFSCALE opFSIN opFCOS*/ + PAIR_NP | CYCLES(9), PAIR_NP | CYCLES(20), PAIR_NP | CYCLES(50), PAIR_NP | CYCLES(50) +}; + +static uint32_t opcode_timings_da[8] = +{ +/* FIADDl FIMULl FICOMl FICOMPl*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), +/* FISUBl FISUBRl FIDIVl FIDIVRl*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(42), PAIR_NP | CYCLES(42) +}; +static uint32_t opcode_timings_da_mod3[8] = +{ + INVALID, INVALID, INVALID, INVALID, + INVALID, PAIR_NP | CYCLES(5), INVALID, INVALID +}; + + +static uint32_t opcode_timings_db[8] = +{ +/* FLDil FSTil FSTPil*/ + PAIR_NP | CYCLES(1), INVALID, PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), +/* FLDe FSTPe*/ + INVALID, PAIR_NP | CYCLES(3), INVALID, PAIR_NP | CYCLES(3) +}; +static uint32_t opcode_timings_db_mod3[64] = +{ + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + +/* opFNOP opFCLEX opFINIT*/ + INVALID, PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(7), PAIR_NP | CYCLES(17), +/* opFNOP opFNOP*/ + PAIR_NP | CYCLES(3), PAIR_NP | CYCLES(3), INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, + + INVALID, INVALID, INVALID, INVALID, + INVALID, INVALID, INVALID, INVALID, +}; + +static uint32_t opcode_timings_dc[8] = +{ +/* FADDd FMULd FCOMd FCOMPd*/ + PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), +/* FSUBd FSUBRd FDIVd FDIVRd*/ + PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(39), PAIR_FX | CYCLES(39) +}; +static uint32_t opcode_timings_dc_mod3[8] = +{ +/* opFADDr opFMULr*/ + PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), INVALID, INVALID, +/* opFSUBRr opFSUBr opFDIVRr opFDIVr*/ + PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(39), PAIR_FX | CYCLES(39) +}; + +static uint32_t opcode_timings_dd[8] = +{ +/* FLDd FSTd FSTPd*/ + PAIR_FX | CYCLES(1), INVALID, PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), +/* FRSTOR FSAVE FSTSW*/ + PAIR_NP | CYCLES(70), INVALID, PAIR_NP | CYCLES(127), PAIR_NP | CYCLES(2) +}; +static uint32_t opcode_timings_dd_mod3[8] = +{ +/* FFFREE FST FSTP*/ + PAIR_NP | CYCLES(3), INVALID, PAIR_NP | CYCLES(2), PAIR_NP | CYCLES(2), +/* FUCOM FUCOMP*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), INVALID, INVALID +}; + +static uint32_t opcode_timings_de[8] = +{ +/* FIADDw FIMULw FICOMw FICOMPw*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), +/* FISUBw FISUBRw FIDIVw FIDIVRw*/ + PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(4), PAIR_NP | CYCLES(42), PAIR_NP | CYCLES(42) +}; +static uint32_t opcode_timings_de_mod3[8] = +{ +/* FADD FMUL FCOMPP*/ + PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), INVALID, PAIR_FX | CYCLES(1), +/* FSUB FSUBR FDIV FDIVR*/ + PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(1), PAIR_FX | CYCLES(39), PAIR_FX | CYCLES(39) +}; + +static uint32_t opcode_timings_df[8] = +{ +/* FILDiw FISTiw FISTPiw*/ + PAIR_NP | CYCLES(1), INVALID, PAIR_NP | CYCLES(6), PAIR_NP | CYCLES(6), +/* FILDiq FBSTP FISTPiq*/ + INVALID, PAIR_NP | CYCLES(1), PAIR_NP | CYCLES(148), PAIR_NP | CYCLES(6) +}; +static uint32_t opcode_timings_df_mod3[8] = +{ + INVALID, INVALID, INVALID, INVALID, +/* FSTSW AX*/ + PAIR_NP | CYCLES(2), INVALID, INVALID, INVALID +}; + +static uint32_t opcode_timings_8x[8] = +{ + PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RMW | SRCDEP_REG, + PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RMW | SRCDEP_REG, PAIR_UV | CYCLES_RM | SRCDEP_REG +}; + +static int decode_delay; +static uint8_t last_prefix; + +static inline int COUNT(uint32_t c, int op_32) +{ + if (c & CYCLES_HAS_MULTI) + { + if (op_32 & 0x100) + return ((uintptr_t)c >> 8) & 0xff; + return (uintptr_t)c & 0xff; + } + if (!(c & PAIR_MASK)) + return c & 0xffff; + if ((c & PAIR_MASK) == PAIR_FX) + return c & 0xffff; + switch (c & CYCLES_MASK) + { + case CYCLES_REG: + return 1; + case CYCLES_RM: + return 2; + case CYCLES_RMW: + return 3; + case CYCLES_BRANCH: + return cpu_hasMMX ? 1 : 2; + } + + fatal("Illegal COUNT %08x\n", c); + + return c; +} + +void codegen_timing_pentium_block_start() +{ + u_pipe_full = decode_delay = 0; +} + +void codegen_timing_pentium_start() +{ +// decode_delay = 0; + last_prefix = 0; +} + +void codegen_timing_pentium_prefix(uint8_t prefix, uint32_t fetchdat) +{ + if (cpu_hasMMX && prefix == 0x0f) + { + /*On Pentium MMX 0fh prefix is 'free'*/ + last_prefix = prefix; + return; + } + if (cpu_hasMMX && (prefix == 0x66 || prefix == 0x67)) + { + /*On Pentium MMX 66h and 67h prefixes take 2 clocks*/ + decode_delay += 2; + last_prefix = prefix; + return; + } + if (prefix == 0x0f && (opcode & 0xf0) == 0x80) + { + /*On Pentium 0fh prefix is 'free' when used on conditional jumps*/ + last_prefix = prefix; + return; + } + /*On Pentium all prefixes take 1 cycle to decode. Decode may be shadowed + by execution of previous instructions*/ + decode_delay++; + last_prefix = prefix; +} + +void codegen_timing_pentium_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) +{ + int *timings; + int mod3 = ((fetchdat & 0xc0) == 0xc0); + int bit8 = !(opcode & 1); + + switch (last_prefix) + { + case 0x0f: + timings = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; +// pclog("timings 0f\n"); + break; + + case 0xd8: + timings = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; + opcode = (opcode >> 3) & 7; +// pclog("timings d8\n"); + break; + case 0xd9: + timings = mod3 ? opcode_timings_d9_mod3 : opcode_timings_d9; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; +// pclog("timings d9\n"); + break; + case 0xda: + timings = mod3 ? opcode_timings_da_mod3 : opcode_timings_da; + opcode = (opcode >> 3) & 7; +// pclog("timings da\n"); + break; + case 0xdb: + timings = mod3 ? opcode_timings_db_mod3 : opcode_timings_db; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; +// pclog("timings db\n"); + break; + case 0xdc: + timings = mod3 ? opcode_timings_dc_mod3 : opcode_timings_dc; + opcode = (opcode >> 3) & 7; +// pclog("timings dc\n"); + break; + case 0xdd: + timings = mod3 ? opcode_timings_dd_mod3 : opcode_timings_dd; + opcode = (opcode >> 3) & 7; +// pclog("timings dd\n"); + break; + case 0xde: + timings = mod3 ? opcode_timings_de_mod3 : opcode_timings_de; + opcode = (opcode >> 3) & 7; +// pclog("timings de\n"); + break; + case 0xdf: + timings = mod3 ? opcode_timings_df_mod3 : opcode_timings_df; + opcode = (opcode >> 3) & 7; +// pclog("timings df\n"); + break; + + default: + switch (opcode) + { + case 0x80: case 0x81: case 0x82: case 0x83: + timings = mod3 ? opcode_timings_mod3 : opcode_timings_8x; + if (!mod3) + opcode = (fetchdat >> 3) & 7; +// pclog("timings 80 %p %p %p\n", (void *)timings, (void *)opcode_timings_mod3, (void *)opcode_timings_8x); + break; + + case 0xc0: case 0xc1: case 0xd0: case 0xd1: case 0xd2: case 0xd3: + timings = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; + opcode = (fetchdat >> 3) & 7; +// pclog("timings c0\n"); + break; + + case 0xf6: + timings = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; + opcode = (fetchdat >> 3) & 7; +// pclog("timings f6\n"); + break; + case 0xf7: + timings = mod3 ? opcode_timings_f7_mod3 : opcode_timings_f7; + opcode = (fetchdat >> 3) & 7; +// pclog("timings f7\n"); + break; + case 0xff: + timings = mod3 ? opcode_timings_ff_mod3 : opcode_timings_ff; + opcode = (fetchdat >> 3) & 7; +// pclog("timings ff\n"); + break; + + default: + timings = mod3 ? opcode_timings_mod3 : opcode_timings; +// pclog("timings normal\n"); + break; + } + } + + if (decode_delay < 0) + decode_delay = 0; + + if (u_pipe_full) + { + uint8_t regmask = get_srcdep_mask(timings[opcode], fetchdat, bit8); + + if ((u_pipe_timings[u_pipe_opcode] & PAIR_MASK) == PAIR_FX && + (timings[opcode] & PAIR_MASK) != PAIR_FXCH) + goto nopair; + + if ((timings[opcode] & PAIR_MASK) == PAIR_FXCH && + (u_pipe_timings[u_pipe_opcode] & PAIR_MASK) != PAIR_FX) + goto nopair; + + if ((timings[opcode] & PAIR_V) && !(u_pipe_regmask & regmask) && !decode_delay) + { + int t1 = u_pipe_timings[u_pipe_opcode] & CYCLES_MASK; + int t2 = timings[opcode] & CYCLES_MASK; + int t_pair; + + if (t1 < 0 || t2 < 0 || t1 > CYCLES_BRANCH || t2 > CYCLES_BRANCH) + fatal("Pair out of range\n"); + + t_pair = pair_timings[t1][t2]; + if (t_pair < 1) + fatal("Illegal pair timings : t1=%i t2=%i u_opcode=%02x v_opcode=%02x\n", t1, t2, u_pipe_opcode, opcode); + +// pclog("Paired timings : t_pair=%i t1=%i t2=%i u_opcode=%02x v_opcode=%02x %08x:%08x\n", t_pair, t1, t2, u_pipe_opcode, opcode, cs, pc); + codegen_block_cycles += t_pair; + decode_delay = (-t_pair) + 1; + + /*Instruction can pair with previous*/ + u_pipe_full = 0; + return; + } +nopair: + /*Instruction can not pair with previous*/ + /*Run previous now*/ + codegen_block_cycles += COUNT(u_pipe_timings[u_pipe_opcode], u_pipe_op_32) + decode_delay; + decode_delay = (-COUNT(u_pipe_timings[u_pipe_opcode], u_pipe_op_32)) + 1; + u_pipe_full = 0; +// pclog("Evicited U-pipe timings : t1=%i u_opcode=%02x decode_delay=%i %08x:%08x\n", COUNT(u_pipe_timings[u_pipe_opcode], u_pipe_op_32), u_pipe_opcode, decode_delay, cs, pc); + } + + if ((timings[opcode] & PAIR_U) && !decode_delay) + { + /*Instruction might pair with next*/ + u_pipe_full = 1; + u_pipe_opcode = opcode; + u_pipe_timings = timings; + u_pipe_op_32 = op_32; + u_pipe_regmask = get_dstdep_mask(timings[opcode], fetchdat, bit8); + return; + } + /*Instruction can not pair and must run now*/ + + codegen_block_cycles += COUNT(timings[opcode], op_32) + decode_delay; + decode_delay = (-COUNT(timings[opcode], op_32)) + 1; +// pclog("Non-pairable timings : %08x t1=%i opcode=%02x mod3=%i decode_delay=%i %08x:%08x %08x %p %p\n", timings[opcode], COUNT(timings[opcode], op_32), opcode, mod3, decode_delay, cs, pc, opcode_timings[0x04], (void *)timings, (void *)opcode_timings); +} + +void codegen_timing_pentium_block_end() +{ + if (u_pipe_full) + { + /*Run previous now*/ + codegen_block_cycles += COUNT(u_pipe_timings[u_pipe_opcode], u_pipe_op_32) + decode_delay; + u_pipe_full = 0; + } +} + +codegen_timing_t codegen_timing_pentium = +{ + codegen_timing_pentium_start, + codegen_timing_pentium_prefix, + codegen_timing_pentium_opcode, + codegen_timing_pentium_block_start, + codegen_timing_pentium_block_end +}; diff --git a/src/codegen_timing_winchip.c b/src/codegen_timing_winchip.c new file mode 100644 index 000000000..342fbb0b6 --- /dev/null +++ b/src/codegen_timing_winchip.c @@ -0,0 +1,375 @@ +#include "ibm.h" +#include "cpu.h" +#include "x86.h" +#include "x86_ops.h" +#include "x87.h" +#include "mem.h" +#include "codegen.h" + +#define CYCLES(c) (int *)c +#define CYCLES2(c16, c32) (int *)((-1 & ~0xffff) | c16 | (c32 << 8)) + +static int *opcode_timings[256] = +{ +/*00*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), NULL, +/*10*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), +/*20*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), +/*30*/ &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), &timing_mr, &timing_mr, &timing_rm, &timing_rm, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), + +/*40*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, +/*50*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*60*/ CYCLES(11), CYCLES(9), CYCLES(7), CYCLES(9), CYCLES(4), CYCLES(4), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES2(17,25), CYCLES(1), CYCLES2(17,20), CYCLES(17), CYCLES(17), CYCLES(17), CYCLES(17), +/*70*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, + +/*80*/ &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm, &timing_rm, CYCLES(5), CYCLES(5), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(3), CYCLES(1), CYCLES(5), CYCLES(6), +/*90*/ CYCLES(1), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(0), CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(2), CYCLES(3), +/*a0*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(7), CYCLES(7), CYCLES(8), CYCLES(8), CYCLES(1), CYCLES(1), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), +/*b0*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, + +/*c0*/ CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(1), CYCLES(1), CYCLES(14), CYCLES(5), CYCLES(0), CYCLES(0), &timing_int, &timing_int, CYCLES(3), CYCLES(0), +/*d0*/ CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(15), CYCLES(14), CYCLES(2), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(5), CYCLES(14), CYCLES(14), CYCLES(16), CYCLES(16), CYCLES(3), CYCLES(3), CYCLES(17), CYCLES(3), CYCLES(14), CYCLES(14), CYCLES(14), CYCLES(14), +/*f0*/ CYCLES(4), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(4), CYCLES(2), NULL, NULL, CYCLES(2), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(3), NULL +}; + +static int *opcode_timings_mod3[256] = +{ +/*00*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), NULL, +/*10*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(2), CYCLES(3), +/*20*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(3), +/*30*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(4), CYCLES(2), + +/*40*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, +/*50*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*60*/ CYCLES(11), CYCLES(9), CYCLES(7), CYCLES(9), CYCLES(4), CYCLES(4), CYCLES(2), CYCLES(2), CYCLES(1), CYCLES2(14,25), CYCLES(1), CYCLES2(17,20), CYCLES(17), CYCLES(17), CYCLES(17), CYCLES(17), +/*70*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, + +/*80*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(5), CYCLES(5), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(2), CYCLES(1), CYCLES(2), CYCLES(1), +/*90*/ CYCLES(1), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(0), CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(2), CYCLES(3), +/*a0*/ CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(7), CYCLES(7), CYCLES(8), CYCLES(8), CYCLES(1), CYCLES(1), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), +/*b0*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, + +/*c0*/ CYCLES(4), CYCLES(4), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(1), CYCLES(1), CYCLES(14), CYCLES(5), CYCLES(0), CYCLES(0), &timing_int, &timing_int, CYCLES(3), CYCLES(0), +/*d0*/ CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(15), CYCLES(14), CYCLES(2), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*e0*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(5), CYCLES(14), CYCLES(14), CYCLES(16), CYCLES(16), CYCLES(3), CYCLES(3), CYCLES(17), CYCLES(3), CYCLES(14), CYCLES(14), CYCLES(14), CYCLES(14), +/*f0*/ CYCLES(4), CYCLES(0), CYCLES(0), CYCLES(0), CYCLES(4), CYCLES(2), NULL, NULL, CYCLES(2), CYCLES(2), CYCLES(3), CYCLES(2), CYCLES(2), CYCLES(2), CYCLES(3), NULL +}; + +static int *opcode_timings_0f[256] = +{ +/*00*/ CYCLES(20), CYCLES(11), CYCLES(11), CYCLES(10), NULL, CYCLES(195), CYCLES(7), NULL, CYCLES(1000), CYCLES(10000), NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ CYCLES(9), CYCLES(1), CYCLES(9), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, +/*70*/ NULL, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, &timing_rm, CYCLES(100), NULL, NULL, NULL, NULL, NULL, NULL, &timing_rm, &timing_rm, + +/*80*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, +/*90*/ CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), +/*a0*/ CYCLES(3), CYCLES(3), CYCLES(14), CYCLES(8), CYCLES(3), CYCLES(4), NULL, NULL, CYCLES(3), CYCLES(3), NULL, CYCLES(13), CYCLES(3), CYCLES(3), NULL, CYCLES2(18,30), +/*b0*/ CYCLES(10), CYCLES(10), CYCLES(6), CYCLES(13), CYCLES(6), CYCLES(6), CYCLES(3), CYCLES(3), NULL, NULL, CYCLES(6), CYCLES(13), CYCLES(7), CYCLES(7), CYCLES(3), CYCLES(3), + +/*c0*/ CYCLES(4), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*d0*/ NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, +/*e0*/ NULL, &timing_rm, &timing_rm, NULL, NULL, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, +/*f0*/ NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, NULL, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, &timing_rm, &timing_rm, &timing_rm, NULL, +}; +static int *opcode_timings_0f_mod3[256] = +{ +/*00*/ CYCLES(20), CYCLES(11), CYCLES(11), CYCLES(10), NULL, CYCLES(195), CYCLES(7), NULL, CYCLES(1000), CYCLES(10000), NULL, NULL, NULL, NULL, NULL, NULL, +/*10*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*20*/ CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), CYCLES(6), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*30*/ CYCLES(9), CYCLES(1), CYCLES(9), NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + +/*40*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*50*/ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/*60*/ &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, +/*70*/ NULL, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, &timing_rr, CYCLES(100), NULL, NULL, NULL, NULL, NULL, NULL, &timing_rr, &timing_rr, + +/*80*/ &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, &timing_bnt, +/*90*/ CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3), +/*a0*/ CYCLES(3), CYCLES(3), CYCLES(14), CYCLES(8), CYCLES(3), CYCLES(4), NULL, NULL, CYCLES(3), CYCLES(3), NULL, CYCLES(13), CYCLES(3), CYCLES(3), NULL, CYCLES2(18,30), +/*b0*/ CYCLES(10), CYCLES(10), CYCLES(6), CYCLES(13), CYCLES(6), CYCLES(6), CYCLES(3), CYCLES(3), NULL, NULL, CYCLES(6), CYCLES(13), CYCLES(7), CYCLES(7), CYCLES(3), CYCLES(3), + +/*c0*/ CYCLES(4), CYCLES(4), NULL, NULL, NULL, NULL, NULL, NULL, CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/*d0*/ NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, +/*e0*/ NULL, &timing_rr, &timing_rr, NULL, NULL, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, +/*f0*/ NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, NULL, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, &timing_rr, &timing_rr, &timing_rr, NULL, +}; + +static int *opcode_timings_shift[8] = +{ + CYCLES(7), CYCLES(7), CYCLES(10), CYCLES(10), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(7) +}; +static int *opcode_timings_shift_mod3[8] = +{ + CYCLES(3), CYCLES(3), CYCLES(9), CYCLES(9), CYCLES(3), CYCLES(3), CYCLES(3), CYCLES(3) +}; + +static int *opcode_timings_f6[8] = +{ + &timing_rm, NULL, &timing_mm, &timing_mm, CYCLES(13), CYCLES(14), CYCLES(16), CYCLES(19) +}; +static int *opcode_timings_f6_mod3[8] = +{ + &timing_rr, NULL, &timing_rr, &timing_rr, CYCLES(13), CYCLES(14), CYCLES(16), CYCLES(19) +}; +static int *opcode_timings_f7[8] = +{ + &timing_rm, NULL, &timing_mm, &timing_mm, CYCLES(21), CYCLES2(22,38), CYCLES2(24,40), CYCLES2(27,43) +}; +static int *opcode_timings_f7_mod3[8] = +{ + &timing_rr, NULL, &timing_rr, &timing_rr, CYCLES(21), CYCLES2(22,38), CYCLES2(24,40), CYCLES2(27,43) +}; +static int *opcode_timings_ff[8] = +{ + &timing_mm, &timing_mm, CYCLES(5), CYCLES(0), CYCLES(5), CYCLES(0), CYCLES(5), NULL +}; +static int *opcode_timings_ff_mod3[8] = +{ + &timing_rr, &timing_rr, CYCLES(5), CYCLES(0), CYCLES(5), CYCLES(0), CYCLES(5), NULL +}; + +static int *opcode_timings_d8[8] = +{ +/* FADDil FMULil FCOMil FCOMPil FSUBil FSUBRil FDIVil FDIVRil*/ + CYCLES(10), CYCLES(12), CYCLES(9), CYCLES(9), CYCLES(10), CYCLES(10), CYCLES(78), CYCLES(78) +}; +static int *opcode_timings_d8_mod3[8] = +{ +/* FADD FMUL FCOM FCOMP FSUB FSUBR FDIV FDIVR*/ + CYCLES(4), CYCLES(6), CYCLES(3), CYCLES(3), CYCLES(4), CYCLES(4), CYCLES(72), CYCLES(72) +}; + +static int *opcode_timings_d9[8] = +{ +/* FLDs FSTs FSTPs FLDENV FLDCW FSTENV FSTCW*/ + CYCLES(2), NULL, CYCLES(7), CYCLES(7), CYCLES(34), CYCLES(4), CYCLES(67), CYCLES(3) +}; +static int *opcode_timings_d9_mod3[64] = +{ + /*FLD*/ + CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), + /*FXCH*/ + CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), CYCLES(4), + /*FNOP*/ + CYCLES(7), NULL, NULL, NULL, NULL, NULL, NULL, NULL, + /*FSTP*/ + CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), CYCLES(1), +/* opFCHS opFABS opFTST opFXAM*/ + CYCLES(2), CYCLES(2), NULL, NULL, CYCLES(5), CYCLES(7), NULL, NULL, +/* opFLD1 opFLDL2T opFLDL2E opFLDPI opFLDEG2 opFLDLN2 opFLDZ*/ + CYCLES(5), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(7), CYCLES(5), NULL, +/* opF2XM1 opFYL2X opFPTAN opFPATAN opFDECSTP opFINCSTP,*/ + CYCLES(300), CYCLES(58), CYCLES(676), CYCLES(355), NULL, NULL, CYCLES(3), CYCLES(3), +/* opFPREM opFSQRT opFSINCOS opFRNDINT opFSCALE opFSIN opFCOS*/ + CYCLES(70), NULL, CYCLES(72), CYCLES(292), CYCLES(21), CYCLES(30), CYCLES(474), CYCLES(474) +}; + +static int *opcode_timings_da[8] = +{ +/* FADDil FMULil FCOMil FCOMPil FSUBil FSUBRil FDIVil FDIVRil*/ + CYCLES(10), CYCLES(12), CYCLES(9), CYCLES(9), CYCLES(10), CYCLES(10), CYCLES(78), CYCLES(78) +}; +static int *opcode_timings_da_mod3[8] = +{ + NULL, NULL, NULL, NULL, NULL, CYCLES(5), NULL, NULL +}; + + +static int *opcode_timings_db[8] = +{ +/* FLDil FSTil FSTPil FLDe FSTPe*/ + CYCLES(6), NULL, CYCLES(7), CYCLES(7), NULL, CYCLES(8), NULL, CYCLES(8) +}; +static int *opcode_timings_db_mod3[64] = +{ + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +/* opFNOP opFCLEX opFINIT opFNOP opFNOP*/ + NULL, CYCLES(7), CYCLES(18), CYCLES(27), CYCLES(7), CYCLES(7), NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, +}; + +static int *opcode_timings_dc[8] = +{ +/* opFADDd_a16 opFMULd_a16 opFCOMd_a16 opFCOMPd_a16 opFSUBd_a16 opFSUBRd_a16 opFDIVd_a16 opFDIVRd_a16*/ + CYCLES(6), CYCLES(8), CYCLES(5), CYCLES(5), CYCLES(6), CYCLES(6), CYCLES(74), CYCLES(74) +}; +static int *opcode_timings_dc_mod3[8] = +{ +/* opFADDr opFMULr opFSUBRr opFSUBr opFDIVRr opFDIVr*/ + CYCLES(4), CYCLES(6), NULL, NULL, CYCLES(4), CYCLES(4), CYCLES(72), CYCLES(72) +}; + +static int *opcode_timings_dd[8] = +{ +/* FLDd FSTd FSTPd FRSTOR FSAVE FSTSW*/ + CYCLES(2), NULL, CYCLES(8), CYCLES(8), CYCLES(131), NULL, CYCLES(154), CYCLES(5) +}; +static int *opcode_timings_dd_mod3[8] = +{ +/* FFFREE FST FSTP FUCOM FUCOMP*/ + CYCLES(3), NULL, CYCLES(1), CYCLES(1), CYCLES(3), CYCLES(3), NULL, NULL +}; + +static int *opcode_timings_de[8] = +{ +/* FADDiw FMULiw FCOMiw FCOMPiw FSUBil FSUBRil FDIVil FDIVRil*/ + CYCLES(10), CYCLES(12), CYCLES(9), CYCLES(9), CYCLES(10), CYCLES(10), CYCLES(78), CYCLES(78) +}; +static int *opcode_timings_de_mod3[8] = +{ +/* FADD FMUL FCOMPP FSUB FSUBR FDIV FDIVR*/ + CYCLES(4), CYCLES(6), NULL, CYCLES(3), CYCLES(4), CYCLES(4), CYCLES(72), CYCLES(72) +}; + +static int *opcode_timings_df[8] = +{ +/* FILDiw FISTiw FISTPiw FILDiq FBSTP FISTPiq*/ + CYCLES(6), NULL, CYCLES(7), CYCLES(7), NULL, CYCLES(8), CYCLES(172), CYCLES(8) +}; +static int *opcode_timings_df_mod3[8] = +{ +/* FFREE FST FSTP FUCOM FUCOMP*/ + CYCLES(3), NULL, CYCLES(1), CYCLES(1), CYCLES(3), CYCLES(3), NULL, NULL +}; + +static int *opcode_timings_8x[8] = +{ + &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_mr, &timing_rm +}; + +static int timing_count; +static uint8_t last_prefix; + +static inline int COUNT(int *c, int op_32) +{ + if ((uintptr_t)c <= 10000) + return (int)c; + if (((uintptr_t)c & ~0xffff) == (-1 & ~0xffff)) + { + if (op_32 & 0x100) + return ((uintptr_t)c >> 8) & 0xff; + return (uintptr_t)c & 0xff; + } + return *c; +} + +void codegen_timing_winchip_block_start() +{ +} + +void codegen_timing_winchip_start() +{ + timing_count = 0; + last_prefix = 0; +} + +void codegen_timing_winchip_prefix(uint8_t prefix, uint32_t fetchdat) +{ + timing_count += COUNT(opcode_timings[prefix], 0); + last_prefix = prefix; +} + +void codegen_timing_winchip_opcode(uint8_t opcode, uint32_t fetchdat, int op_32) +{ + int **timings; + int mod3 = ((fetchdat & 0xc0) == 0xc0); + + switch (last_prefix) + { + case 0x0f: + timings = mod3 ? opcode_timings_0f_mod3 : opcode_timings_0f; + break; + + case 0xd8: + timings = mod3 ? opcode_timings_d8_mod3 : opcode_timings_d8; + opcode = (opcode >> 3) & 7; + break; + case 0xd9: + timings = mod3 ? opcode_timings_d9_mod3 : opcode_timings_d9; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; + break; + case 0xda: + timings = mod3 ? opcode_timings_da_mod3 : opcode_timings_da; + opcode = (opcode >> 3) & 7; + break; + case 0xdb: + timings = mod3 ? opcode_timings_db_mod3 : opcode_timings_db; + opcode = mod3 ? opcode & 0x3f : (opcode >> 3) & 7; + break; + case 0xdc: + timings = mod3 ? opcode_timings_dc_mod3 : opcode_timings_dc; + opcode = (opcode >> 3) & 7; + break; + case 0xdd: + timings = mod3 ? opcode_timings_dd_mod3 : opcode_timings_dd; + opcode = (opcode >> 3) & 7; + break; + case 0xde: + timings = mod3 ? opcode_timings_de_mod3 : opcode_timings_de; + opcode = (opcode >> 3) & 7; + break; + case 0xdf: + timings = mod3 ? opcode_timings_df_mod3 : opcode_timings_df; + opcode = (opcode >> 3) & 7; + break; + + default: + switch (opcode) + { + case 0x80: case 0x81: case 0x82: case 0x83: + timings = mod3 ? opcode_timings_mod3 : opcode_timings_8x; + if (!mod3) + opcode = (fetchdat >> 3) & 7; + break; + + case 0xc0: case 0xc1: case 0xd0: case 0xd1: case 0xd2: case 0xd3: + timings = mod3 ? opcode_timings_shift_mod3 : opcode_timings_shift; + opcode = (fetchdat >> 3) & 7; + break; + + case 0xf6: + timings = mod3 ? opcode_timings_f6_mod3 : opcode_timings_f6; + opcode = (fetchdat >> 3) & 7; + break; + case 0xf7: + timings = mod3 ? opcode_timings_f7_mod3 : opcode_timings_f7; + opcode = (fetchdat >> 3) & 7; + break; + case 0xff: + timings = mod3 ? opcode_timings_ff_mod3 : opcode_timings_ff; + opcode = (fetchdat >> 3) & 7; + break; + + default: + timings = mod3 ? opcode_timings_mod3 : opcode_timings; + break; + } + } + + timing_count += COUNT(timings[opcode], op_32); + codegen_block_cycles += timing_count; +} + +void codegen_timing_winchip_block_end() +{ +} + +codegen_timing_t codegen_timing_winchip = +{ + codegen_timing_winchip_start, + codegen_timing_winchip_prefix, + codegen_timing_winchip_opcode, + codegen_timing_winchip_block_start, + codegen_timing_winchip_block_end +}; diff --git a/src/codegen_x86-64.c b/src/codegen_x86-64.c new file mode 100644 index 000000000..807224de2 --- /dev/null +++ b/src/codegen_x86-64.c @@ -0,0 +1,1247 @@ +#ifdef __amd64__ + +#include +#include "ibm.h" +#include "cpu.h" +#include "x86.h" +#include "x86_flags.h" +#include "x86_ops.h" +#include "x87.h" +#include "mem.h" + +#include "386_common.h" + +#include "codegen.h" +#include "codegen_ops.h" +#include "codegen_ops_x86-64.h" + +#ifdef __linux__ +#include +#include +#endif +#if WIN64 +#include +#endif + + +int codegen_flags_changed = 0; +int codegen_fpu_entered = 0; +int codegen_fpu_loaded_iq[8]; +int codegen_reg_loaded[8]; +x86seg *op_ea_seg; +int op_ssegs; +uint32_t op_old_pc; + +uint32_t recomp_page = -1; + +int host_reg_mapping[NR_HOST_REGS]; +int host_reg_xmm_mapping[NR_HOST_XMM_REGS]; +codeblock_t *codeblock; +codeblock_t **codeblock_hash; +int codegen_mmx_entered = 0; + +int block_current = 0; +static int block_num; +int block_pos; + +int cpu_recomp_flushes, cpu_recomp_flushes_latched; +int cpu_recomp_evicted, cpu_recomp_evicted_latched; +int cpu_recomp_reuse, cpu_recomp_reuse_latched; +int cpu_recomp_removed, cpu_recomp_removed_latched; + +static uint32_t codegen_endpc; + +int codegen_block_cycles; +static int codegen_block_ins; +static int codegen_block_full_ins; + +static uint32_t last_op32; +static x86seg *last_ea_seg; +static int last_ssegs; + +void codegen_init() +{ + int c; +#ifdef __linux__ + void *start; + size_t len; + long pagesize = sysconf(_SC_PAGESIZE); + long pagemask = ~(pagesize - 1); +#endif + +#if WIN64 + codeblock = VirtualAlloc(NULL, BLOCK_SIZE * sizeof(codeblock_t), MEM_COMMIT, PAGE_EXECUTE_READWRITE); +#else + codeblock = malloc(BLOCK_SIZE * sizeof(codeblock_t)); +#endif + codeblock_hash = malloc(HASH_SIZE * sizeof(codeblock_t *)); + + memset(codeblock, 0, BLOCK_SIZE * sizeof(codeblock_t)); + memset(codeblock_hash, 0, HASH_SIZE * sizeof(codeblock_t *)); + +#ifdef __linux__ + start = (void *)((long)codeblock & pagemask); + len = ((BLOCK_SIZE * sizeof(codeblock_t)) + pagesize) & pagemask; + if (mprotect(start, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) + { + perror("mprotect"); + exit(-1); + } +#endif +// pclog("Codegen is %p\n", (void *)pages[0xfab12 >> 12].block); +} + +void codegen_reset() +{ + memset(codeblock, 0, BLOCK_SIZE * sizeof(codeblock_t)); + memset(codeblock_hash, 0, HASH_SIZE * sizeof(codeblock_t *)); + mem_reset_page_blocks(); +} + +void dump_block() +{ + codeblock_t *block = pages[0x119000 >> 12].block; + + pclog("dump_block:\n"); + while (block) + { + uint32_t start_pc = (block->pc & 0xffc) | (block->phys & ~0xfff); + uint32_t end_pc = (block->endpc & 0xffc) | (block->phys & ~0xfff); + pclog(" %p : %08x-%08x %08x-%08x %p %p\n", (void *)block, start_pc, end_pc, block->pc, block->endpc, (void *)block->prev, (void *)block->next); + if (!block->pc) + fatal("Dead PC=0\n"); + + block = block->next; + } + pclog("dump_block done\n"); +} + +static void delete_block(codeblock_t *block) +{ +// pclog("delete_block: pc=%08x\n", block->pc); + if (block == codeblock_hash[HASH(block->phys)]) + codeblock_hash[HASH(block->phys)] = NULL; + + if (!block->pc) + fatal("Deleting deleted block\n"); + block->pc = 0; + + codeblock_tree_delete(block); + + if (block->prev) + { + block->prev->next = block->next; + if (block->next) + block->next->prev = block->prev; + } + else + { + pages[block->phys >> 12].block = block->next; + if (block->next) + block->next->prev = NULL; + else + mem_flush_write_page(block->phys, 0); + } + if (!block->page_mask2) + { + if (block->prev_2 || block->next_2) + fatal("Invalid block_2\n"); + return; + } + + if (block->prev_2) + { + block->prev_2->next_2 = block->next_2; + if (block->next_2) + block->next_2->prev_2 = block->prev_2; + } + else + { +// pclog(" pages.block_2=%p 3 %p %p\n", (void *)block->next_2, (void *)block, (void *)pages[block->phys_2 >> 12].block_2); + pages[block->phys_2 >> 12].block_2 = block->next_2; + if (block->next_2) + block->next_2->prev_2 = NULL; + else + mem_flush_write_page(block->phys_2, 0); + } +} + +void codegen_check_flush(page_t *page, uint64_t mask, uint32_t phys_addr) +{ + struct codeblock_t *block = page->block; + + while (block) + { + if (mask & block->page_mask) + { + delete_block(block); + cpu_recomp_evicted++; + } + if (block == block->next) + fatal("Broken 1\n"); + block = block->next; + } + + block = page->block_2; + + while (block) + { + if (mask & block->page_mask2) + { + delete_block(block); + cpu_recomp_evicted++; + } + if (block == block->next_2) + fatal("Broken 2\n"); + block = block->next_2; + } +} + +void codegen_block_init(uint32_t phys_addr) +{ + codeblock_t *block; + int has_evicted = 0; + page_t *page = &pages[phys_addr >> 12]; + + if (!page->block) + mem_flush_write_page(phys_addr, cs+cpu_state.pc); + + block_current = (block_current + 1) & BLOCK_MASK; + block = &codeblock[block_current]; + +// if (block->pc == 0xb00b4ff5) +// pclog("Init target block\n"); + if (block->pc != 0) + { +// pclog("Reuse block : was %08x now %08x\n", block->pc, cs+pc); + delete_block(block); + cpu_recomp_reuse++; + } + block_num = HASH(phys_addr); + codeblock_hash[block_num] = &codeblock[block_current]; + block->ins = 0; + block->pc = cs + cpu_state.pc; + block->_cs = cs; + block->pnt = block_current; + block->phys = phys_addr; + block->use32 = use32; + block->stack32 = stack32; + block->next = block->prev = NULL; + + block_pos = BLOCK_GPF_OFFSET; +#if WIN64 + addbyte(0x48); /*XOR RCX, RCX*/ + addbyte(0x31); + addbyte(0xc9); + addbyte(0x31); /*XOR EDX, EDX*/ + addbyte(0xd2); +#else + addbyte(0x48); /*XOR RDI, RDI*/ + addbyte(0x31); + addbyte(0xff); + addbyte(0x31); /*XOR ESI, ESI*/ + addbyte(0xf6); +#endif + call(block, (uintptr_t)x86gpf); + while (block_pos < BLOCK_EXIT_OFFSET) + addbyte(0x90); /*NOP*/ + block_pos = BLOCK_EXIT_OFFSET; /*Exit code*/ + addbyte(0x48); /*ADDL $40,%rsp*/ + addbyte(0x83); + addbyte(0xC4); + addbyte(0x28); + addbyte(0x41); /*POP R15*/ + addbyte(0x5f); + addbyte(0x41); /*POP R14*/ + addbyte(0x5e); + addbyte(0x41); /*POP R13*/ + addbyte(0x5d); + addbyte(0x41); /*POP R12*/ + addbyte(0x5c); + addbyte(0x5f); /*POP RDI*/ + addbyte(0x5e); /*POP RSI*/ + addbyte(0x5d); /*POP RBP*/ + addbyte(0x5b); /*POP RDX*/ + addbyte(0xC3); /*RET*/ + cpu_block_end = 0; + block_pos = 0; /*Entry code*/ + addbyte(0x53); /*PUSH RBX*/ + addbyte(0x55); /*PUSH RBP*/ + addbyte(0x56); /*PUSH RSI*/ + addbyte(0x57); /*PUSH RDI*/ + addbyte(0x41); /*PUSH R12*/ + addbyte(0x54); + addbyte(0x41); /*PUSH R13*/ + addbyte(0x55); + addbyte(0x41); /*PUSH R14*/ + addbyte(0x56); + addbyte(0x41); /*PUSH R15*/ + addbyte(0x57); + addbyte(0x48); /*SUBL $40,%rsp*/ + addbyte(0x83); + addbyte(0xEC); + addbyte(0x28); + addbyte(0x48); /*MOVL EBP, &EAX*/ + addbyte(0xBD); + addquad((uint64_t)&EAX); + +// pclog("New block %i for %08X %03x\n", block_current, cs+pc, block_num); + + last_op32 = -1; + last_ea_seg = NULL; + last_ssegs = -1; + + codegen_block_cycles = 0; + codegen_timing_block_start(); + + codegen_block_ins = 0; + codegen_block_full_ins = 0; + + recomp_page = phys_addr & ~0xfff; + + codegen_flags_changed = 0; + codegen_fpu_entered = 0; + codegen_mmx_entered = 0; + + codegen_fpu_loaded_iq[0] = codegen_fpu_loaded_iq[1] = codegen_fpu_loaded_iq[2] = codegen_fpu_loaded_iq[3] = + codegen_fpu_loaded_iq[4] = codegen_fpu_loaded_iq[5] = codegen_fpu_loaded_iq[6] = codegen_fpu_loaded_iq[7] = 0; + + _ds.checked = _es.checked = _fs.checked = _gs.checked = (cr0 & 1) ? 0 : 1; + + codegen_reg_loaded[0] = codegen_reg_loaded[1] = codegen_reg_loaded[2] = codegen_reg_loaded[3] = + codegen_reg_loaded[4] = codegen_reg_loaded[5] = codegen_reg_loaded[6] = codegen_reg_loaded[7] = 0; +} + +void codegen_block_remove() +{ + codeblock_t *block = &codeblock[block_current]; +//if ((block->phys & ~0xfff) == 0x119000) pclog("codegen_block_remove %08x\n", block->pc); +// if (block->pc == 0xb00b4ff5) +// pclog("Remove target block\n"); + codeblock_hash[block_num] = NULL; + block->pc = 0;//xffffffff; + cpu_recomp_removed++; +// pclog("Remove block %i\n", block_num); + recomp_page = -1; +} + +void codegen_block_end() +{ + codeblock_t *block = &codeblock[block_current]; + codeblock_t *block_prev = pages[block->phys >> 12].block; + uint32_t start_pc = (block->pc & 0xffc) | (block->phys & ~0xfff); + uint32_t end_pc = ((codegen_endpc + 3) & 0xffc) | (block->phys & ~0xfff); + + block->endpc = codegen_endpc; + +// if (block->pc == 0xb00b4ff5) +// pclog("End target block\n"); + + if (block_prev) + { + block->next = block_prev; + block_prev->prev = block; + pages[block->phys >> 12].block = block; + } + else + { + block->next = NULL; + pages[block->phys >> 12].block = block; + } + + if (block->next) + { +// pclog(" next->pc=%08x\n", block->next->pc); + if (!block->next->pc) + fatal("block->next->pc=0 %p %p %x %x\n", (void *)block->next, (void *)codeblock, block_current, block_pos); + } + + block->page_mask = 0; + start_pc = block->pc & 0xffc; + start_pc &= ~PAGE_MASK_MASK; + end_pc = ((block->endpc & 0xffc) + PAGE_MASK_MASK) & ~PAGE_MASK_MASK; + if (end_pc > 0xfff || end_pc < start_pc) + end_pc = 0xfff; + start_pc >>= PAGE_MASK_SHIFT; + end_pc >>= PAGE_MASK_SHIFT; + +// pclog("block_end: %08x %08x\n", start_pc, end_pc); + for (; start_pc <= end_pc; start_pc++) + { + block->page_mask |= ((uint64_t)1 << start_pc); +// pclog(" %08x %llx\n", start_pc, block->page_mask); + } + + pages[block->phys >> 12].code_present_mask |= block->page_mask; + + block->phys_2 = -1; + block->page_mask2 = 0; + block->next_2 = block->prev_2 = NULL; + if ((block->pc ^ block->endpc) & ~0xfff) + { + block->phys_2 = get_phys_noabrt(block->endpc); + if (block->phys_2 != -1) + { +// pclog("start block - %08x %08x %p %p %p %08x\n", block->pc, block->endpc, (void *)block, (void *)block->next_2, (void *)pages[block->phys_2 >> 12].block_2, block->phys_2); + + if (pages[block->phys_2 >> 12].block_2 == block) + fatal("Block same\n"); + + block_prev = pages[block->phys_2 >> 12].block_2; + + if (block_prev) + { + block->next_2 = block_prev; + block_prev->prev_2 = block; + pages[block->phys_2 >> 12].block_2 = block; +// pclog(" pages.block_2=%p\n", (void *)block); + } + else + { + block->next_2 = NULL; + pages[block->phys_2 >> 12].block_2 = block; +// pclog(" pages.block_2=%p 2\n", (void *)block); + } + + start_pc = 0; + end_pc = (block->endpc & 0xfff) >> PAGE_MASK_SHIFT; + for (; start_pc <= end_pc; start_pc++) + block->page_mask2 |= ((uint64_t)1 << start_pc); + + if (!pages[block->phys_2 >> 12].block_2) + mem_flush_write_page(block->phys_2, block->endpc); +// pclog("New block - %08x %08x %p %p phys %08x %08x %016llx\n", block->pc, block->endpc, (void *)block, (void *)block->next_2, block->phys, block->phys_2, block->page_mask2); + if (!block->page_mask2) + fatal("!page_mask2\n"); + if (block->next_2) + { +// pclog(" next_2->pc=%08x\n", block->next_2->pc); + if (!block->next_2->pc) + fatal("block->next_2->pc=0 %p\n", (void *)block->next_2); + } + } + } + +// pclog("block_end: %08x %08x %016llx\n", block->pc, block->endpc, block->page_mask); + + codegen_timing_block_end(); + + if (codegen_block_cycles) + { + addbyte(0x81); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2c); + addbyte(0x25); + addlong((uint32_t)&cycles); + addlong((uint32_t)codegen_block_cycles); + } + if (codegen_block_ins) + { + addbyte(0x81); /*ADD $codegen_block_ins,ins*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&cpu_recomp_ins); + addlong(codegen_block_ins); + } +#if 0 + if (codegen_block_full_ins) + { + addbyte(0x81); /*ADD $codegen_block_ins,ins*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&cpu_recomp_full_ins); + addlong(codegen_block_full_ins); + } +#endif + addbyte(0x48); /*ADDL $40,%rsp*/ + addbyte(0x83); + addbyte(0xC4); + addbyte(0x28); + addbyte(0x41); /*POP R15*/ + addbyte(0x5f); + addbyte(0x41); /*POP R14*/ + addbyte(0x5e); + addbyte(0x41); /*POP R13*/ + addbyte(0x5d); + addbyte(0x41); /*POP R12*/ + addbyte(0x5c); + addbyte(0x5f); /*POP RDI*/ + addbyte(0x5e); /*POP RSI*/ + addbyte(0x5d); /*POP RBP*/ + addbyte(0x5b); /*POP RDX*/ + addbyte(0xC3); /*RET*/ + + if (block_pos > BLOCK_GPF_OFFSET) + fatal("Over limit!\n"); +// pclog("End block %i\n", block_num); + + recomp_page = -1; + + codeblock_tree_add(block); +} + +void codegen_flush() +{ + return; +} + +static int opcode_needs_tempc[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /*00*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*10*/ + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, /*20*/ + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, /*30*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*40*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*60*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*70*/ + + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, /*80*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*90*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*a0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*b0*/ + + 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*c0*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*d0*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*e0*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*f0*/ +}; + +static int opcode_conditional_jump[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /*00*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*10*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*30*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*40*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*60*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*70*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*80*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*90*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*a0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*b0*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*c0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*d0*/ + 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*e0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*f0*/ +}; + +static int opcode_modrm[256] = +{ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*00*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*10*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*20*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*30*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*40*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, /*60*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*70*/ + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*80*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*90*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*a0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*b0*/ + + 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, /*c0*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*d0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*e0*/ + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, /*f0*/ +}; +int opcode_0f_modrm[256] = +{ + 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*00*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*10*/ + 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*30*/ + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*40*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, /*60*/ + 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, /*70*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*80*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*90*/ + 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, /*a0*/ + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, /*b0*/ + + 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, /*c0*/ + 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, /*d0*/ + 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, /*e0*/ + 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0 /*f0*/ +}; + +void codegen_debug() +{ + if (output) + { + pclog("At %04x(%08x):%04x %04x(%08x):%04x es=%08x EAX=%08x BX=%04x ECX=%08x BP=%04x EDX=%08x EDI=%08x\n", CS, cs, cpu_state.pc, SS, ss, ESP, es,EAX, BX,ECX,BP, EDX,EDI); + } +} + +static x86seg *codegen_generate_ea_16_long(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc) +{ + if (!mod && rm == 6) + { + addbyte(0xC7); /*MOVL $0,(ssegs)*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&eaaddr); + addlong((fetchdat >> 8) & 0xffff); + (*op_pc) += 2; + } + else + { + int base_reg, index_reg; + + switch (rm) + { + case 0: case 1: case 7: + base_reg = LOAD_REG_W(REG_BX); + break; + case 2: case 3: case 6: + base_reg = LOAD_REG_W(REG_BP); + break; + case 4: + base_reg = LOAD_REG_W(REG_SI); + break; + case 5: + base_reg = LOAD_REG_W(REG_DI); + break; + } + if (!(rm & 4)) + { + if (rm & 1) + index_reg = LOAD_REG_W(REG_DI); + else + index_reg = LOAD_REG_W(REG_SI); + } + base_reg &= 7; + index_reg &= 7; + + switch (mod) + { + case 0: + if (rm & 4) + { + addbyte(0x41); /*MOVZX EAX, base_reg*/ + addbyte(0x0f); + addbyte(0xb7); + addbyte(0xc0 | base_reg); + } + else + { + addbyte(0x67); /*LEA EAX, base_reg+index_reg*/ + addbyte(0x43); + addbyte(0x8d); + if (base_reg == 5) + { + addbyte(0x44); + addbyte(base_reg | (index_reg << 3)); + addbyte(0); + } + else + { + addbyte(0x04); + addbyte(base_reg | (index_reg << 3)); + } + } + break; + case 1: + if (rm & 4) + { + addbyte(0x67); /*LEA EAX, base_reg+imm8*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x40 | base_reg); + addbyte((fetchdat >> 8) & 0xff); + } + else + { + addbyte(0x67); /*LEA EAX, base_reg+index_reg+imm8*/ + addbyte(0x43); + addbyte(0x8d); + addbyte(0x44); + addbyte(base_reg | (index_reg << 3)); + addbyte((fetchdat >> 8) & 0xff); + } + (*op_pc)++; + break; + case 2: + if (rm & 4) + { + addbyte(0x67); /*LEA EAX, base_reg+imm8*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x80 | base_reg); + addlong((fetchdat >> 8) & 0xffff); + } + else + { + addbyte(0x67); /*LEA EAX, base_reg+index_reg+imm16*/ + addbyte(0x43); + addbyte(0x8d); + addbyte(0x84); + addbyte(base_reg | (index_reg << 3)); + addlong((fetchdat >> 8) & 0xffff); + } + (*op_pc) += 2; + break; + + } + if (mod || !(rm & 4)) + { + addbyte(0x25); /*ANDL $0xffff, %eax*/ + addlong(0xffff); + } + addbyte(0x89); /*MOV eaaddr, EAX*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&eaaddr); + + if (mod1seg[rm] == &ss && !op_ssegs) + op_ea_seg = &_ss; + } + return op_ea_seg; +} +//#if 0 +static x86seg *codegen_generate_ea_32_long(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, int stack_offset) +{ + uint32_t new_eaaddr; + + if (rm == 4) + { + uint8_t sib = fetchdat >> 8; + int base_reg = -1, index_reg = -1; + + (*op_pc)++; + + if (mod || (sib & 7) != 5) + base_reg = LOAD_REG_L(sib & 7) & 7; + + if (((sib >> 3) & 7) != 4) + index_reg = LOAD_REG_L((sib >> 3) & 7) & 7; + + if (index_reg == -1) + { + switch (mod) + { + case 0: + if ((sib & 7) == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0xb8); /*MOV EAX, imm32*/ + addlong(new_eaaddr); + (*op_pc) += 4; + } + else + { + addbyte(0x44); /*MOV EAX, base_reg*/ + addbyte(0x89); + addbyte(0xc0 | (base_reg << 3)); + } + break; + case 1: + addbyte(0x67); /*LEA EAX, imm8+base_reg*/ + addbyte(0x41); + addbyte(0x8d); + if (base_reg == 4) + { + addbyte(0x44); + addbyte(0x24); + } + else + { + addbyte(0x40 | base_reg); + } + addbyte((fetchdat >> 16) & 0xff); + (*op_pc)++; + break; + case 2: + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0x67); /*LEA EAX, imm32+base_reg*/ + addbyte(0x41); + addbyte(0x8d); + if (base_reg == 4) + { + addbyte(0x84); + addbyte(0x24); + } + else + { + addbyte(0x80 | base_reg); + } + addlong(new_eaaddr); + (*op_pc) += 4; + break; + } + } + else + { + switch (mod) + { + case 0: + if ((sib & 7) == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + if (sib >> 6) + { + addbyte(0x67); /*LEA EAX, imm32+index_reg*scale*/ + addbyte(0x42); + addbyte(0x8d); + addbyte(0x04); + addbyte(0x05 | (sib & 0xc0) | (index_reg << 3)); + addlong(new_eaaddr); + } + else + { + addbyte(0x67); /*LEA EAX, imm32+index_reg*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x80 | index_reg); + addlong(new_eaaddr); + } + (*op_pc) += 4; + } + else + { + addbyte(0x67); /*LEA EAX, base_reg+index_reg*scale*/ + addbyte(0x43); + addbyte(0x8d); + if (base_reg == 5) + { + addbyte(0x44); + addbyte(base_reg | (index_reg << 3) | (sib & 0xc0)); + addbyte(0); + } + else + { + addbyte(0x04); + addbyte(base_reg | (index_reg << 3) | (sib & 0xc0)); + } + } + break; + case 1: + addbyte(0x67); /*LEA EAX, imm8+base_reg+index_reg*scale*/ + addbyte(0x43); + addbyte(0x8d); + addbyte(0x44); + addbyte(base_reg | (index_reg << 3) | (sib & 0xc0)); + addbyte((fetchdat >> 16) & 0xff); + (*op_pc)++; + break; + case 2: + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0x67); /*LEA EAX, imm32+base_reg+index_reg*scale*/ + addbyte(0x43); + addbyte(0x8d); + addbyte(0x84); + addbyte(base_reg | (index_reg << 3) | (sib & 0xc0)); + addlong(new_eaaddr); + (*op_pc) += 4; + break; + } + } + if (stack_offset && (sib & 7) == 4 && (mod || (sib & 7) != 5)) /*ESP*/ + { + addbyte(0x05); + addlong(stack_offset); + } + if (((sib & 7) == 4 || (mod && (sib & 7) == 5)) && !op_ssegs) + op_ea_seg = &_ss; + + addbyte(0x89); /*MOV eaaddr, EAX*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&eaaddr); + } + else + { + int base_reg; + + if (!mod && rm == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0xC7); /*MOVL $new_eaaddr,(eaaddr)*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&eaaddr); + addlong(new_eaaddr); + (*op_pc) += 4; + return op_ea_seg; + } + base_reg = LOAD_REG_L(rm) & 7; + if (mod) + { + if (rm == 5 && !op_ssegs) + op_ea_seg = &_ss; + if (mod == 1) + { + addbyte(0x67); /*LEA EAX, base_reg+imm8*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x40 | base_reg); + addbyte((fetchdat >> 8) & 0xff); + (*op_pc)++; + } + else + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0x67); /*LEA EAX, base_reg+imm32*/ + addbyte(0x41); + addbyte(0x8d); + addbyte(0x80 | base_reg); + addlong(new_eaaddr); + (*op_pc) += 4; + } + addbyte(0x89); /*MOV eaaddr, EAX*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&eaaddr); + } + else + { + addbyte(0x44); /*MOV eaaddr, base_reg*/ + addbyte(0x89); + addbyte(4 | (base_reg << 3)); + addbyte(0x25); + addlong((uint32_t)&eaaddr); + } + } + return op_ea_seg; +} +//#endif +void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_pc, uint32_t old_pc) +{ + codeblock_t *block = &codeblock[block_current]; + uint32_t op_32 = use32; + uint32_t op_pc = new_pc; + OpFn *op_table = x86_dynarec_opcodes; + RecompOpFn *recomp_op_table = recomp_opcodes; + int opcode_shift = 0; + int opcode_mask = 0x3ff; + int over = 0; + int pc_off = 0; + int test_modrm = 1; + int c; + + op_ea_seg = &_ds; + op_ssegs = 0; + op_old_pc = old_pc; + + for (c = 0; c < NR_HOST_REGS; c++) + host_reg_mapping[c] = -1; + for (c = 0; c < NR_HOST_XMM_REGS; c++) + host_reg_xmm_mapping[c] = -1; + + codegen_timing_start(); + + while (!over) + { + switch (opcode) + { + case 0x0f: + op_table = x86_dynarec_opcodes_0f; + recomp_op_table = recomp_opcodes_0f; + over = 1; + break; + + case 0x26: /*ES:*/ + op_ea_seg = &_es; + op_ssegs = 1; + break; + case 0x2e: /*CS:*/ + op_ea_seg = &_cs; + op_ssegs = 1; + break; + case 0x36: /*SS:*/ + op_ea_seg = &_ss; + op_ssegs = 1; + break; + case 0x3e: /*DS:*/ + op_ea_seg = &_ds; + op_ssegs = 1; + break; + case 0x64: /*FS:*/ + op_ea_seg = &_fs; + op_ssegs = 1; + break; + case 0x65: /*GS:*/ + op_ea_seg = &_gs; + op_ssegs = 1; + break; + + case 0x66: /*Data size select*/ + op_32 = ((use32 & 0x100) ^ 0x100) | (op_32 & 0x200); + break; + case 0x67: /*Address size select*/ + op_32 = ((use32 & 0x200) ^ 0x200) | (op_32 & 0x100); + break; + + case 0xd8: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_d8_a32 : x86_dynarec_opcodes_d8_a16; + recomp_op_table = recomp_opcodes_d8; + opcode_shift = 3; + opcode_mask = 0x1f; + over = 1; + pc_off = -1; + test_modrm = 0; + break; + case 0xd9: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_d9_a32 : x86_dynarec_opcodes_d9_a16; + recomp_op_table = recomp_opcodes_d9; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + break; + case 0xda: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_da_a32 : x86_dynarec_opcodes_da_a16; + recomp_op_table = recomp_opcodes_da; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + break; + case 0xdb: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_db_a32 : x86_dynarec_opcodes_db_a16; + recomp_op_table = recomp_opcodes_db; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + break; + case 0xdc: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_dc_a32 : x86_dynarec_opcodes_dc_a16; + recomp_op_table = recomp_opcodes_dc; + opcode_shift = 3; + opcode_mask = 0x1f; + over = 1; + pc_off = -1; + test_modrm = 0; + break; + case 0xdd: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_dd_a32 : x86_dynarec_opcodes_dd_a16; + recomp_op_table = recomp_opcodes_dd; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + break; + case 0xde: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_de_a32 : x86_dynarec_opcodes_de_a16; + recomp_op_table = recomp_opcodes_de; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + break; + case 0xdf: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_df_a32 : x86_dynarec_opcodes_df_a16; + recomp_op_table = recomp_opcodes_df; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + break; + + case 0xf0: /*LOCK*/ + break; + + default: + goto generate_call; + } + fetchdat = fastreadl(cs + op_pc); + codegen_timing_prefix(opcode, fetchdat); + if (abrt) + return; + opcode = fetchdat & 0xff; + if (!pc_off) + fetchdat >>= 8; + op_pc++; + } + +generate_call: + codegen_timing_opcode(opcode, fetchdat, op_32); + + if ((op_table == x86_dynarec_opcodes && + ((opcode & 0xf0) == 0x70 || (opcode & 0xfc) == 0xe0 || opcode == 0xc2 || + (opcode & 0xfe) == 0xca || (opcode & 0xfc) == 0xcc || (opcode & 0xfc) == 0xe8 || + (opcode == 0xff && ((fetchdat & 0x38) >= 0x10 && (fetchdat & 0x38) < 0x30))) || + (op_table == x86_dynarec_opcodes_0f && ((opcode & 0xf0) == 0x80)))) + { + /*Opcode is likely to cause block to exit, update cycle count*/ + if (codegen_block_cycles) + { + addbyte(0x81); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2c); + addbyte(0x25); + addlong((uint32_t)&cycles); + addlong((uint32_t)codegen_block_cycles); + codegen_block_cycles = 0; + } + if (codegen_block_ins) + { + addbyte(0x81); /*ADD $codegen_block_ins,ins*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&cpu_recomp_ins); + addlong(codegen_block_ins); + codegen_block_ins = 0; + } +#if 0 + if (codegen_block_full_ins) + { + addbyte(0x81); /*ADD $codegen_block_ins,ins*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&cpu_recomp_full_ins); + addlong(codegen_block_full_ins); + codegen_block_full_ins = 0; + } +#endif + } + if (recomp_op_table && recomp_op_table[(opcode | op_32) & 0x1ff]) + { + uint32_t new_pc = recomp_op_table[(opcode | op_32) & 0x1ff](opcode, fetchdat, op_32, op_pc, block); + if (new_pc) + { + if (new_pc != -1) + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, new_pc); + + codegen_block_ins++; + block->ins++; + codegen_block_full_ins++; + codegen_endpc = (cs + cpu_state.pc) + 8; + + return; + } + } + + op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask]; +// if (output) +// pclog("Generate call at %08X %02X %08X %02X %08X %08X %08X %08X %08X %02X %02X %02X %02X\n", &codeblock[block_current][block_pos], opcode, new_pc, ram[old_pc], EAX, EBX, ECX, EDX, ESI, ram[0x7bd2+6],ram[0x7bd2+7],ram[0x7bd2+8],ram[0x7bd2+9]); + if (opcode_needs_tempc[opcode]) + { + addbyte(0x8b); /*MOVL (flags), %eax*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&flags); + addbyte(0x83); /*ANDL $1, %eax*/ + addbyte(0xe0); + addbyte(0x01); + addbyte(0x89); /*MOVL %eax, (tempc)*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&tempc); + } + if (op_ssegs != last_ssegs) + { + last_ssegs = op_ssegs; + addbyte(0xC7); /*MOVL $0,(ssegs)*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&ssegs); + addlong(op_ssegs); + } +//#if 0 + if ((!test_modrm || + (op_table == x86_dynarec_opcodes && opcode_modrm[opcode]) || + (op_table == x86_dynarec_opcodes_0f && opcode_0f_modrm[opcode]))/* && !(op_32 & 0x200)*/) + { + int stack_offset = 0; + + if (op_table == x86_dynarec_opcodes && opcode == 0x8f) /*POP*/ + stack_offset = (op_32 & 0x100) ? 4 : 2; + + mod = (fetchdat >> 6) & 3; + reg = (fetchdat >> 3) & 7; + rm = fetchdat & 7; + + addbyte(0xC7); /*MOVL $mod,(mod)*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&mod); + addlong(mod); + addbyte(0xC7); /*MOVL $reg,(reg)*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)®); + addlong(reg); + addbyte(0xC7); /*MOVL $rm,(rm)*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&rm); + addlong(rm); + + op_pc += pc_off; + if (mod != 3 && !(op_32 & 0x200)) + op_ea_seg = codegen_generate_ea_16_long(op_ea_seg, fetchdat, op_ssegs, &op_pc); + if (mod != 3 && (op_32 & 0x200)) + op_ea_seg = codegen_generate_ea_32_long(op_ea_seg, fetchdat, op_ssegs, &op_pc, stack_offset); + op_pc -= pc_off; + } +//#endif +// if (op_ea_seg != last_ea_seg) +// { +// last_ea_seg = op_ea_seg; + addbyte(0xC7); /*MOVL $&_ds,(ea_seg)*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&ea_seg); + addlong((uint32_t)op_ea_seg); +// } + + + addbyte(0xC7); /*MOVL [pc],new_pc*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.pc - (uintptr_t)&cpu_state); + addlong(op_pc + pc_off); + addbyte(0xC7); /*MOVL $old_pc,(oldpc)*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&oldpc); + addlong(old_pc); + if (op_32 != last_op32) + { + last_op32 = op_32; + addbyte(0xC7); /*MOVL $use32,(op32)*/ + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)&op32); + addlong(op_32); + } + + load_param_1_32(block, fetchdat); + call(block, (uintptr_t)op); + + codegen_block_ins++; + + block->ins++; + + addbyte(0x85); /*OR %eax, %eax*/ + addbyte(0xc0); + addbyte(0x0F); addbyte(0x85); /*JNZ 0*/ + addlong((uint32_t)&block->data[BLOCK_EXIT_OFFSET] - (uint32_t)(&block->data[block_pos + 4])); + +// call(block, codegen_debug); + + codegen_endpc = (cs + cpu_state.pc) + 8; +} + +void codegen_check_abrt() +{ + codeblock_t *block = &codeblock[block_current]; +// pclog("Generate check abrt at %08X\n", &codeblock[block_current][block_pos]); + addbyte(0xf7); addbyte(0x04); /*TESTL $-1, (abrt)*/ + addbyte(0x25); + addlong((uint32_t)&abrt); addlong(0xffffffff); + addbyte(0x0F); addbyte(0x85); /*JNZ 0*/ + addlong((uint32_t)&block->data[BLOCK_EXIT_OFFSET] - (uint32_t)(&block->data[block_pos + 4])); +} + +#endif diff --git a/src/codegen_x86-64.h b/src/codegen_x86-64.h new file mode 100644 index 000000000..29c09ac4f --- /dev/null +++ b/src/codegen_x86-64.h @@ -0,0 +1,21 @@ +#define BLOCK_SIZE 0x4000 +#define BLOCK_MASK 0x3fff +#define BLOCK_START 0 + +#define HASH_SIZE 0x20000 +#define HASH_MASK 0x1ffff + +#define HASH(l) ((l) & 0x1ffff) + +#define BLOCK_EXIT_OFFSET 0x7e0 +#define BLOCK_GPF_OFFSET (BLOCK_EXIT_OFFSET - 20) + +enum +{ + OP_RET = 0xc3 +}; + +#define NR_HOST_REGS 3 +extern int host_reg_mapping[NR_HOST_REGS]; +#define NR_HOST_XMM_REGS 7 +extern int host_reg_xmm_mapping[NR_HOST_XMM_REGS]; diff --git a/src/codegen_x86.c b/src/codegen_x86.c new file mode 100644 index 000000000..a1d1778de --- /dev/null +++ b/src/codegen_x86.c @@ -0,0 +1,1048 @@ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 + +#include +#include "ibm.h" +#include "cpu.h" +#include "x86.h" +#include "x86_flags.h" +#include "x86_ops.h" +#include "x87.h" +#include "mem.h" + +#include "386_common.h" + +#include "codegen.h" +#include "codegen_ops.h" +#include "codegen_ops_x86.h" + +#ifdef __linux__ +#include +#include +#endif +#if defined WIN32 || defined _WIN32 || defined _WIN32 +#include +#endif + +int mmx_ebx_ecx_loaded; +int codegen_flags_changed = 0; +int codegen_fpu_entered = 0; +int codegen_mmx_entered = 0; +int codegen_fpu_loaded_iq[8]; +x86seg *op_ea_seg; +int op_ssegs; +uint32_t op_old_pc; + +uint32_t recomp_page = -1; + +int host_reg_mapping[NR_HOST_REGS]; +int host_reg_xmm_mapping[NR_HOST_XMM_REGS]; +codeblock_t *codeblock; +codeblock_t **codeblock_hash; + + +int block_current = 0; +static int block_num; +int block_pos; + +int cpu_recomp_flushes, cpu_recomp_flushes_latched; +int cpu_recomp_evicted, cpu_recomp_evicted_latched; +int cpu_recomp_reuse, cpu_recomp_reuse_latched; +int cpu_recomp_removed, cpu_recomp_removed_latched; + +static uint32_t codegen_endpc; + +int codegen_block_cycles; +static int codegen_block_ins; +static int codegen_block_full_ins; + +static uint32_t last_op32; +static x86seg *last_ea_seg; +static int last_ssegs; + +void codegen_init() +{ + int c; +#ifdef __linux__ + void *start; + size_t len; + long pagesize = sysconf(_SC_PAGESIZE); + long pagemask = ~(pagesize - 1); +#endif + +#if defined WIN32 || defined _WIN32 || defined _WIN32 + codeblock = VirtualAlloc(NULL, BLOCK_SIZE * sizeof(codeblock_t), MEM_COMMIT, PAGE_EXECUTE_READWRITE); +#else + codeblock = malloc(BLOCK_SIZE * sizeof(codeblock_t)); +#endif + codeblock_hash = malloc(HASH_SIZE * sizeof(codeblock_t *)); + + memset(codeblock, 0, BLOCK_SIZE * sizeof(codeblock_t)); + memset(codeblock_hash, 0, HASH_SIZE * sizeof(codeblock_t *)); + +#ifdef __linux__ + start = (void *)((long)codeblock & pagemask); + len = ((BLOCK_SIZE * sizeof(codeblock_t)) + pagesize) & pagemask; + if (mprotect(start, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) + { + perror("mprotect"); + exit(-1); + } +#endif +// pclog("Codegen is %p\n", (void *)pages[0xfab12 >> 12].block); +} + +void codegen_reset() +{ + memset(codeblock, 0, BLOCK_SIZE * sizeof(codeblock_t)); + memset(codeblock_hash, 0, HASH_SIZE * sizeof(codeblock_t *)); + mem_reset_page_blocks(); +} + +void dump_block() +{ + codeblock_t *block = pages[0x119000 >> 12].block; + + pclog("dump_block:\n"); + while (block) + { + uint32_t start_pc = (block->pc & 0xffc) | (block->phys & ~0xfff); + uint32_t end_pc = (block->endpc & 0xffc) | (block->phys & ~0xfff); + pclog(" %p : %08x-%08x %08x-%08x %p %p\n", (void *)block, start_pc, end_pc, block->pc, block->endpc, (void *)block->prev, (void *)block->next); + if (!block->pc) + fatal("Dead PC=0\n"); + + block = block->next; + } + pclog("dump_block done\n"); +} + +static void delete_block(codeblock_t *block) +{ +// pclog("delete_block: pc=%08x\n", block->pc); + if (block == codeblock_hash[HASH(block->phys)]) + codeblock_hash[HASH(block->phys)] = NULL; + + if (!block->pc) + fatal("Deleting deleted block\n"); + block->pc = 0; + + codeblock_tree_delete(block); + + if (block->prev) + { + block->prev->next = block->next; + if (block->next) + block->next->prev = block->prev; + } + else + { + pages[block->phys >> 12].block = block->next; + if (block->next) + block->next->prev = NULL; + else + mem_flush_write_page(block->phys, 0); + } + if (!block->page_mask2) + { + if (block->prev_2 || block->next_2) + fatal("Invalid block_2\n"); + return; + } + + if (block->prev_2) + { + block->prev_2->next_2 = block->next_2; + if (block->next_2) + block->next_2->prev_2 = block->prev_2; + } + else + { +// pclog(" pages.block_2=%p 3 %p %p\n", (void *)block->next_2, (void *)block, (void *)pages[block->phys_2 >> 12].block_2); + pages[block->phys_2 >> 12].block_2 = block->next_2; + if (block->next_2) + block->next_2->prev_2 = NULL; + else + mem_flush_write_page(block->phys_2, 0); + } +} + +void codegen_check_flush(page_t *page, uint64_t mask, uint32_t phys_addr) +{ + struct codeblock_t *block = page->block; + + while (block) + { + if (mask & block->page_mask) + { + delete_block(block); + cpu_recomp_evicted++; + } + if (block == block->next) + fatal("Broken 1\n"); + block = block->next; + } + + block = page->block_2; + + while (block) + { + if (mask & block->page_mask2) + { + delete_block(block); + cpu_recomp_evicted++; + } + if (block == block->next_2) + fatal("Broken 2\n"); + block = block->next_2; + } +} + +void codegen_block_init(uint32_t phys_addr) +{ + codeblock_t *block; + int has_evicted = 0; + page_t *page = &pages[phys_addr >> 12]; + + if (!page->block) + mem_flush_write_page(phys_addr, cs+cpu_state.pc); + + block_current = (block_current + 1) & BLOCK_MASK; + block = &codeblock[block_current]; + +// if (block->pc == 0xb00b4ff5) +// pclog("Init target block\n"); + if (block->pc != 0) + { +// pclog("Reuse block : was %08x now %08x\n", block->pc, cs+pc); + delete_block(block); + cpu_recomp_reuse++; + } + block_num = HASH(phys_addr); + codeblock_hash[block_num] = &codeblock[block_current]; + block->ins = 0; + block->pc = cs + cpu_state.pc; + block->_cs = cs; + block->pnt = block_current; + block->phys = phys_addr; + block->use32 = use32; + block->stack32 = stack32; + block->next = block->prev = NULL; + + block_pos = BLOCK_GPF_OFFSET; + addbyte(0xc7); /*MOV [ESP],0*/ + addbyte(0x04); + addbyte(0x24); + addlong(0); + addbyte(0xc7); /*MOV [ESP+4],0*/ + addbyte(0x44); + addbyte(0x24); + addbyte(0x04); + addlong(0); + addbyte(0xe8); /*CALL x86gpf*/ + addlong((uint32_t)x86gpf - (uint32_t)(&codeblock[block_current].data[block_pos + 4])); + block_pos = BLOCK_EXIT_OFFSET; /*Exit code*/ + addbyte(0x83); /*ADDL $16,%esp*/ + addbyte(0xC4); + addbyte(0x10); + addbyte(0x5f); /*POP EDI*/ + addbyte(0x5e); /*POP ESI*/ + addbyte(0x5d); /*POP EBP*/ + addbyte(0x5b); /*POP EDX*/ + addbyte(0xC3); /*RET*/ + cpu_block_end = 0; + block_pos = 0; /*Entry code*/ + addbyte(0x53); /*PUSH EBX*/ + addbyte(0x55); /*PUSH EBP*/ + addbyte(0x56); /*PUSH ESI*/ + addbyte(0x57); /*PUSH EDI*/ + addbyte(0x83); /*SUBL $16,%esp*/ + addbyte(0xEC); + addbyte(0x10); + addbyte(0xBD); /*MOVL EBP, &EAX*/ + addlong((uint32_t)&EAX); + +// pclog("New block %i for %08X %03x\n", block_current, cs+pc, block_num); + + last_op32 = -1; + last_ea_seg = NULL; + last_ssegs = -1; + + codegen_block_cycles = 0; + codegen_timing_block_start(); + + codegen_block_ins = 0; + codegen_block_full_ins = 0; + + recomp_page = phys_addr & ~0xfff; + + codegen_flags_changed = 0; + codegen_fpu_entered = 0; + codegen_mmx_entered = 0; + + codegen_fpu_loaded_iq[0] = codegen_fpu_loaded_iq[1] = codegen_fpu_loaded_iq[2] = codegen_fpu_loaded_iq[3] = + codegen_fpu_loaded_iq[4] = codegen_fpu_loaded_iq[5] = codegen_fpu_loaded_iq[6] = codegen_fpu_loaded_iq[7] = 0; + + _ds.checked = _es.checked = _fs.checked = _gs.checked = (cr0 & 1) ? 0 : 1; +} + +void codegen_block_remove() +{ + codeblock_t *block = &codeblock[block_current]; +//if ((block->phys & ~0xfff) == 0x119000) pclog("codegen_block_remove %08x\n", block->pc); +// if (block->pc == 0xb00b4ff5) +// pclog("Remove target block\n"); + codeblock_hash[block_num] = NULL; + block->pc = 0;//xffffffff; + cpu_recomp_removed++; +// pclog("Remove block %i\n", block_num); + recomp_page = -1; +} + +void codegen_block_end() +{ + codeblock_t *block = &codeblock[block_current]; + codeblock_t *block_prev = pages[block->phys >> 12].block; + uint32_t start_pc = (block->pc & 0xffc) | (block->phys & ~0xfff); + uint32_t end_pc = ((codegen_endpc + 3) & 0xffc) | (block->phys & ~0xfff); + + block->endpc = codegen_endpc; + +// if (block->pc == 0xb00b4ff5) +// pclog("End target block\n"); + + if (block_prev) + { + block->next = block_prev; + block_prev->prev = block; + pages[block->phys >> 12].block = block; + } + else + { + block->next = NULL; + pages[block->phys >> 12].block = block; + } + + if (block->next) + { +// pclog(" next->pc=%08x\n", block->next->pc); + if (!block->next->pc) + fatal("block->next->pc=0 %p %p %x %x\n", (void *)block->next, (void *)codeblock, block_current, block_pos); + } + + block->page_mask = 0; + start_pc = block->pc & 0xffc; + start_pc &= ~PAGE_MASK_MASK; + end_pc = ((block->endpc & 0xffc) + PAGE_MASK_MASK) & ~PAGE_MASK_MASK; + if (end_pc > 0xfff || end_pc < start_pc) + end_pc = 0xfff; + start_pc >>= PAGE_MASK_SHIFT; + end_pc >>= PAGE_MASK_SHIFT; + +// pclog("block_end: %08x %08x\n", start_pc, end_pc); + for (; start_pc <= end_pc; start_pc++) + { + block->page_mask |= ((uint64_t)1 << start_pc); +// pclog(" %08x %llx\n", start_pc, block->page_mask); + } + + pages[block->phys >> 12].code_present_mask |= block->page_mask; + + block->phys_2 = -1; + block->page_mask2 = 0; + block->next_2 = block->prev_2 = NULL; + if ((block->pc ^ block->endpc) & ~0xfff) + { + block->phys_2 = get_phys_noabrt(block->endpc); + if (block->phys_2 != -1) + { +// pclog("start block - %08x %08x %p %p %p %08x\n", block->pc, block->endpc, (void *)block, (void *)block->next_2, (void *)pages[block->phys_2 >> 12].block_2, block->phys_2); + + if (pages[block->phys_2 >> 12].block_2 == block) + fatal("Block same\n"); + + block_prev = pages[block->phys_2 >> 12].block_2; + + if (block_prev) + { + block->next_2 = block_prev; + block_prev->prev_2 = block; + pages[block->phys_2 >> 12].block_2 = block; +// pclog(" pages.block_2=%p\n", (void *)block); + } + else + { + block->next_2 = NULL; + pages[block->phys_2 >> 12].block_2 = block; +// pclog(" pages.block_2=%p 2\n", (void *)block); + } + + start_pc = 0; + end_pc = (block->endpc & 0xfff) >> PAGE_MASK_SHIFT; + for (; start_pc <= end_pc; start_pc++) + block->page_mask2 |= ((uint64_t)1 << start_pc); + + if (!pages[block->phys_2 >> 12].block_2) + mem_flush_write_page(block->phys_2, block->endpc); +// pclog("New block - %08x %08x %p %p phys %08x %08x %016llx\n", block->pc, block->endpc, (void *)block, (void *)block->next_2, block->phys, block->phys_2, block->page_mask2); + if (!block->page_mask2) + fatal("!page_mask2\n"); + if (block->next_2) + { +// pclog(" next_2->pc=%08x\n", block->next_2->pc); + if (!block->next_2->pc) + fatal("block->next_2->pc=0 %p\n", (void *)block->next_2); + } + } + } + +// pclog("block_end: %08x %08x %016llx\n", block->pc, block->endpc, block->page_mask); + + codegen_timing_block_end(); + + if (codegen_block_cycles) + { + addbyte(0x81); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2d); + addlong((uint32_t)&cycles); + addlong((uint32_t)codegen_block_cycles); + } + if (codegen_block_ins) + { + addbyte(0x81); /*ADD $codegen_block_ins,ins*/ + addbyte(0x05); + addlong((uint32_t)&cpu_recomp_ins); + addlong(codegen_block_ins); + } +#if 0 + if (codegen_block_full_ins) + { + addbyte(0x81); /*ADD $codegen_block_ins,ins*/ + addbyte(0x05); + addlong((uint32_t)&cpu_recomp_full_ins); + addlong(codegen_block_full_ins); + } +#endif + addbyte(0x83); /*ADDL $16,%esp*/ + addbyte(0xC4); + addbyte(0x10); + addbyte(0x5f); /*POP EDI*/ + addbyte(0x5e); /*POP ESI*/ + addbyte(0x5d); /*POP EBP*/ + addbyte(0x5b); /*POP EDX*/ + addbyte(0xC3); /*RET*/ + + if (block_pos > BLOCK_GPF_OFFSET) + fatal("Over limit!\n"); +// pclog("End block %i\n", block_num); + + recomp_page = -1; + + codeblock_tree_add(block); +} + +void codegen_flush() +{ + return; +} + +static int opcode_needs_tempc[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /*00*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*10*/ + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, /*20*/ + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, /*30*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*40*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*60*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*70*/ + + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, /*80*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*90*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*a0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*b0*/ + + 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*c0*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*d0*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*e0*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*f0*/ +}; + +static int opcode_conditional_jump[256] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, /*00*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*10*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*30*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*40*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*60*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*70*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*80*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*90*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*a0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*b0*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*c0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*d0*/ + 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*e0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*f0*/ +}; + +static int opcode_modrm[256] = +{ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*00*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*10*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*20*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, /*30*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*40*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, /*60*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*70*/ + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*80*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*90*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*a0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*b0*/ + + 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, /*c0*/ + 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, /*d0*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*e0*/ + 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, /*f0*/ +}; +int opcode_0f_modrm[256] = +{ + 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*00*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*10*/ + 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*20*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*30*/ + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*40*/ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*50*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, /*60*/ + 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, /*70*/ + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /*80*/ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /*90*/ + 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, /*a0*/ + 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, /*b0*/ + + 1, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, /*c0*/ + 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, /*d0*/ + 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 1, /*e0*/ + 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0 /*f0*/ +}; + +void codegen_debug() +{ + if (output) + { + pclog("At %04x(%08x):%04x %04x(%08x):%04x es=%08x EAX=%08x BX=%04x ECX=%08x BP=%04x EDX=%08x EDI=%08x\n", CS, cs, cpu_state.pc, SS, ss, ESP, es,EAX, BX,ECX,BP, EDX,EDI); + } +} + +static x86seg *codegen_generate_ea_16_long(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc) +{ + if (!mod && rm == 6) + { + addbyte(0xC7); /*MOVL $0,(ssegs)*/ + addbyte(0x05); + addlong((uint32_t)&eaaddr); + addlong((fetchdat >> 8) & 0xffff); + (*op_pc) += 2; + } + else + { + switch (mod) + { + case 0: + addbyte(0xa1); /*MOVL *mod1add[0][rm], %eax*/ + addlong((uint32_t)mod1add[0][rm]); + addbyte(0x03); /*ADDL *mod1add[1][rm], %eax*/ + addbyte(0x05); + addlong((uint32_t)mod1add[1][rm]); + break; + case 1: + addbyte(0xb8); /*MOVL ,%eax*/ + addlong((uint32_t)(int8_t)(rmdat >> 8));// pc++; + addbyte(0x03); /*ADDL *mod1add[0][rm], %eax*/ + addbyte(0x05); + addlong((uint32_t)mod1add[0][rm]); + addbyte(0x03); /*ADDL *mod1add[1][rm], %eax*/ + addbyte(0x05); + addlong((uint32_t)mod1add[1][rm]); + (*op_pc)++; + break; + case 2: + addbyte(0xb8); /*MOVL ,%eax*/ + addlong((fetchdat >> 8) & 0xffff);// pc++; + addbyte(0x03); /*ADDL *mod1add[0][rm], %eax*/ + addbyte(0x05); + addlong((uint32_t)mod1add[0][rm]); + addbyte(0x03); /*ADDL *mod1add[1][rm], %eax*/ + addbyte(0x05); + addlong((uint32_t)mod1add[1][rm]); + (*op_pc) += 2; + break; + } + addbyte(0x25); /*ANDL $0xffff, %eax*/ + addlong(0xffff); + addbyte(0xa3); + addlong((uint32_t)&eaaddr); + + if (mod1seg[rm] == &ss && !op_ssegs) + op_ea_seg = &_ss; + } + return op_ea_seg; +} + +static x86seg *codegen_generate_ea_32_long(x86seg *op_ea_seg, uint32_t fetchdat, int op_ssegs, uint32_t *op_pc, int stack_offset) +{ + uint32_t new_eaaddr; + + if (rm == 4) + { + uint8_t sib = fetchdat >> 8; + (*op_pc)++; + + switch (mod) + { + case 0: + if ((sib & 7) == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0xb8); /*MOVL ,%eax*/ + addlong(new_eaaddr);// pc++; + (*op_pc) += 4; + } + else + { + addbyte(0x8b); /*MOVL regs[sib&7].l, %eax*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.regs[sib & 7].l - (uintptr_t)&cpu_state); + } + break; + case 1: + new_eaaddr = (uint32_t)(int8_t)((fetchdat >> 16) & 0xff); + addbyte(0xb8); /*MOVL new_eaaddr, %eax*/ + addlong(new_eaaddr); + addbyte(0x03); /*ADDL regs[sib&7].l, %eax*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.regs[sib & 7].l - (uintptr_t)&cpu_state); + (*op_pc)++; + break; + case 2: + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0xb8); /*MOVL new_eaaddr, %eax*/ + addlong(new_eaaddr); + addbyte(0x03); /*ADDL regs[sib&7].l, %eax*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.regs[sib & 7].l - (uintptr_t)&cpu_state); + (*op_pc) += 4; + break; + } + if (stack_offset && (sib & 7) == 4 && (mod || (sib & 7) != 5)) /*ESP*/ + { + addbyte(0x05); + addlong(stack_offset); + } + if (((sib & 7) == 4 || (mod && (sib & 7) == 5)) && !op_ssegs) + op_ea_seg = &_ss; + if (((sib >> 3) & 7) != 4) + { + switch (sib >> 6) + { + case 0: + addbyte(0x03); /*ADDL regs[sib&7].l, %eax*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.regs[(sib >> 3) & 7].l - (uintptr_t)&cpu_state); + break; + case 1: + addbyte(0x8B); addbyte(0x5D); addbyte((uintptr_t)&cpu_state.regs[(sib >> 3) & 7].l - (uintptr_t)&cpu_state); /*MOVL armregs[RD],%ebx*/ + addbyte(0x01); addbyte(0xD8); /*ADDL %ebx,%eax*/ + addbyte(0x01); addbyte(0xD8); /*ADDL %ebx,%eax*/ + break; + case 2: + addbyte(0x8B); addbyte(0x5D); addbyte((uintptr_t)&cpu_state.regs[(sib >> 3) & 7].l - (uintptr_t)&cpu_state); /*MOVL armregs[RD],%ebx*/ + addbyte(0xC1); addbyte(0xE3); addbyte(2); /*SHL $2,%ebx*/ + addbyte(0x01); addbyte(0xD8); /*ADDL %ebx,%eax*/ + break; + case 3: + addbyte(0x8B); addbyte(0x5D); addbyte((uintptr_t)&cpu_state.regs[(sib >> 3) & 7].l - (uintptr_t)&cpu_state); /*MOVL armregs[RD],%ebx*/ + addbyte(0xC1); addbyte(0xE3); addbyte(3); /*SHL $2,%ebx*/ + addbyte(0x01); addbyte(0xD8); /*ADDL %ebx,%eax*/ + break; + } + } + addbyte(0xa3); + addlong((uint32_t)&eaaddr); + } + else + { + if (!mod && rm == 5) + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0xC7); /*MOVL $new_eaaddr,(eaaddr)*/ + addbyte(0x05); + addlong((uint32_t)&eaaddr); + addlong(new_eaaddr); + (*op_pc) += 4; + return op_ea_seg; + } + addbyte(0x8b); /*MOVL regs[sib&7].l, %eax*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.regs[rm].l - (uintptr_t)&cpu_state); +// addbyte(0xa1); /*MOVL regs[rm].l, %eax*/ +// addlong((uint32_t)&cpu_state.regs[rm].l); + eaaddr = cpu_state.regs[rm].l; + if (mod) + { + if (rm == 5 && !op_ssegs) + op_ea_seg = &_ss; + if (mod == 1) + { + addbyte(0x05); + addlong((uint32_t)(int8_t)(fetchdat >> 8)); + (*op_pc)++; + } + else + { + new_eaaddr = fastreadl(cs + (*op_pc) + 1); + addbyte(0x05); + addlong(new_eaaddr); + (*op_pc) += 4; + } + } + addbyte(0xa3); + addlong((uint32_t)&eaaddr); + } + return op_ea_seg; +} + +void codegen_generate_call(uint8_t opcode, OpFn op, uint32_t fetchdat, uint32_t new_pc, uint32_t old_pc) +{ + codeblock_t *block = &codeblock[block_current]; + uint32_t op_32 = use32; + uint32_t op_pc = new_pc; + OpFn *op_table = x86_dynarec_opcodes; + RecompOpFn *recomp_op_table = recomp_opcodes; + int opcode_shift = 0; + int opcode_mask = 0x3ff; + int over = 0; + int pc_off = 0; + int test_modrm = 1; + int c; + + op_ea_seg = &_ds; + op_ssegs = 0; + op_old_pc = old_pc; + + for (c = 0; c < NR_HOST_REGS; c++) + host_reg_mapping[c] = -1; + mmx_ebx_ecx_loaded = 0; + for (c = 0; c < NR_HOST_XMM_REGS; c++) + host_reg_xmm_mapping[c] = -1; + + codegen_timing_start(); + + while (!over) + { + switch (opcode) + { + case 0x0f: + op_table = x86_dynarec_opcodes_0f; + recomp_op_table = recomp_opcodes_0f; + over = 1; + break; + + case 0x26: /*ES:*/ + op_ea_seg = &_es; + op_ssegs = 1; + break; + case 0x2e: /*CS:*/ + op_ea_seg = &_cs; + op_ssegs = 1; + break; + case 0x36: /*SS:*/ + op_ea_seg = &_ss; + op_ssegs = 1; + break; + case 0x3e: /*DS:*/ + op_ea_seg = &_ds; + op_ssegs = 1; + break; + case 0x64: /*FS:*/ + op_ea_seg = &_fs; + op_ssegs = 1; + break; + case 0x65: /*GS:*/ + op_ea_seg = &_gs; + op_ssegs = 1; + break; + + case 0x66: /*Data size select*/ + op_32 = ((use32 & 0x100) ^ 0x100) | (op_32 & 0x200); + break; + case 0x67: /*Address size select*/ + op_32 = ((use32 & 0x200) ^ 0x200) | (op_32 & 0x100); + break; + + case 0xd8: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_d8_a32 : x86_dynarec_opcodes_d8_a16; + recomp_op_table = recomp_opcodes_d8; + opcode_shift = 3; + opcode_mask = 0x1f; + over = 1; + pc_off = -1; + test_modrm = 0; + break; + case 0xd9: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_d9_a32 : x86_dynarec_opcodes_d9_a16; + recomp_op_table = recomp_opcodes_d9; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + break; + case 0xda: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_da_a32 : x86_dynarec_opcodes_da_a16; + recomp_op_table = recomp_opcodes_da; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + break; + case 0xdb: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_db_a32 : x86_dynarec_opcodes_db_a16; + recomp_op_table = recomp_opcodes_db; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + break; + case 0xdc: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_dc_a32 : x86_dynarec_opcodes_dc_a16; + recomp_op_table = recomp_opcodes_dc; + opcode_shift = 3; + opcode_mask = 0x1f; + over = 1; + pc_off = -1; + test_modrm = 0; + break; + case 0xdd: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_dd_a32 : x86_dynarec_opcodes_dd_a16; + recomp_op_table = recomp_opcodes_dd; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + break; + case 0xde: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_de_a32 : x86_dynarec_opcodes_de_a16; + recomp_op_table = recomp_opcodes_de; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + break; + case 0xdf: + op_table = (op_32 & 0x200) ? x86_dynarec_opcodes_df_a32 : x86_dynarec_opcodes_df_a16; + recomp_op_table = recomp_opcodes_df; + opcode_mask = 0xff; + over = 1; + pc_off = -1; + test_modrm = 0; + break; + + case 0xf0: /*LOCK*/ + break; + + default: + goto generate_call; + } + fetchdat = fastreadl(cs + op_pc); + codegen_timing_prefix(opcode, fetchdat); + if (abrt) + return; + opcode = fetchdat & 0xff; + if (!pc_off) + fetchdat >>= 8; + + op_pc++; + } + +generate_call: + codegen_timing_opcode(opcode, fetchdat, op_32); + + if ((op_table == x86_dynarec_opcodes && + ((opcode & 0xf0) == 0x70 || (opcode & 0xfc) == 0xe0 || opcode == 0xc2 || + (opcode & 0xfe) == 0xca || (opcode & 0xfc) == 0xcc || (opcode & 0xfc) == 0xe8 || + (opcode == 0xff && ((fetchdat & 0x38) >= 0x10 && (fetchdat & 0x38) < 0x30))) || + (op_table == x86_dynarec_opcodes_0f && ((opcode & 0xf0) == 0x80)))) + { + /*Opcode is likely to cause block to exit, update cycle count*/ + if (codegen_block_cycles) + { + addbyte(0x81); /*SUB $codegen_block_cycles, cyclcs*/ + addbyte(0x2d); + addlong((uint32_t)&cycles); + addlong((uint32_t)codegen_block_cycles); + codegen_block_cycles = 0; + } + if (codegen_block_ins) + { + addbyte(0x81); /*ADD $codegen_block_ins,ins*/ + addbyte(0x05); + addlong((uint32_t)&cpu_recomp_ins); + addlong(codegen_block_ins); + codegen_block_ins = 0; + } +#if 0 + if (codegen_block_full_ins) + { + addbyte(0x81); /*ADD $codegen_block_ins,ins*/ + addbyte(0x05); + addlong((uint32_t)&cpu_recomp_full_ins); + addlong(codegen_block_full_ins); + codegen_block_full_ins = 0; + } +#endif + } + + if (recomp_op_table && recomp_op_table[(opcode | op_32) & 0x1ff]) + { + uint32_t new_pc = recomp_op_table[(opcode | op_32) & 0x1ff](opcode, fetchdat, op_32, op_pc, block); + if (new_pc) + { + if (new_pc != -1) + STORE_IMM_ADDR_L((uintptr_t)&cpu_state.pc, new_pc); + + codegen_block_ins++; + block->ins++; + codegen_block_full_ins++; + codegen_endpc = (cs + cpu_state.pc) + 8; + + return; + } + } + + op = op_table[((opcode >> opcode_shift) | op_32) & opcode_mask]; +// if (output) +// pclog("Generate call at %08X %02X %08X %02X %08X %08X %08X %08X %08X %02X %02X %02X %02X\n", &codeblock[block_current][block_pos], opcode, new_pc, ram[old_pc], EAX, EBX, ECX, EDX, ESI, ram[0x7bd2+6],ram[0x7bd2+7],ram[0x7bd2+8],ram[0x7bd2+9]); + if (opcode_needs_tempc[opcode]) + { + addbyte(0xa1); /*MOVL (flags), %eax*/ + addlong((uint32_t)&flags); + addbyte(0x83); /*ANDL $1, %eax*/ + addbyte(0xe0); + addbyte(0x01); + addbyte(0xa3); /*MOVL %eax, (tempc)*/ + addlong((uint32_t)&tempc); + } + if (op_ssegs != last_ssegs) + { + last_ssegs = op_ssegs; + addbyte(0xC7); /*MOVL $0,(ssegs)*/ + addbyte(0x05); + addlong((uint32_t)&ssegs); + addlong(op_ssegs); + } + + if (!test_modrm || + (op_table == x86_dynarec_opcodes && opcode_modrm[opcode]) || + (op_table == x86_dynarec_opcodes_0f && opcode_0f_modrm[opcode])) + { + int stack_offset = 0; + + if (op_table == x86_dynarec_opcodes && opcode == 0x8f) /*POP*/ + stack_offset = (op_32 & 0x100) ? 4 : 2; + + mod = (fetchdat >> 6) & 3; + reg = (fetchdat >> 3) & 7; + rm = fetchdat & 7; + + addbyte(0xC7); /*MOVL $mod,(mod)*/ + addbyte(0x05); + addlong((uint32_t)&mod); + addlong(mod); + addbyte(0xC7); /*MOVL $reg,(reg)*/ + addbyte(0x05); + addlong((uint32_t)®); + addlong(reg); + addbyte(0xC7); /*MOVL $rm,(rm)*/ + addbyte(0x05); + addlong((uint32_t)&rm); + addlong(rm); + + op_pc += pc_off; + if (mod != 3 && !(op_32 & 0x200)) + op_ea_seg = codegen_generate_ea_16_long(op_ea_seg, fetchdat, op_ssegs, &op_pc); + if (mod != 3 && (op_32 & 0x200)) + op_ea_seg = codegen_generate_ea_32_long(op_ea_seg, fetchdat, op_ssegs, &op_pc, stack_offset); + op_pc -= pc_off; + } + +// if (op_ea_seg != last_ea_seg) +// { +// last_ea_seg = op_ea_seg; + addbyte(0xC7); /*MOVL $&_ds,(ea_seg)*/ + addbyte(0x05); + addlong((uint32_t)&ea_seg); + addlong((uint32_t)op_ea_seg); +// } + + addbyte(0xC7); /*MOVL pc,new_pc*/ + addbyte(0x45); + addbyte((uintptr_t)&cpu_state.pc - (uintptr_t)&cpu_state); + addlong(op_pc + pc_off); + + addbyte(0xC7); /*MOVL $old_pc,(oldpc)*/ + addbyte(0x05); + addlong((uint32_t)&oldpc); + addlong(old_pc); + if (op_32 != last_op32) + { + last_op32 = op_32; + addbyte(0xC7); /*MOVL $use32,(op32)*/ + addbyte(0x05); + addlong((uint32_t)&op32); + addlong(op_32); + } + + addbyte(0xC7); /*MOVL $fetchdat,(%esp)*/ + addbyte(0x04); + addbyte(0x24); + addlong(fetchdat); + + addbyte(0xE8); /*CALL*/ + addlong(((uint8_t *)op - (uint8_t *)(&block->data[block_pos + 4]))); + + codegen_block_ins++; + + block->ins++; + + addbyte(0x09); /*OR %eax, %eax*/ + addbyte(0xc0); + addbyte(0x0F); addbyte(0x85); /*JNZ 0*/ + addlong((uint32_t)&block->data[BLOCK_EXIT_OFFSET] - (uint32_t)(&block->data[block_pos + 4])); + +// addbyte(0xE8); /*CALL*/ +// addlong(((uint8_t *)codegen_debug - (uint8_t *)(&block->data[block_pos + 4]))); + + codegen_endpc = (cs + cpu_state.pc) + 8; +} + +void codegen_check_abrt() +{ + codeblock_t *block = &codeblock[block_current]; +// pclog("Generate check abrt at %08X\n", &codeblock[block_current][block_pos]); + addbyte(0x83); addbyte(0x3d); /*CMP abrt, 0*/ + addlong((uint32_t)&abrt); addbyte(0); + addbyte(0x0F); addbyte(0x85); /*JNZ 0*/ + addlong((uint32_t)&block->data[BLOCK_EXIT_OFFSET] - (uint32_t)(&block->data[block_pos + 4])); +} + +#endif diff --git a/src/codegen_x86.h b/src/codegen_x86.h new file mode 100644 index 000000000..e512679db --- /dev/null +++ b/src/codegen_x86.h @@ -0,0 +1,21 @@ +#define BLOCK_SIZE 0x4000 +#define BLOCK_MASK 0x3fff +#define BLOCK_START 0 + +#define HASH_SIZE 0x20000 +#define HASH_MASK 0x1ffff + +#define HASH(l) ((l) & 0x1ffff) + +#define BLOCK_EXIT_OFFSET 0x7f0 +#define BLOCK_GPF_OFFSET (BLOCK_EXIT_OFFSET - 20) + +enum +{ + OP_RET = 0xc3 +}; + +#define NR_HOST_REGS 3 +extern int host_reg_mapping[NR_HOST_REGS]; +#define NR_HOST_XMM_REGS 7 +extern int host_reg_xmm_mapping[NR_HOST_XMM_REGS]; diff --git a/src/compaq.c b/src/compaq.c new file mode 100644 index 000000000..c9bfd4f2e --- /dev/null +++ b/src/compaq.c @@ -0,0 +1,51 @@ +#include "ibm.h" +#include "mem.h" + +/* Compaq Deskpro 386 remaps RAM from 0xA0000-0xFFFFF to 0xFA0000-0xFFFFFF */ + +static mem_mapping_t compaq_ram_mapping; + +uint8_t compaq_read_ram(uint32_t addr, void *priv) +{ + addr = (addr & 0x7ffff) + 0x80000; + addreadlookup(mem_logical_addr, addr); + return ram[addr]; +} +uint16_t compaq_read_ramw(uint32_t addr, void *priv) +{ + addr = (addr & 0x7ffff) + 0x80000; + addreadlookup(mem_logical_addr, addr); + return *(uint16_t *)&ram[addr]; +} +uint32_t compaq_read_raml(uint32_t addr, void *priv) +{ + addr = (addr & 0x7ffff) + 0x80000; + addreadlookup(mem_logical_addr, addr); + return *(uint32_t *)&ram[addr]; +} +void compaq_write_ram(uint32_t addr, uint8_t val, void *priv) +{ + addr = (addr & 0x7ffff) + 0x80000; + addwritelookup(mem_logical_addr, addr); + mem_write_ramb_page(addr, val, &pages[addr >> 12]); +} +void compaq_write_ramw(uint32_t addr, uint16_t val, void *priv) +{ + addr = (addr & 0x7ffff) + 0x80000; + addwritelookup(mem_logical_addr, addr); + mem_write_ramw_page(addr, val, &pages[addr >> 12]); +} +void compaq_write_raml(uint32_t addr, uint32_t val, void *priv) +{ + addr = (addr & 0x7ffff) + 0x80000; + addwritelookup(mem_logical_addr, addr); + mem_write_raml_page(addr, val, &pages[addr >> 12]); +} + +void compaq_init() +{ + mem_mapping_add(&compaq_ram_mapping, 0xfa0000, 0x60000, + compaq_read_ram, compaq_read_ramw, compaq_read_raml, + compaq_write_ram, compaq_write_ramw, compaq_write_raml, + ram + 0xa0000, MEM_MAPPING_INTERNAL, NULL); +} diff --git a/src/compaq.h b/src/compaq.h new file mode 100644 index 000000000..36e9bc2ce --- /dev/null +++ b/src/compaq.h @@ -0,0 +1 @@ +void compaq_init(); diff --git a/src/config.c b/src/config.c new file mode 100644 index 000000000..676532563 --- /dev/null +++ b/src/config.c @@ -0,0 +1,400 @@ +#include +#include +#include +#include "config.h" + +char config_file_default[256]; + +static char config_file[256]; + +typedef struct list_t +{ + struct list_t *next; +} list_t; + +static list_t config_head; + +typedef struct section_t +{ + struct list_t list; + + char name[256]; + + struct list_t entry_head; +} section_t; + +typedef struct entry_t +{ + struct list_t list; + + char name[256]; + char data[256]; +} entry_t; + +#define list_add(new, head) \ + { \ + struct list_t *next = head; \ + \ + while (next->next) \ + next = next->next; \ + \ + (next)->next = new; \ + (new)->next = NULL; \ + } + +void config_dump() +{ + section_t *current_section; + + pclog("Config data :\n"); + + current_section = (section_t *)config_head.next; + + while (current_section) + { + entry_t *current_entry; + + pclog("[%s]\n", current_section->name); + + current_entry = (entry_t *)current_section->entry_head.next; + + while (current_entry) + { + pclog("%s = %s\n", current_entry->name, current_entry->data); + + current_entry = (entry_t *)current_entry->list.next; + } + + current_section = (section_t *)current_section->list.next; + } +} + +void config_free() +{ + section_t *current_section; + current_section = (section_t *)config_head.next; + + while (current_section) + { + section_t *next_section = (section_t *)current_section->list.next; + entry_t *current_entry; + + current_entry = (entry_t *)current_section->entry_head.next; + + while (current_entry) + { + entry_t *next_entry = (entry_t *)current_entry->list.next; + + free(current_entry); + current_entry = next_entry; + } + + free(current_section); + current_section = next_section; + } +} + +void config_load(char *fn) +{ + FILE *f = fopen(fn, "rt"); + section_t *current_section; + + memset(&config_head, 0, sizeof(list_t)); + + current_section = malloc(sizeof(section_t)); + memset(current_section, 0, sizeof(section_t)); + list_add(¤t_section->list, &config_head); + + if (!f) + return; + + while (1) + { + int c; + char buffer[256]; + + fgets(buffer, 255, f); + if (feof(f)) break; + + c = 0; + + while (buffer[c] == ' ' && buffer[c]) + c++; + + if (!buffer[c]) continue; + + if (buffer[c] == '#') /*Comment*/ + continue; + + if (buffer[c] == '[') /*Section*/ + { + section_t *new_section; + char name[256]; + int d = 0; + + c++; + while (buffer[c] != ']' && buffer[c]) + name[d++] = buffer[c++]; + + if (buffer[c] != ']') + continue; + name[d] = 0; + + new_section = malloc(sizeof(section_t)); + memset(new_section, 0, sizeof(section_t)); + strncpy(new_section->name, name, 256); + list_add(&new_section->list, &config_head); + + current_section = new_section; + +// pclog("New section : %s %p\n", name, (void *)current_section); + } + else + { + entry_t *new_entry; + char name[256]; + int d = 0, data_pos; + + while (buffer[c] != '=' && buffer[c] != ' ' && buffer[c]) + name[d++] = buffer[c++]; + + if (!buffer[c]) continue; + name[d] = 0; + + while ((buffer[c] == '=' || buffer[c] == ' ') && buffer[c]) + c++; + + if (!buffer[c]) continue; + + data_pos = c; + while (buffer[c]) + { + if (buffer[c] == '\n') + buffer[c] = 0; + c++; + } + + new_entry = malloc(sizeof(entry_t)); + memset(new_entry, 0, sizeof(entry_t)); + strncpy(new_entry->name, name, 256); + strncpy(new_entry->data, &buffer[data_pos], 256); + list_add(&new_entry->list, ¤t_section->entry_head); + +// pclog("New data under section [%s] : %s = %s\n", current_section->name, new_entry->name, new_entry->data); + } + } + + fclose(f); + + config_dump(); +} + + + +void config_new() +{ + FILE *f = fopen(config_file, "wt"); + fclose(f); +} + +static section_t *find_section(char *name) +{ + section_t *current_section; + char blank[] = ""; + + current_section = (section_t *)config_head.next; + if (!name) + name = blank; + + while (current_section) + { + if (!strncmp(current_section->name, name, 256)) + return current_section; + + current_section = (section_t *)current_section->list.next; + } + return NULL; +} + +static entry_t *find_entry(section_t *section, char *name) +{ + entry_t *current_entry; + + current_entry = (entry_t *)section->entry_head.next; + + while (current_entry) + { + if (!strncmp(current_entry->name, name, 256)) + return current_entry; + + current_entry = (entry_t *)current_entry->list.next; + } + return NULL; +} + +static section_t *create_section(char *name) +{ + section_t *new_section = malloc(sizeof(section_t)); + + memset(new_section, 0, sizeof(section_t)); + strncpy(new_section->name, name, 256); + list_add(&new_section->list, &config_head); + + return new_section; +} + +static entry_t *create_entry(section_t *section, char *name) +{ + entry_t *new_entry = malloc(sizeof(entry_t)); + memset(new_entry, 0, sizeof(entry_t)); + strncpy(new_entry->name, name, 256); + list_add(&new_entry->list, §ion->entry_head); + + return new_entry; +} + +int config_get_int(char *head, char *name, int def) +{ + section_t *section; + entry_t *entry; + int value; + + section = find_section(head); + + if (!section) + return def; + + entry = find_entry(section, name); + + if (!entry) + return def; + + sscanf(entry->data, "%i", &value); + + return value; +} + +char *config_get_string(char *head, char *name, char *def) +{ + section_t *section; + entry_t *entry; + int value; + + section = find_section(head); + + if (!section) + return def; + + entry = find_entry(section, name); + + if (!entry) + return def; + + return entry->data; +} + +void config_set_int(char *head, char *name, int val) +{ + section_t *section; + entry_t *entry; + + section = find_section(head); + + if (!section) + section = create_section(head); + + entry = find_entry(section, name); + + if (!entry) + entry = create_entry(section, name); + + sprintf(entry->data, "%i", val); +} + +void config_set_string(char *head, char *name, char *val) +{ + section_t *section; + entry_t *entry; + + section = find_section(head); + + if (!section) + section = create_section(head); + + entry = find_entry(section, name); + + if (!entry) + entry = create_entry(section, name); + + strncpy(entry->data, val, 256); +} + + +char *get_filename(char *s) +{ + int c = strlen(s) - 1; + while (c > 0) + { + if (s[c] == '/' || s[c] == '\\') + return &s[c+1]; + c--; + } + return s; +} + +void append_filename(char *dest, char *s1, char *s2, int size) +{ + sprintf(dest, "%s%s", s1, s2); +} + +void put_backslash(char *s) +{ + int c = strlen(s) - 1; + if (s[c] != '/' && s[c] != '\\') + s[c] = '/'; +} + +char *get_extension(char *s) +{ + int c = strlen(s) - 1; + + if (c <= 0) + return s; + + while (c && s[c] != '.') + c--; + + if (!c) + return &s[strlen(s)]; + + return &s[c+1]; +} + +void config_save(char *fn) +{ + FILE *f = fopen(fn, "wt"); + section_t *current_section; + + current_section = (section_t *)config_head.next; + + while (current_section) + { + entry_t *current_entry; + + if (current_section->name[0]) + fprintf(f, "\n[%s]\n", current_section->name); + + current_entry = (entry_t *)current_section->entry_head.next; + + while (current_entry) + { + fprintf(f, "%s = %s\n", current_entry->name, current_entry->data); + + current_entry = (entry_t *)current_entry->list.next; + } + + current_section = (section_t *)current_section->list.next; + } + + fclose(f); +} diff --git a/src/config.h b/src/config.h new file mode 100644 index 000000000..5c4f4e495 --- /dev/null +++ b/src/config.h @@ -0,0 +1,16 @@ +int config_get_int(char *head, char *name, int def); +char *config_get_string(char *head, char *name, char *def); +void config_set_int(char *head, char *name, int val); +void config_set_string(char *head, char *name, char *val); + +char *get_filename(char *s); +void append_filename(char *dest, char *s1, char *s2, int size); +void put_backslash(char *s); +char *get_extension(char *s); + +void config_load(char *fn); +void config_save(char *fn); +void config_dump(); +void config_free(); + +extern char config_file_default[256]; diff --git a/src/cpu.c b/src/cpu.c new file mode 100644 index 000000000..5fc2d6fe5 --- /dev/null +++ b/src/cpu.c @@ -0,0 +1,2260 @@ +#include "ibm.h" +#include "cpu.h" +#include "model.h" +#include "io.h" +#include "x86_ops.h" +#include "mem.h" +#include "pci.h" +#include "codegen.h" + +int isa_cycles; +static uint8_t ccr0, ccr1, ccr2, ccr3, ccr4, ccr5, ccr6; + +OpFn *x86_dynarec_opcodes; +OpFn *x86_dynarec_opcodes_0f; +OpFn *x86_dynarec_opcodes_d8_a16; +OpFn *x86_dynarec_opcodes_d8_a32; +OpFn *x86_dynarec_opcodes_d9_a16; +OpFn *x86_dynarec_opcodes_d9_a32; +OpFn *x86_dynarec_opcodes_da_a16; +OpFn *x86_dynarec_opcodes_da_a32; +OpFn *x86_dynarec_opcodes_db_a16; +OpFn *x86_dynarec_opcodes_db_a32; +OpFn *x86_dynarec_opcodes_dc_a16; +OpFn *x86_dynarec_opcodes_dc_a32; +OpFn *x86_dynarec_opcodes_dd_a16; +OpFn *x86_dynarec_opcodes_dd_a32; +OpFn *x86_dynarec_opcodes_de_a16; +OpFn *x86_dynarec_opcodes_de_a32; +OpFn *x86_dynarec_opcodes_df_a16; +OpFn *x86_dynarec_opcodes_df_a32; + +OpFn *x86_opcodes; +OpFn *x86_opcodes_0f; +OpFn *x86_opcodes_d8_a16; +OpFn *x86_opcodes_d8_a32; +OpFn *x86_opcodes_d9_a16; +OpFn *x86_opcodes_d9_a32; +OpFn *x86_opcodes_da_a16; +OpFn *x86_opcodes_da_a32; +OpFn *x86_opcodes_db_a16; +OpFn *x86_opcodes_db_a32; +OpFn *x86_opcodes_dc_a16; +OpFn *x86_opcodes_dc_a32; +OpFn *x86_opcodes_dd_a16; +OpFn *x86_opcodes_dd_a32; +OpFn *x86_opcodes_de_a16; +OpFn *x86_opcodes_de_a32; +OpFn *x86_opcodes_df_a16; +OpFn *x86_opcodes_df_a32; + +enum +{ + CPUID_FPU = (1 << 0), + CPUID_TSC = (1 << 4), + CPUID_MSR = (1 << 5), + CPUID_CMPXCHG8B = (1 << 8), + CPUID_AMDSEP = (1 << 10), + CPUID_SEP = (1 << 11), + CPUID_CMOV = (1 << 15), + CPUID_MMX = (1 << 23), + CPUID_FXSR = (1 << 24) +}; + +int cpu = 3, cpu_manufacturer = 0; +CPU *cpu_s; +int cpu_multi; +int cpu_iscyrix; +int cpu_16bitbus; +int cpu_busspeed; +int cpu_hasrdtsc; +int cpu_hasMMX, cpu_hasMSR; +int cpu_hasCR4; +int cpu_use_dynarec; + +uint64_t cpu_CR4_mask; + +int is286, is386; + +uint64_t tsc = 0; + +uint64_t pmc[2] = {0, 0}; + +uint16_t temp_seg_data[4] = {0, 0, 0, 0}; + +uint16_t cs_msr = 0; +uint32_t esp_msr = 0; +uint32_t eip_msr = 0; +uint64_t apic_base_msr = 0; +uint64_t mtrr_cap_msr = 0; +uint64_t mtrr_physbase_msr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +uint64_t mtrr_physmask_msr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +uint64_t mtrr_fix64k_8000_msr = 0; +uint64_t mtrr_fix16k_8000_msr = 0; +uint64_t mtrr_fix16k_a000_msr = 0; +uint64_t mtrr_fix4k_msr[8] = {0, 0, 0, 0, 0, 0, 0, 0}; +uint64_t pat_msr = 0; +uint64_t mtrr_deftype_msr = 0; +uint64_t ecx17_msr = 0; +uint64_t ecx79_msr = 0; +uint64_t ecx8x_msr[4] = {0, 0, 0, 0}; +uint64_t ecx116_msr = 0; +uint64_t ecx11x_msr[4] = {0, 0, 0, 0}; +uint64_t ecx11e_msr = 0; +uint64_t ecx1e0_msr = 0; + +/* AMD K5 and K6 MSR's. */ +uint64_t ecx83_msr = 0; +/* These are K6-only. */ +uint64_t star = 0; +uint64_t sfmask = 0; + +int timing_rr; +int timing_mr, timing_mrl; +int timing_rm, timing_rml; +int timing_mm, timing_mml; +int timing_bt, timing_bnt; +int timing_int, timing_int_rm, timing_int_v86, timing_int_pm, timing_int_pm_outer; +int timing_iret_rm, timing_iret_v86, timing_iret_pm, timing_iret_pm_outer; +int timing_call_rm, timing_call_pm, timing_call_pm_gate, timing_call_pm_gate_inner; +int timing_retf_rm, timing_retf_pm, timing_retf_pm_outer; +int timing_jmp_rm, timing_jmp_pm, timing_jmp_pm_gate; + +static struct +{ + uint32_t tr1, tr12; + uint32_t cesr; + uint32_t fcr; + uint64_t fcr2, fcr3; +} msr; + +/*Available cpuspeeds : + 0 = 16 MHz + 1 = 20 MHz + 2 = 25 MHz + 3 = 33 MHz + 4 = 40 MHz + 5 = 50 MHz + 6 = 66 MHz + 7 = 75 MHz + 8 = 80 MHz + 9 = 90 MHz + 10 = 100 MHz + 11 = 120 MHz + 12 = 133 MHz + 13 = 150 MHz + 14 = 160 MHz + 15 = 166 MHz + 16 = 180 MHz + 17 = 200 MHz +*/ + +CPU cpus_8088[] = +{ + /*8088 standard*/ + {"8088/4.77", CPU_8088, 0, 4772728, 1, 0, 0, 0, 0, 0}, + {"8088/7.16", CPU_8088, 1, 14318184/2, 1, 0, 0, 0, 0, 0}, + {"8088/8", CPU_8088, 1, 8000000, 1, 0, 0, 0, 0, 0}, + {"8088/10", CPU_8088, 2, 10000000, 1, 0, 0, 0, 0, 0}, + {"8088/12", CPU_8088, 3, 12000000, 1, 0, 0, 0, 0, 0}, + {"8088/16", CPU_8088, 4, 16000000, 1, 0, 0, 0, 0, 0}, + {"", -1, 0, 0, 0, 0} +}; + +CPU cpus_pcjr[] = +{ + /*8088 PCjr*/ + {"8088/4.77", CPU_8088, 0, 4772728, 1, 0, 0, 0, 0, 0}, + {"", -1, 0, 0, 0, 0} +}; + +CPU cpus_8086[] = +{ + /*8086 standard*/ + {"8086/7.16", CPU_8086, 1, 14318184/2, 1, 0, 0, 0, 0, 0}, + {"8086/8", CPU_8086, 1, 8000000, 1, 0, 0, 0, 0, 0}, + {"8086/9.54", CPU_8086, 1, 4772728*2, 1, 0, 0, 0, 0, 0}, + {"8086/10", CPU_8086, 2, 10000000, 1, 0, 0, 0, 0, 0}, + {"8086/12", CPU_8086, 3, 12000000, 1, 0, 0, 0, 0, 0}, + {"8086/16", CPU_8086, 4, 16000000, 1, 0, 0, 0, 0, 0}, + {"", -1, 0, 0, 0, 0} +}; + +CPU cpus_pc1512[] = +{ + /*8086 Amstrad*/ + {"8086/8", CPU_8086, 1, 8000000, 1, 0, 0, 0, 0, 0}, + {"", -1, 0, 0, 0, 0} +}; + +CPU cpus_286[] = +{ + /*286*/ + {"286/6", CPU_286, 0, 6000000, 1, 0, 0, 0, 0, 0}, + {"286/8", CPU_286, 1, 8000000, 1, 0, 0, 0, 0, 0}, + {"286/10", CPU_286, 2, 10000000, 1, 0, 0, 0, 0, 0}, + {"286/12", CPU_286, 3, 12000000, 1, 0, 0, 0, 0, 0}, + {"286/16", CPU_286, 4, 16000000, 1, 0, 0, 0, 0, 0}, + {"286/20", CPU_286, 5, 20000000, 1, 0, 0, 0, 0, 0}, + {"286/25", CPU_286, 6, 25000000, 1, 0, 0, 0, 0, 0}, + {"", -1, 0, 0, 0, 0} +}; + +CPU cpus_ibmat[] = +{ + /*286*/ + {"286/6", CPU_286, 0, 6000000, 1, 0, 0, 0, 0, 0}, + {"286/8", CPU_286, 0, 8000000, 1, 0, 0, 0, 0, 0}, + {"", -1, 0, 0, 0, 0} +}; + +CPU cpus_ps1_m2011[] = +{ + /*286*/ + {"286/10", CPU_286, 2, 10000000, 1, 0, 0, 0, 0, 0}, + {"", -1, 0, 0, 0, 0} +}; + +CPU cpus_i386[] = +{ + /*i386*/ + {"i386SX/16", CPU_386SX, 0, 16000000, 1, 0, 0x2308, 0, 0, 0}, + {"i386SX/20", CPU_386SX, 1, 20000000, 1, 0, 0x2308, 0, 0, 0}, + {"i386SX/25", CPU_386SX, 2, 25000000, 1, 0, 0x2308, 0, 0, 0}, + {"i386SX/33", CPU_386SX, 3, 33333333, 1, 0, 0x2308, 0, 0, 0}, + {"i386SX/40", CPU_386SX, 4, 40000000, 1, 0, 0x2308, 0, 0, 0}, + {"i386DX/16", CPU_386DX, 0, 16000000, 1, 0, 0x0308, 0, 0, 0}, + {"i386DX/20", CPU_386DX, 1, 20000000, 1, 0, 0x0308, 0, 0, 0}, + {"i386DX/25", CPU_386DX, 2, 25000000, 1, 0, 0x0308, 0, 0, 0}, + {"i386DX/33", CPU_386DX, 3, 33333333, 1, 0, 0x0308, 0, 0, 0}, + {"i386DX/40", CPU_386DX, 4, 40000000, 1, 0, 0x0308, 0, 0, 0}, + {"RapidCAD/25", CPU_i486DX, 2, 25000000, 1, 0, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"RapidCAD/33", CPU_i486DX, 3, 33333333, 1, 0, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"RapidCAD/40", CPU_i486DX, 4, 40000000, 1, 0, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_acer[] = +{ + /*i386*/ + {"i386SX/25", CPU_386SX, 2, 25000000, 1, 0, 0x2308, 0, 0, 0}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_Am386[] = +{ + /*Am386*/ + {"Am386SX/16", CPU_386SX, 0, 16000000, 1, 0, 0x2308, 0, 0, 0}, + {"Am386SX/20", CPU_386SX, 1, 20000000, 1, 0, 0x2308, 0, 0, 0}, + {"Am386SX/25", CPU_386SX, 2, 25000000, 1, 0, 0x2308, 0, 0, 0}, + {"Am386SX/33", CPU_386SX, 3, 33333333, 1, 0, 0x2308, 0, 0, 0}, + {"Am386SX/40", CPU_386SX, 4, 40000000, 1, 0, 0x2308, 0, 0, 0}, + {"Am386DX/25", CPU_386DX, 2, 25000000, 1, 0, 0x0308, 0, 0, 0}, + {"Am386DX/33", CPU_386DX, 3, 33333333, 1, 0, 0x0308, 0, 0, 0}, + {"Am386DX/40", CPU_386DX, 4, 40000000, 1, 0, 0x0308, 0, 0, 0}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_486SDLC[] = +{ + /*Cx486SLC/DLC*/ + {"Cx486SLC/20", CPU_486SLC, 1, 20000000, 1, 0, 0, 0, 0x0000, 0}, + {"Cx486SLC/25", CPU_486SLC, 2, 25000000, 1, 0, 0, 0, 0x0000, 0}, + {"Cx486SLC/33", CPU_486SLC, 3, 33333333, 1, 0, 0, 0, 0x0000, 0}, + {"Cx486SRx2/32", CPU_486SLC, 3, 32000000, 2, 0, 0, 0, 0x0006, 0}, + {"Cx486SRx2/40", CPU_486SLC, 4, 40000000, 2, 0, 0, 0, 0x0006, 0}, + {"Cx486SRx2/50", CPU_486SLC, 5, 50000000, 2, 0, 0, 0, 0x0006, 0}, + {"Cx486DLC/25", CPU_486DLC, 2, 25000000, 1, 0, 0, 0, 0x0001, 0}, + {"Cx486DLC/33", CPU_486DLC, 3, 33333333, 1, 0, 0, 0, 0x0001, 0}, + {"Cx486DLC/40", CPU_486DLC, 4, 40000000, 1, 0, 0, 0, 0x0001, 0}, + {"Cx486DRx2/32", CPU_486DLC, 3, 32000000, 2, 0, 0, 0, 0x0007, 0}, + {"Cx486DRx2/40", CPU_486DLC, 4, 40000000, 2, 0, 0, 0, 0x0007, 0}, + {"Cx486DRx2/50", CPU_486DLC, 5, 50000000, 2, 0, 0, 0, 0x0007, 0}, + {"Cx486DRx2/66", CPU_486DLC, 6, 66666666, 2, 0, 0, 0, 0x0007, 0}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_i486[] = +{ + /*i486*/ + {"i486SX/16", CPU_i486SX, 0, 16000000, 1, 16000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"i486SX/20", CPU_i486SX, 1, 20000000, 1, 20000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"i486SX/25", CPU_i486SX, 2, 25000000, 1, 25000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"i486SX/33", CPU_i486SX, 3, 33333333, 1, 33333333, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"i486SX2/50", CPU_i486SX, 5, 50000000, 2, 25000000, 0x45b, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"i486DX/25", CPU_i486DX, 2, 25000000, 1, 25000000, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"i486DX/33", CPU_i486DX, 3, 33333333, 1, 33333333, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"i486DX/50", CPU_i486DX, 5, 50000000, 1, 25000000, 0x404, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"i486DX2/40", CPU_i486DX, 4, 40000000, 2, 20000000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"i486DX2/50", CPU_i486DX, 5, 50000000, 2, 25000000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"i486DX2/66", CPU_i486DX, 6, 66666666, 2, 33333333, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"iDX4/75", CPU_i486DX, 7, 75000000, 3, 25000000, 0x481, 0x481, 0, CPU_SUPPORTS_DYNAREC}, /*CPUID available on DX4, >= 75 MHz*/ + {"iDX4/100", CPU_i486DX,10, 100000000, 3, 33333333, 0x481, 0x481, 0, CPU_SUPPORTS_DYNAREC}, /*Is on some real Intel DX2s, limit here is pretty arbitary*/ + {"Pentium OverDrive/63", CPU_PENTIUM, 6, 62500000, 3, 25000000, 0x1531, 0x1531, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive/83", CPU_PENTIUM, 8, 83333333, 3, 33333333, 0x1532, 0x1532, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"i386DX/33", CPU_386DX, 3, 33333333, 1, 0, 0x0308, 0, 0, 0}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_Am486[] = +{ + /*Am486/5x86*/ + {"Am486SX/33", CPU_Am486SX, 3, 33333333, 1, 33333333, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"Am486SX/40", CPU_Am486SX, 4, 40000000, 1, 20000000, 0x42a, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"Am486SX2/50", CPU_Am486SX, 5, 50000000, 2, 25000000, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC}, /*CPUID available on SX2, DX2, DX4, 5x86, >= 50 MHz*/ + {"Am486SX2/66", CPU_Am486SX, 6, 66666666, 2, 33333333, 0x45b, 0x45b, 0, CPU_SUPPORTS_DYNAREC}, /*Isn't on all real AMD SX2s and DX2s, availability here is pretty arbitary (and distinguishes them from the Intel chips)*/ + {"Am486DX/33", CPU_Am486DX, 3, 33333333, 1, 33333333, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"Am486DX/40", CPU_Am486DX, 4, 40000000, 1, 20000000, 0x430, 0, 0, CPU_SUPPORTS_DYNAREC}, + {"Am486DX2/50", CPU_Am486DX, 5, 50000000, 2, 25000000, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC}, + {"Am486DX2/66", CPU_Am486DX, 6, 66666666, 2, 33333333, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC}, + {"Am486DX2/80", CPU_Am486DX, 8, 80000000, 2, 20000000, 0x470, 0x470, 0, CPU_SUPPORTS_DYNAREC}, + {"Am486DX4/75", CPU_Am486DX, 7, 75000000, 3, 25000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC}, + {"Am486DX4/90", CPU_Am486DX, 9, 90000000, 3, 30000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC}, + {"Am486DX4/100", CPU_Am486DX, 10, 100000000, 3, 33333333, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC}, + {"Am486DX4/120", CPU_Am486DX, 11, 120000000, 3, 20000000, 0x482, 0x482, 0, CPU_SUPPORTS_DYNAREC}, + {"Am5x86/P75", CPU_Am486DX, 12, 133333333, 4, 33333333, 0x4e0, 0x4e0, 0, CPU_SUPPORTS_DYNAREC}, + {"Am5x86/P75+", CPU_Am486DX, 13, 160000000, 4, 20000000, 0x4e0, 0x4e0, 0, CPU_SUPPORTS_DYNAREC}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_Cx486[] = +{ + /*Cx486/5x86*/ + {"Cx486S/25", CPU_Cx486S, 2, 25000000, 1, 25000000, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC}, + {"Cx486S/33", CPU_Cx486S, 3, 33333333, 1, 33333333, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC}, + {"Cx486S/40", CPU_Cx486S, 4, 40000000, 1, 20000000, 0x420, 0, 0x0010, CPU_SUPPORTS_DYNAREC}, + {"Cx486DX/33", CPU_Cx486DX, 3, 33333333, 1, 33333333, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC}, + {"Cx486DX/40", CPU_Cx486DX, 4, 40000000, 1, 20000000, 0x430, 0, 0x051a, CPU_SUPPORTS_DYNAREC}, + {"Cx486DX2/50", CPU_Cx486DX, 5, 50000000, 2, 25000000, 0x430, 0, 0x081b, CPU_SUPPORTS_DYNAREC}, + {"Cx486DX2/66", CPU_Cx486DX, 6, 66666666, 2, 33333333, 0x430, 0, 0x0b1b, CPU_SUPPORTS_DYNAREC}, + {"Cx486DX2/80", CPU_Cx486DX, 8, 80000000, 2, 20000000, 0x430, 0, 0x311b, CPU_SUPPORTS_DYNAREC}, + {"Cx486DX4/75", CPU_Cx486DX, 7, 75000000, 3, 25000000, 0x480, 0, 0x361f, CPU_SUPPORTS_DYNAREC}, + {"Cx486DX4/100", CPU_Cx486DX, 10, 100000000, 3, 33333333, 0x480, 0, 0x361f, CPU_SUPPORTS_DYNAREC}, + {"Cx5x86/100", CPU_Cx5x86, 10, 100000000, 3, 33333333, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC}, + {"Cx5x86/120", CPU_Cx5x86, 11, 120000000, 3, 20000000, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC}, + {"Cx5x86/133", CPU_Cx5x86, 12, 133333333, 4, 33333333, 0x480, 0, 0x002f, CPU_SUPPORTS_DYNAREC}, + {"", -1, 0, 0, 0} +}; + + CPU cpus_6x86[] = + { + /*Cyrix 6x86*/ + {"6x86-P90", CPU_Cx6x86, 17, 80000000, 3, 40000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86-PR120+", CPU_Cx6x86, 17, 100000000, 3, 25000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86-PR133+", CPU_Cx6x86, 17, 110000000, 3, 27500000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86-PR150+", CPU_Cx6x86, 17, 120000000, 3, 30000000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86-PR166+", CPU_Cx6x86, 17, 133333333, 3, 33333333, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86-PR200+", CPU_Cx6x86, 17, 150000000, 3, 37500000, 0x520, 0x520, 0x1731, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + + /*Cyrix 6x86L*/ + {"6x86L-PR133+", CPU_Cx6x86L, 19, 110000000, 3, 27500000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86L-PR150+", CPU_Cx6x86L, 19, 120000000, 3, 30000000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86L-PR166+", CPU_Cx6x86L, 19, 133333333, 3, 33333333, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86L-PR200+", CPU_Cx6x86L, 19, 150000000, 3, 37500000, 0x540, 0x540, 0x2231, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + + /*Cyrix 6x86MX*/ + {"6x86MX-PR90/75",CPU_Cx6x86MX, 18, 75000000, 2, 25000000, 0x600, 0x600, 0x0451, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86MX-PR90", CPU_Cx6x86MX, 18, 90000000, 2, 30000000, 0x600, 0x600, 0x0451, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86MX-PR133", CPU_Cx6x86MX, 18, 100000000, 2, 33333333, 0x600, 0x600, 0x0451, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86MX-PR150", CPU_Cx6x86MX, 18, 120000000, 3, 30000000, 0x600, 0x600, 0x0451, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86MX-PR166", CPU_Cx6x86MX, 18, 133333333, 3, 33333333, 0x600, 0x600, 0x0451, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86MX-PR200", CPU_Cx6x86MX, 18, 166666666, 3, 33333333, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86MX-PR233", CPU_Cx6x86MX, 18, 188888888, 3, 37500000, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86MX-PR266", CPU_Cx6x86MX, 18, 207500000, 3, 41666667, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86MX-PR300", CPU_Cx6x86MX, 18, 233333333, 3, 33333333, 0x600, 0x600, 0x0454, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86MX-PR333", CPU_Cx6x86MX, 18, 250000000, 3, 41666667, 0x600, 0x600, 0x0453, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86MX-PR366", CPU_Cx6x86MX, 18, 250000000, 3, 33333333, 0x600, 0x600, 0x0452, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"6x86MX-PR400", CPU_Cx6x86MX, 18, 285000000, 3, 31666667, 0x600, 0x600, 0x0453, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"", -1, 0, 0, 0} + }; + + + +CPU cpus_WinChip[] = +{ + /*IDT WinChip*/ + {"WinChip 75", CPU_WINCHIP, 7, 75000000, 2, 25000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC}, + {"WinChip 90", CPU_WINCHIP, 9, 90000000, 2, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC}, + {"WinChip 100", CPU_WINCHIP, 10, 100000000, 2, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC}, + {"WinChip 120", CPU_WINCHIP, 11, 120000000, 2, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC}, + {"WinChip 133", CPU_WINCHIP, 12, 133333333, 2, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC}, + {"WinChip 150", CPU_WINCHIP, 13, 150000000, 3, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC}, + {"WinChip 166", CPU_WINCHIP, 15, 166666666, 3, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC}, + {"WinChip 180", CPU_WINCHIP, 16, 180000000, 3, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC}, + {"WinChip 200", CPU_WINCHIP, 17, 200000000, 3, 33333333, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC}, + {"WinChip 225", CPU_WINCHIP, 17, 225000000, 3, 37500000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC}, + {"WinChip 240", CPU_WINCHIP, 17, 240000000, 6, 30000000, 0x540, 0x540, 0, CPU_SUPPORTS_DYNAREC}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_Pentium5V[] = +{ + /*Intel Pentium (5V, socket 4)*/ + {"Pentium 60", CPU_PENTIUM, 6, 60000000, 1, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium 66", CPU_PENTIUM, 6, 66666666, 1, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive 120",CPU_PENTIUM, 14, 120000000, 2, 30000000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive 133",CPU_PENTIUM, 16, 133333333, 2, 33333333, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_Pentium5V50[] = +{ + /*Intel Pentium (5V, socket 4, including 50 MHz FSB)*/ + {"Pentium 50 (Q0399)",CPU_PENTIUM, 5, 50000000, 1, 25000000, 0x513, 0x513, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium 60", CPU_PENTIUM, 6, 60000000, 1, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium 66", CPU_PENTIUM, 6, 66666666, 1, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive 100",CPU_PENTIUM, 13, 100000000, 2, 25000000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive 120",CPU_PENTIUM, 14, 120000000, 2, 30000000, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive 133",CPU_PENTIUM, 16, 133333333, 2, 33333333, 0x51A, 0x51A, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_PentiumS5[] = +{ + /*Intel Pentium (Socket 5)*/ + {"Pentium 50 (Q0399)",CPU_PENTIUM, 5, 50000000, 1, 25000000, 0x513, 0x513, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium MMX 50", CPU_PENTIUMMMX, 5, 50000000, 1, 25000000, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC}, + {"Pentium 60", CPU_PENTIUM, 6, 60000000, 1, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium MMX 60", CPU_PENTIUMMMX, 6, 60000000, 1, 30000000, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC}, + {"Pentium 66", CPU_PENTIUM, 6, 66666666, 1, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium MMX 66", CPU_PENTIUMMMX, 6, 66666666, 1, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC}, + {"Pentium 75", CPU_PENTIUM, 9, 75000000, 2, 25000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium MMX 75", CPU_PENTIUMMMX, 9, 75000000, 2, 25000000, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC}, + {"Pentium 90", CPU_PENTIUM, 12, 90000000, 2, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium MMX 90", CPU_PENTIUMMMX, 12, 90000000, 2, 30000000, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC}, + {"Pentium 100/50", CPU_PENTIUM, 13, 100000000, 2, 25000000, 0x525, 0x525, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium 100/66", CPU_PENTIUM, 13, 100000000, 2, 33333333, 0x525, 0x525, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium 120", CPU_PENTIUM, 14, 120000000, 2, 30000000, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive 125",CPU_PENTIUM,15, 125000000, 3, 25000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive 150",CPU_PENTIUM,17, 150000000, 3, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive 166",CPU_PENTIUM,17, 166666666, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive MMX 125", CPU_PENTIUMMMX,15,125000000, 3, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive MMX 150/60", CPU_PENTIUMMMX,17,150000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive MMX 166", CPU_PENTIUMMMX,19,166000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive MMX 180", CPU_PENTIUMMMX,20,180000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive MMX 200", CPU_PENTIUMMMX,21,200000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_Pentium[] = +{ + /*Intel Pentium*/ + {"Pentium 50 (Q0399)",CPU_PENTIUM, 5, 50000000, 1, 25000000, 0x513, 0x513, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium MMX 50", CPU_PENTIUMMMX, 5, 50000000, 1, 25000000, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC}, + {"Pentium 60", CPU_PENTIUM, 6, 60000000, 1, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium MMX 60", CPU_PENTIUMMMX, 6, 60000000, 1, 30000000, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC}, + {"Pentium 66", CPU_PENTIUM, 6, 66666666, 1, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium MMX 66", CPU_PENTIUMMMX, 6, 66666666, 1, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC}, + {"Pentium 75", CPU_PENTIUM, 9, 75000000, 2, 25000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium MMX 75", CPU_PENTIUMMMX, 9, 75000000, 2, 25000000, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC}, + {"Pentium 90", CPU_PENTIUM, 12, 90000000, 2, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium MMX 90", CPU_PENTIUMMMX, 12, 90000000, 2, 30000000, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC}, + {"Pentium 100/50", CPU_PENTIUM, 13, 100000000, 2, 25000000, 0x525, 0x525, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium 100/66", CPU_PENTIUM, 13, 100000000, 2, 33333333, 0x525, 0x525, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium 120", CPU_PENTIUM, 14, 120000000, 2, 30000000, 0x526, 0x526, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium 133", CPU_PENTIUM, 16, 133333333, 2, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium 150", CPU_PENTIUM, 17, 150000000, 3, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium 166", CPU_PENTIUM, 19, 166666666, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium 200", CPU_PENTIUM, 21, 200000000, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium MMX 166", CPU_PENTIUMMMX, 19, 166666666, 3, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium MMX 200", CPU_PENTIUMMMX, 21, 200000000, 3, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium MMX 233", CPU_PENTIUMMMX, 24, 233333333, 4, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Mobile Pentium MMX 120", CPU_PENTIUMMMX, 14, 120000000, 2, 30000000, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Mobile Pentium MMX 133", CPU_PENTIUMMMX, 16, 133333333, 2, 33333333, 0x543, 0x543, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Mobile Pentium MMX 150", CPU_PENTIUMMMX, 17, 150000000, 3, 30000000, 0x544, 0x544, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Mobile Pentium MMX 166", CPU_PENTIUMMMX, 19, 166666666, 3, 33333333, 0x544, 0x544, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Mobile Pentium MMX 200", CPU_PENTIUMMMX, 21, 200000000, 3, 33333333, 0x581, 0x581, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Mobile Pentium MMX 233", CPU_PENTIUMMMX, 24, 233333333, 4, 33333333, 0x581, 0x581, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Mobile Pentium MMX 266", CPU_PENTIUMMMX, 26, 266666666, 4, 33333333, 0x582, 0x582, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Mobile Pentium MMX 300", CPU_PENTIUMMMX, 28, 300000000, 5, 33333333, 0x582, 0x582, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive 125",CPU_PENTIUM,15, 125000000, 3, 25000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive 150",CPU_PENTIUM,17, 150000000, 3, 30000000, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive 166",CPU_PENTIUM,17, 166666666, 3, 33333333, 0x52c, 0x52c, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive MMX 125", CPU_PENTIUMMMX,15,125000000, 3, 25000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive MMX 150/60", CPU_PENTIUMMMX,17,150000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive MMX 166", CPU_PENTIUMMMX,19,166000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive MMX 180", CPU_PENTIUMMMX,20,180000000, 3, 30000000, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium OverDrive MMX 200", CPU_PENTIUMMMX,21,200000000, 3, 33333333, 0x1542, 0x1542, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_K5[] = +{ + /*AMD K5 (Socket 5)*/ + {"K5 (5k86) 75 (P75)", CPU_K5, 9, 75000000, 1.50, 25000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (SSA/5) 75 (PR75)", CPU_K5, 9, 75000000, 1.50, 25000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (5k86) 90 (P90)", CPU_K5, 12, 90000000, 1.50, 30000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (SSA/5) 90 (PR90)", CPU_K5, 12, 90000000, 1.50, 30000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (5k86) 100 (P100)", CPU_K5, 13, 100000000, 1.50, 33333333, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (SSA/5) 100 (PR100)",CPU_K5, 13, 100000000, 1.50, 33333333, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (5k86) 90 (PR120)", CPU_5K86, 14, 120000000, 2.00, 30000000, 0x511, 0x511, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (5k86) 100 (PR133)", CPU_5K86, 16, 133333333, 2.00, 33333333, 0x514, 0x514, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (5k86) 105 (PR150)", CPU_5K86, 17, 150000000, 2.50, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (5k86) 116.5 (PR166)",CPU_5K86, 19, 166666666, 2.50, 33333333, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (5k86) 133 (PR200)", CPU_5K86, 21, 200000000, 3.00, 33333333, 0x534, 0x534, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_K56[] = +{ + /*AMD K5 and K6 (Socket 7)*/ + {"K5 (5k86) 75 (P75)", CPU_K5, 9, 75000000, 1.50, 25000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (SSA/5) 75 (PR75)", CPU_K5, 9, 75000000, 1.50, 25000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (5k86) 90 (P90)", CPU_K5, 12, 90000000, 1.50, 30000000, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (SSA/5) 90 (PR90)", CPU_K5, 12, 90000000, 1.50, 30000000, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (5k86) 100 (P100)", CPU_K5, 13, 100000000, 1.50, 33333333, 0x500, 0x500, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (SSA/5) 100 (PR100)",CPU_K5, 13, 100000000, 1.50, 33333333, 0x501, 0x501, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (5k86) 90 (PR120)", CPU_5K86, 14, 120000000, 2.00, 30000000, 0x511, 0x511, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (5k86) 100 (PR133)", CPU_5K86, 16, 133333333, 2.00, 33333333, 0x514, 0x514, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (5k86) 105 (PR150)", CPU_5K86, 17, 150000000, 2.50, 30000000, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (5k86) 116.5 (PR166)",CPU_5K86, 19, 166666666, 2.50, 33333333, 0x524, 0x524, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K5 (5k86) 133 (PR200)", CPU_5K86, 21, 200000000, 3.00, 33333333, 0x534, 0x534, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K6 (Model 6) 166", CPU_K6, 19, 166666666, 2.50, 33333333, 0x562, 0x562, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K6 (Model 6) 200", CPU_K6, 21, 200000000, 3.00, 33333333, 0x562, 0x562, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K6 (Model 6) 233", CPU_K6, 24, 233333333, 3.50, 33333333, 0x562, 0x562, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K6 (Model 7) 200", CPU_K6, 21, 200000000, 3.00, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K6 (Model 7) 233", CPU_K6, 24, 233333333, 3.50, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K6 (Model 7) 266", CPU_K6, 26, 266666666, 4.00, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"K6 (Model 7) 300", CPU_K6, 28, 300000000, 4.50, 33333333, 0x570, 0x570, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_PentiumPro[] = +{ + /*Intel Pentium Pro and II Overdrive*/ + {"Pentium Pro 150", CPU_PENTIUMPRO, 17, 150000000, 2.50, 30000000, 0x612, 0x612, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium Pro 166", CPU_PENTIUMPRO, 19, 166666666, 2.50, 33333333, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium Pro 180", CPU_PENTIUMPRO, 20, 180000000, 3.00, 30000000, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium Pro 200", CPU_PENTIUMPRO, 21, 200000000, 3.00, 33333333, 0x617, 0x617, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium II Overdrive 210", CPU_PENTIUM2D, 22, 210000000, 3.50, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium II Overdrive 233", CPU_PENTIUM2D, 24, 233333333, 3.50, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium II Overdrive 240", CPU_PENTIUM2D, 25, 240000000, 4.00, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium II Overdrive 266", CPU_PENTIUM2D, 26, 266666666, 4.00, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium II Overdrive 270", CPU_PENTIUM2D, 27, 270000000, 4.50, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium II Overdrive 300/66",CPU_PENTIUM2D, 28, 300000000, 4.50, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium II Overdrive 300/60",CPU_PENTIUM2D, 28, 300000000, 5.00, 30000000, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium II Overdrive 333", CPU_PENTIUM2D, 29, 333333333, 5.00, 33333333, 0x1632, 0x1632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_Pentium2[] = +{ + /*Intel Pentium II Klamath*/ + {"Pentium II 233", CPU_PENTIUM2, 24, 233333333, 3.50, 33333333, 0x632, 0x632, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium II 266", CPU_PENTIUM2, 26, 266666666, 4.00, 33333333, 0x633, 0x633, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium II 300", CPU_PENTIUM2, 28, 300000000, 4.50, 33333333, 0x634, 0x634, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"", -1, 0, 0, 0} +}; + +CPU cpus_Pentium2D[] = +{ + /*Intel Pentium II Deschutes*/ + {"Pentium II D 266", CPU_PENTIUM2D, 26, 266666666, 4.00, 33333333, 0x650, 0x650, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium II D 300", CPU_PENTIUM2D, 28, 300000000, 4.50, 33333333, 0x650, 0x650, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium II D 333", CPU_PENTIUM2D, 29, 333333333, 5.00, 33333333, 0x650, 0x650, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium II D 350", CPU_PENTIUM2D, 30, 350000000, 3.50, 50000000, 0x653, 0x653, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium II D 400", CPU_PENTIUM2D, 31, 400000000, 4.00, 50000000, 0x653, 0x653, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium II D 450", CPU_PENTIUM2D, 32, 450000000, 4.50, 50000000, 0x654, 0x654, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"Pentium II D 500", CPU_PENTIUM2D, 33, 500000000, 5.00, 50000000, 0x654, 0x654, 0, CPU_SUPPORTS_DYNAREC | CPU_REQUIRES_DYNAREC}, + {"", -1, 0, 0, 0} +}; + +void cpu_set_edx() +{ + EDX = models[model].cpu[cpu_manufacturer].cpus[cpu].edx_reset; +} + +void cpu_set() +{ + CPU *cpu_s; + + if (!models[model].cpu[cpu_manufacturer].cpus) + { + /*CPU is invalid, set to default*/ + cpu_manufacturer = 0; + cpu = 0; + } + + cpu_s = &models[model].cpu[cpu_manufacturer].cpus[cpu]; + + CPUID = cpu_s->cpuid_model; + cpuspeed = cpu_s->speed; + is8086 = (cpu_s->cpu_type > CPU_8088); + is286 = (cpu_s->cpu_type >= CPU_286); + is386 = (cpu_s->cpu_type >= CPU_386SX); + is486 = (cpu_s->cpu_type >= CPU_i486SX) || (cpu_s->cpu_type == CPU_486SLC || cpu_s->cpu_type == CPU_486DLC); + hasfpu = (cpu_s->cpu_type >= CPU_i486DX); + cpu_iscyrix = (cpu_s->cpu_type == CPU_486SLC || cpu_s->cpu_type == CPU_486DLC || cpu_s->cpu_type == CPU_Cx486S || cpu_s->cpu_type == CPU_Cx486DX || cpu_s->cpu_type == CPU_Cx5x86 || cpu_s->cpu_type == CPU_Cx6x86 || cpu_s->cpu_type == CPU_Cx6x86MX || cpu_s->cpu_type == CPU_Cx6x86L || cpu_s->cpu_type == CPU_CxGX1); + cpu_16bitbus = (cpu_s->cpu_type == CPU_386SX || cpu_s->cpu_type == CPU_486SLC); + if (cpu_s->multi) + cpu_busspeed = cpu_s->rspeed / cpu_s->multi; + cpu_multi = cpu_s->multi; + cpu_hasrdtsc = 0; + cpu_hasMMX = 0; + cpu_hasMSR = 0; + cpu_hasCR4 = 0; + ccr0 = ccr1 = ccr2 = ccr3 = ccr4 = ccr5 = ccr6 = 0; + + isa_cycles = (int)(((int64_t)cpu_s->rspeed << ISA_CYCLES_SHIFT) / 8000000ll); + + if (cpu_s->pci_speed) + { + pci_nonburst_time = 3*cpu_s->rspeed / cpu_s->pci_speed; + pci_burst_time = cpu_s->rspeed / cpu_s->pci_speed; + } + else + { + pci_nonburst_time = 3; + pci_burst_time = 1; + } + pclog("PCI burst=%i nonburst=%i\n", pci_burst_time, pci_nonburst_time); + + if (cpu_iscyrix) + io_sethandler(0x0022, 0x0002, cyrix_read, NULL, NULL, cyrix_write, NULL, NULL, NULL); + else + io_removehandler(0x0022, 0x0002, cyrix_read, NULL, NULL, cyrix_write, NULL, NULL, NULL); + + pclog("hasfpu - %i\n",hasfpu); + pclog("is486 - %i %i\n",is486,cpu_s->cpu_type); + + x86_setopcodes(ops_386, ops_386_0f, dynarec_ops_386, dynarec_ops_386_0f); + + if (hasfpu) + { + x86_dynarec_opcodes_d8_a16 = dynarec_ops_fpu_d8_a16; + x86_dynarec_opcodes_d8_a32 = dynarec_ops_fpu_d8_a32; + x86_dynarec_opcodes_d9_a16 = dynarec_ops_fpu_d9_a16; + x86_dynarec_opcodes_d9_a32 = dynarec_ops_fpu_d9_a32; + x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_da_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_da_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_db_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_db_a32; + x86_dynarec_opcodes_dc_a16 = dynarec_ops_fpu_dc_a16; + x86_dynarec_opcodes_dc_a32 = dynarec_ops_fpu_dc_a32; + x86_dynarec_opcodes_dd_a16 = dynarec_ops_fpu_dd_a16; + x86_dynarec_opcodes_dd_a32 = dynarec_ops_fpu_dd_a32; + x86_dynarec_opcodes_de_a16 = dynarec_ops_fpu_de_a16; + x86_dynarec_opcodes_de_a32 = dynarec_ops_fpu_de_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_df_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_df_a32; + } + else + { + x86_dynarec_opcodes_d8_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_d8_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_d9_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_d9_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_da_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_dc_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_dc_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_dd_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_dd_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_de_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_de_a32 = dynarec_ops_nofpu_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_nofpu_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_nofpu_a32; + } + codegen_timing_set(&codegen_timing_486); + + if (hasfpu) + { + x86_opcodes_d8_a16 = ops_fpu_d8_a16; + x86_opcodes_d8_a32 = ops_fpu_d8_a32; + x86_opcodes_d9_a16 = ops_fpu_d9_a16; + x86_opcodes_d9_a32 = ops_fpu_d9_a32; + x86_opcodes_da_a16 = ops_fpu_da_a16; + x86_opcodes_da_a32 = ops_fpu_da_a32; + x86_opcodes_db_a16 = ops_fpu_db_a16; + x86_opcodes_db_a32 = ops_fpu_db_a32; + x86_opcodes_dc_a16 = ops_fpu_dc_a16; + x86_opcodes_dc_a32 = ops_fpu_dc_a32; + x86_opcodes_dd_a16 = ops_fpu_dd_a16; + x86_opcodes_dd_a32 = ops_fpu_dd_a32; + x86_opcodes_de_a16 = ops_fpu_de_a16; + x86_opcodes_de_a32 = ops_fpu_de_a32; + x86_opcodes_df_a16 = ops_fpu_df_a16; + x86_opcodes_df_a32 = ops_fpu_df_a32; + } + else + { + x86_opcodes_d8_a16 = ops_nofpu_a16; + x86_opcodes_d8_a32 = ops_nofpu_a32; + x86_opcodes_d9_a16 = ops_nofpu_a16; + x86_opcodes_d9_a32 = ops_nofpu_a32; + x86_opcodes_da_a16 = ops_nofpu_a16; + x86_opcodes_da_a32 = ops_nofpu_a32; + x86_opcodes_db_a16 = ops_nofpu_a16; + x86_opcodes_db_a32 = ops_nofpu_a32; + x86_opcodes_dc_a16 = ops_nofpu_a16; + x86_opcodes_dc_a32 = ops_nofpu_a32; + x86_opcodes_dd_a16 = ops_nofpu_a16; + x86_opcodes_dd_a32 = ops_nofpu_a32; + x86_opcodes_de_a16 = ops_nofpu_a16; + x86_opcodes_de_a32 = ops_nofpu_a32; + x86_opcodes_df_a16 = ops_nofpu_a16; + x86_opcodes_df_a32 = ops_nofpu_a32; + } + + memset(&msr, 0, sizeof(msr)); + + switch (cpu_s->cpu_type) + { + case CPU_8088: + case CPU_8086: + break; + + case CPU_286: + x86_setopcodes(ops_286, ops_286_0f, dynarec_ops_286, dynarec_ops_286_0f); + timing_rr = 2; /*register dest - register src*/ + timing_rm = 7; /*register dest - memory src*/ + timing_mr = 7; /*memory dest - register src*/ + timing_mm = 7; /*memory dest - memory src*/ + timing_rml = 9; /*register dest - memory src long*/ + timing_mrl = 11; /*memory dest - register src long*/ + timing_mml = 11; /*memory dest - memory src*/ + timing_bt = 7-3; /*branch taken*/ + timing_bnt = 3; /*branch not taken*/ + timing_int = 0; + timing_int_rm = 23; + timing_int_v86 = 0; + timing_int_pm = 40; + timing_int_pm_outer = 78; + timing_iret_rm = 17; + timing_iret_v86 = 0; + timing_iret_pm = 31; + timing_iret_pm_outer = 55; + timing_call_rm = 13; + timing_call_pm = 26; + timing_call_pm_gate = 52; + timing_call_pm_gate_inner = 82; + timing_retf_rm = 15; + timing_retf_pm = 25; + timing_retf_pm_outer = 55; + timing_jmp_rm = 11; + timing_jmp_pm = 23; + timing_jmp_pm_gate = 38; + break; + + case CPU_386SX: + timing_rr = 2; /*register dest - register src*/ + timing_rm = 6; /*register dest - memory src*/ + timing_mr = 7; /*memory dest - register src*/ + timing_mm = 6; /*memory dest - memory src*/ + timing_rml = 8; /*register dest - memory src long*/ + timing_mrl = 11; /*memory dest - register src long*/ + timing_mml = 10; /*memory dest - memory src*/ + timing_bt = 7-3; /*branch taken*/ + timing_bnt = 3; /*branch not taken*/ + timing_int = 0; + timing_int_rm = 37; + timing_int_v86 = 59; + timing_int_pm = 99; + timing_int_pm_outer = 119; + timing_iret_rm = 22; + timing_iret_v86 = 60; + timing_iret_pm = 38; + timing_iret_pm_outer = 82; + timing_call_rm = 17; + timing_call_pm = 34; + timing_call_pm_gate = 52; + timing_call_pm_gate_inner = 86; + timing_retf_rm = 18; + timing_retf_pm = 32; + timing_retf_pm_outer = 68; + timing_jmp_rm = 12; + timing_jmp_pm = 27; + timing_jmp_pm_gate = 45; + break; + + case CPU_386DX: + timing_rr = 2; /*register dest - register src*/ + timing_rm = 6; /*register dest - memory src*/ + timing_mr = 7; /*memory dest - register src*/ + timing_mm = 6; /*memory dest - memory src*/ + timing_rml = 6; /*register dest - memory src long*/ + timing_mrl = 7; /*memory dest - register src long*/ + timing_mml = 6; /*memory dest - memory src*/ + timing_bt = 7-3; /*branch taken*/ + timing_bnt = 3; /*branch not taken*/ + timing_int = 0; + timing_int_rm = 37; + timing_int_v86 = 59; + timing_int_pm = 99; + timing_int_pm_outer = 119; + timing_iret_rm = 22; + timing_iret_v86 = 60; + timing_iret_pm = 38; + timing_iret_pm_outer = 82; + timing_call_rm = 17; + timing_call_pm = 34; + timing_call_pm_gate = 52; + timing_call_pm_gate_inner = 86; + timing_retf_rm = 18; + timing_retf_pm = 32; + timing_retf_pm_outer = 68; + timing_jmp_rm = 12; + timing_jmp_pm = 27; + timing_jmp_pm_gate = 45; + break; + + case CPU_486SLC: + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); + timing_rr = 1; /*register dest - register src*/ + timing_rm = 3; /*register dest - memory src*/ + timing_mr = 5; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 5; /*register dest - memory src long*/ + timing_mrl = 7; /*memory dest - register src long*/ + timing_mml = 7; + timing_bt = 6-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + /*unknown*/ + timing_int = 4; + timing_int_rm = 14; + timing_int_v86 = 82; + timing_int_pm = 49; + timing_int_pm_outer = 77; + timing_iret_rm = 14; + timing_iret_v86 = 66; + timing_iret_pm = 31; + timing_iret_pm_outer = 66; + timing_call_rm = 12; + timing_call_pm = 30; + timing_call_pm_gate = 41; + timing_call_pm_gate_inner = 83; + timing_retf_rm = 13; + timing_retf_pm = 26; + timing_retf_pm_outer = 61; + timing_jmp_rm = 9; + timing_jmp_pm = 26; + timing_jmp_pm_gate = 37; + break; + + case CPU_486DLC: + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); + timing_rr = 1; /*register dest - register src*/ + timing_rm = 3; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 3; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 6-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + /*unknown*/ + timing_int = 4; + timing_int_rm = 14; + timing_int_v86 = 82; + timing_int_pm = 49; + timing_int_pm_outer = 77; + timing_iret_rm = 14; + timing_iret_v86 = 66; + timing_iret_pm = 31; + timing_iret_pm_outer = 66; + timing_call_rm = 12; + timing_call_pm = 30; + timing_call_pm_gate = 41; + timing_call_pm_gate_inner = 83; + timing_retf_rm = 13; + timing_retf_pm = 26; + timing_retf_pm_outer = 61; + timing_jmp_rm = 9; + timing_jmp_pm = 26; + timing_jmp_pm_gate = 37; + break; + + case CPU_i486SX: + case CPU_i486DX: + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 3-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 4; + timing_int_rm = 26; + timing_int_v86 = 82; + timing_int_pm = 44; + timing_int_pm_outer = 71; + timing_iret_rm = 15; + timing_iret_v86 = 36; /*unknown*/ + timing_iret_pm = 20; + timing_iret_pm_outer = 36; + timing_call_rm = 18; + timing_call_pm = 20; + timing_call_pm_gate = 35; + timing_call_pm_gate_inner = 69; + timing_retf_rm = 13; + timing_retf_pm = 17; + timing_retf_pm_outer = 35; + timing_jmp_rm = 17; + timing_jmp_pm = 19; + timing_jmp_pm_gate = 32; + break; + + case CPU_Am486SX: + case CPU_Am486DX: + /*AMD timing identical to Intel*/ + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 3-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 4; + timing_int_rm = 26; + timing_int_v86 = 82; + timing_int_pm = 44; + timing_int_pm_outer = 71; + timing_iret_rm = 15; + timing_iret_v86 = 36; /*unknown*/ + timing_iret_pm = 20; + timing_iret_pm_outer = 36; + timing_call_rm = 18; + timing_call_pm = 20; + timing_call_pm_gate = 35; + timing_call_pm_gate_inner = 69; + timing_retf_rm = 13; + timing_retf_pm = 17; + timing_retf_pm_outer = 35; + timing_jmp_rm = 17; + timing_jmp_pm = 19; + timing_jmp_pm_gate = 32; + break; + + case CPU_Cx486S: + case CPU_Cx486DX: + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); + timing_rr = 1; /*register dest - register src*/ + timing_rm = 3; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 3; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 4-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 4; + timing_int_rm = 14; + timing_int_v86 = 82; + timing_int_pm = 49; + timing_int_pm_outer = 77; + timing_iret_rm = 14; + timing_iret_v86 = 66; /*unknown*/ + timing_iret_pm = 31; + timing_iret_pm_outer = 66; + timing_call_rm = 12; + timing_call_pm = 30; + timing_call_pm_gate = 41; + timing_call_pm_gate_inner = 83; + timing_retf_rm = 13; + timing_retf_pm = 26; + timing_retf_pm_outer = 61; + timing_jmp_rm = 9; + timing_jmp_pm = 26; + timing_jmp_pm_gate = 37; + break; + + case CPU_Cx5x86: + x86_setopcodes(ops_386, ops_486_0f, dynarec_ops_386, dynarec_ops_486_0f); + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 2; /*memory dest - register src*/ + timing_mm = 2; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 2; /*memory dest - register src long*/ + timing_mml = 2; + timing_bt = 5-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 0; + timing_int_rm = 9; + timing_int_v86 = 82; /*unknown*/ + timing_int_pm = 21; + timing_int_pm_outer = 32; + timing_iret_rm = 7; + timing_iret_v86 = 26; /*unknown*/ + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 4; + timing_call_pm = 15; + timing_call_pm_gate = 26; + timing_call_pm_gate_inner = 35; + timing_retf_rm = 4; + timing_retf_pm = 7; + timing_retf_pm_outer = 23; + timing_jmp_rm = 5; + timing_jmp_pm = 7; + timing_jmp_pm_gate = 17; + break; + + case CPU_WINCHIP: + x86_setopcodes(ops_386, ops_winchip_0f, dynarec_ops_386, dynarec_ops_winchip_0f); + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 2; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 2; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 3-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = cpu_hasMSR = 1; + cpu_hasCR4 = 1; + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; + /*unknown*/ + timing_int_rm = 26; + timing_int_v86 = 82; + timing_int_pm = 44; + timing_int_pm_outer = 71; + timing_iret_rm = 7; + timing_iret_v86 = 26; + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 4; + timing_call_pm = 15; + timing_call_pm_gate = 26; + timing_call_pm_gate_inner = 35; + timing_retf_rm = 4; + timing_retf_pm = 7; + timing_retf_pm_outer = 23; + timing_jmp_rm = 5; + timing_jmp_pm = 7; + timing_jmp_pm_gate = 17; + codegen_timing_set(&codegen_timing_winchip); + break; + + case CPU_PENTIUM: + x86_setopcodes(ops_386, ops_pentium_0f, dynarec_ops_386, dynarec_ops_pentium_0f); + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 0; /*branch taken*/ + timing_bnt = 2; /*branch not taken*/ + timing_int = 6; + timing_int_rm = 11; + timing_int_v86 = 54; + timing_int_pm = 25; + timing_int_pm_outer = 42; + timing_iret_rm = 7; + timing_iret_v86 = 27; /*unknown*/ + timing_iret_pm = 10; + timing_iret_pm_outer = 27; + timing_call_rm = 4; + timing_call_pm = 4; + timing_call_pm_gate = 22; + timing_call_pm_gate_inner = 44; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 3; + timing_jmp_pm = 3; + timing_jmp_pm_gate = 18; + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 0; + cpu_hasMSR = 1; + cpu_hasCR4 = 1; + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; + codegen_timing_set(&codegen_timing_pentium); + break; + + case CPU_PENTIUMMMX: + x86_setopcodes(ops_386, ops_pentiummmx_0f, dynarec_ops_386, dynarec_ops_pentiummmx_0f); + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 0; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + timing_int = 6; + timing_int_rm = 11; + timing_int_v86 = 54; + timing_int_pm = 25; + timing_int_pm_outer = 42; + timing_iret_rm = 7; + timing_iret_v86 = 27; /*unknown*/ + timing_iret_pm = 10; + timing_iret_pm_outer = 27; + timing_call_rm = 4; + timing_call_pm = 4; + timing_call_pm_gate = 22; + timing_call_pm_gate_inner = 44; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 3; + timing_jmp_pm = 3; + timing_jmp_pm_gate = 18; + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 1; + cpu_hasMSR = 1; + cpu_hasCR4 = 1; + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; + codegen_timing_set(&codegen_timing_pentium); + break; + + case CPU_Cx6x86: + x86_setopcodes(ops_386, ops_pentium_0f, dynarec_ops_386, dynarec_ops_pentium_0f); + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 2; /*memory dest - register src*/ + timing_mm = 2; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 2; /*memory dest - register src long*/ + timing_mml = 2; + timing_bt = 0; /*branch taken*/ + timing_bnt = 2; /*branch not taken*/ + timing_int_rm = 9; + timing_int_v86 = 46; + timing_int_pm = 21; + timing_int_pm_outer = 32; + timing_iret_rm = 7; + timing_iret_v86 = 26; + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 3; + timing_call_pm = 4; + timing_call_pm_gate = 15; + timing_call_pm_gate_inner = 26; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 1; + timing_jmp_pm = 4; + timing_jmp_pm_gate = 14; + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 0; + cpu_hasMSR = 0; + cpu_hasCR4 = 0; + codegen_timing_set(&codegen_timing_686); + CPUID = 0; /*Disabled on powerup by default*/ + break; + + case CPU_Cx6x86L: + x86_setopcodes(ops_386, ops_pentium_0f, dynarec_ops_386, dynarec_ops_pentium_0f); + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 2; /*memory dest - register src*/ + timing_mm = 2; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 2; /*memory dest - register src long*/ + timing_mml = 2; + timing_bt = 0; /*branch taken*/ + timing_bnt = 2; /*branch not taken*/ + timing_int_rm = 9; + timing_int_v86 = 46; + timing_int_pm = 21; + timing_int_pm_outer = 32; + timing_iret_rm = 7; + timing_iret_v86 = 26; + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 3; + timing_call_pm = 4; + timing_call_pm_gate = 15; + timing_call_pm_gate_inner = 26; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 1; + timing_jmp_pm = 4; + timing_jmp_pm_gate = 14; + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 0; + cpu_hasMSR = 0; + cpu_hasCR4 = 0; + codegen_timing_set(&codegen_timing_686); + ccr4 = 0x80; + break; + + + case CPU_CxGX1: + x86_setopcodes(ops_386, ops_pentium_0f, dynarec_ops_386, dynarec_ops_pentium_0f); + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 2; /*memory dest - register src*/ + timing_mm = 2; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 2; /*memory dest - register src long*/ + timing_mml = 2; + timing_bt = 5-1; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 0; + cpu_hasMSR = 1; + cpu_hasCR4 = 1; + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_PCE; + codegen_timing_set(&codegen_timing_686); + break; + + + case CPU_Cx6x86MX: + x86_setopcodes(ops_386, ops_c6x86mx_0f, dynarec_ops_386, dynarec_ops_c6x86mx_0f); + x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_686_da_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_686_da_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_686_db_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_686_db_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_686_df_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_686_df_a32; + x86_opcodes_da_a16 = ops_fpu_686_da_a16; + x86_opcodes_da_a32 = ops_fpu_686_da_a32; + x86_opcodes_db_a16 = ops_fpu_686_db_a16; + x86_opcodes_db_a32 = ops_fpu_686_db_a32; + x86_opcodes_df_a16 = ops_fpu_686_df_a16; + x86_opcodes_df_a32 = ops_fpu_686_df_a32; + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 2; /*memory dest - register src*/ + timing_mm = 2; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 2; /*memory dest - register src long*/ + timing_mml = 2; + timing_bt = 0; /*branch taken*/ + timing_bnt = 2; /*branch not taken*/ + timing_int_rm = 9; + timing_int_v86 = 46; + timing_int_pm = 21; + timing_int_pm_outer = 32; + timing_iret_rm = 7; + timing_iret_v86 = 26; + timing_iret_pm = 10; + timing_iret_pm_outer = 26; + timing_call_rm = 3; + timing_call_pm = 4; + timing_call_pm_gate = 15; + timing_call_pm_gate_inner = 26; + timing_retf_rm = 4; + timing_retf_pm = 4; + timing_retf_pm_outer = 23; + timing_jmp_rm = 1; + timing_jmp_pm = 4; + timing_jmp_pm_gate = 14; + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 1; + cpu_hasMSR = 1; + cpu_hasCR4 = 1; + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_PCE; + codegen_timing_set(&codegen_timing_686); + ccr4 = 0x80; + break; + + case CPU_K5: + case CPU_5K86: + x86_setopcodes(ops_386, ops_k6_0f, dynarec_ops_386, dynarec_ops_k6_0f); + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 0; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 1; + cpu_hasMSR = 1; + cpu_hasCR4 = 1; + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; + break; + + case CPU_K6: + x86_setopcodes(ops_386, ops_k6_0f, dynarec_ops_386, dynarec_ops_k6_0f); + timing_rr = 1; /*register dest - register src*/ + timing_rm = 2; /*register dest - memory src*/ + timing_mr = 3; /*memory dest - register src*/ + timing_mm = 3; + timing_rml = 2; /*register dest - memory src long*/ + timing_mrl = 3; /*memory dest - register src long*/ + timing_mml = 3; + timing_bt = 0; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 1; + cpu_hasMSR = 1; + cpu_hasCR4 = 1; + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; + codegen_timing_set(&codegen_timing_pentium); + break; + + case CPU_PENTIUMPRO: + x86_setopcodes(ops_386, ops_pentiumpro_0f, dynarec_ops_386, dynarec_ops_pentiumpro_0f); + x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_686_da_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_686_da_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_686_db_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_686_db_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_686_df_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_686_df_a32; + x86_opcodes_da_a16 = ops_fpu_686_da_a16; + x86_opcodes_da_a32 = ops_fpu_686_da_a32; + x86_opcodes_db_a16 = ops_fpu_686_db_a16; + x86_opcodes_db_a32 = ops_fpu_686_db_a32; + x86_opcodes_df_a16 = ops_fpu_686_df_a16; + x86_opcodes_df_a32 = ops_fpu_686_df_a32; + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 1; /*memory dest - register src*/ + timing_mm = 1; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 1; /*memory dest - register src long*/ + timing_mml = 1; + timing_bt = 0; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 0; + cpu_hasMSR = 1; + cpu_hasCR4 = 1; + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; + codegen_timing_set(&codegen_timing_686); + break; + + case CPU_PENTIUM2: + x86_setopcodes(ops_386, ops_pentium2_0f, dynarec_ops_386, dynarec_ops_pentium2_0f); + x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_686_da_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_686_da_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_686_db_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_686_db_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_686_df_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_686_df_a32; + x86_opcodes_da_a16 = ops_fpu_686_da_a16; + x86_opcodes_da_a32 = ops_fpu_686_da_a32; + x86_opcodes_db_a16 = ops_fpu_686_db_a16; + x86_opcodes_db_a32 = ops_fpu_686_db_a32; + x86_opcodes_df_a16 = ops_fpu_686_df_a16; + x86_opcodes_df_a32 = ops_fpu_686_df_a32; + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 1; /*memory dest - register src*/ + timing_mm = 1; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 1; /*memory dest - register src long*/ + timing_mml = 1; + timing_bt = 0; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 1; + cpu_hasMSR = 1; + cpu_hasCR4 = 1; + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE; + codegen_timing_set(&codegen_timing_686); + break; + + case CPU_PENTIUM2D: + x86_setopcodes(ops_386, ops_pentium2d_0f, dynarec_ops_386, dynarec_ops_pentium2d_0f); + x86_dynarec_opcodes_da_a16 = dynarec_ops_fpu_686_da_a16; + x86_dynarec_opcodes_da_a32 = dynarec_ops_fpu_686_da_a32; + x86_dynarec_opcodes_db_a16 = dynarec_ops_fpu_686_db_a16; + x86_dynarec_opcodes_db_a32 = dynarec_ops_fpu_686_db_a32; + x86_dynarec_opcodes_df_a16 = dynarec_ops_fpu_686_df_a16; + x86_dynarec_opcodes_df_a32 = dynarec_ops_fpu_686_df_a32; + x86_opcodes_da_a16 = ops_fpu_686_da_a16; + x86_opcodes_da_a32 = ops_fpu_686_da_a32; + x86_opcodes_db_a16 = ops_fpu_686_db_a16; + x86_opcodes_db_a32 = ops_fpu_686_db_a32; + x86_opcodes_df_a16 = ops_fpu_686_df_a16; + x86_opcodes_df_a32 = ops_fpu_686_df_a32; + timing_rr = 1; /*register dest - register src*/ + timing_rm = 1; /*register dest - memory src*/ + timing_mr = 1; /*memory dest - register src*/ + timing_mm = 1; + timing_rml = 1; /*register dest - memory src long*/ + timing_mrl = 1; /*memory dest - register src long*/ + timing_mml = 1; + timing_bt = 0; /*branch taken*/ + timing_bnt = 1; /*branch not taken*/ + cpu_hasrdtsc = 1; + msr.fcr = (1 << 8) | (1 << 9) | (1 << 12) | (1 << 16) | (1 << 19) | (1 << 21); + cpu_hasMMX = 1; + cpu_hasMSR = 1; + cpu_hasCR4 = 1; + cpu_CR4_mask = CR4_TSD | CR4_DE | CR4_MCE | CR4_PCE | CR4_OSFXSR; + codegen_timing_set(&codegen_timing_686); + break; + + default: + fatal("cpu_set : unknown CPU type %i\n", cpu_s->cpu_type); + } +} + +void cpu_CPUID() +{ + switch (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type) + { + case CPU_i486DX: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU; /*FPU*/ + } + else + EAX = 0; + break; + + case CPU_Am486SX: + if (!EAX) + { + EAX = 1; + EBX = 0x68747541; + ECX = 0x444D4163; + EDX = 0x69746E65; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = EDX = 0; /*No FPU*/ + } + else + EAX = 0; + break; + + case CPU_Am486DX: + if (!EAX) + { + EAX = 1; + EBX = 0x68747541; + ECX = 0x444D4163; + EDX = 0x69746E65; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU; /*FPU*/ + } + else + EAX = 0; + break; + + case CPU_WINCHIP: + if (!EAX) + { + EAX = 1; + if (msr.fcr2 & (1 << 14)) + { + EBX = msr.fcr3 >> 32; + ECX = msr.fcr3 & 0xffffffff; + EDX = msr.fcr2 >> 32; + } + else + { + EBX = 0x746e6543; /*CentaurHauls*/ + ECX = 0x736c7561; + EDX = 0x48727561; + } + } + else if (EAX == 1) + { + EAX = 0x540; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR; + if (msr.fcr & (1 << 9)) + EDX |= CPUID_MMX; + } + else + EAX = 0; + break; + + case CPU_PENTIUM: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; + } + else + EAX = 0; + break; + + case CPU_K5: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x68747541; + EDX = 0x69746E65; + ECX = 0x444D4163; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; + } + else + EAX = 0; + break; + + case CPU_5K86: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x68747541; + EDX = 0x69746E65; + ECX = 0x444D4163; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; + } + else if (EAX == 0x80000000) + { + EAX = 0x80000005; + EBX = ECX = EDX = 0; + } + else if (EAX == 0x80000001) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; + } + else if (EAX == 0x80000002) + { + EAX = 0x2D444D41; + EBX = 0x7428354B; + ECX = 0x5020296D; + EDX = 0x65636F72; + } + else if (EAX == 0x80000003) + { + EAX = 0x726F7373; + EBX = ECX = EDX = 0; + } + else if (EAX == 0x80000004) + { + EAX = EBX = ECX = EDX = 0; + } + else if (EAX == 0x80000005) + { + EAX = 0; + EBX = 0x04800000; + ECX = 0x08040120; + EDX = 0x10040120; + } + else + EAX = 0; + break; + + case CPU_K6: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x68747541; + EDX = 0x69746E65; + ECX = 0x444D4163; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; + } + else if (EAX == 0x80000000) + { + EAX = 0x80000005; + EBX = ECX = EDX = 0; + } + else if (EAX == 0x80000001) + { + EAX = CPUID + 0x100; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_AMDSEP; + } + else if (EAX == 0x80000002) + { + EAX = 0x2D444D41; + EBX = 0x6D74364B; + ECX = 0x202F7720; + EDX = 0x746C756D; + } + else if (EAX == 0x80000003) + { + EAX = 0x64656D69; + EBX = 0x65206169; + ECX = 0x6E657478; + EDX = 0x6E6F6973; + } + else if (EAX == 0x80000004) + { + EAX = 0x73; + EBX = ECX = EDX = 0; + } + else if (EAX == 0x80000005) + { + EAX = 0; + EBX = 0x02800140; + ECX = 0x20020220; + EDX = 0x20020220; + } + else if (EAX == 0x8FFFFFFF) + { + EAX = 0x4778654E; + EBX = 0x72656E65; + ECX = 0x6F697461; + EDX = 0x444D416E; + } + else + EAX = 0; + break; + + case CPU_PENTIUMMMX: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX; + } + else + EAX = 0; + break; + + + case CPU_Cx6x86: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x69727943; + EDX = 0x736e4978; + ECX = 0x64616574; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU; + } + else + EAX = 0; + break; + + + case CPU_Cx6x86L: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x69727943; + EDX = 0x736e4978; + ECX = 0x64616574; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_CMPXCHG8B; + } + else + EAX = 0; + break; + + + case CPU_CxGX1: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x69727943; + EDX = 0x736e4978; + ECX = 0x64616574; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B; + } + else + EAX = 0; + break; + + + + case CPU_Cx6x86MX: + if (!EAX) + { + EAX = 0x00000001; + EBX = 0x69727943; + EDX = 0x736e4978; + ECX = 0x64616574; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_CMOV | CPUID_MMX; + } + else + EAX = 0; + break; + + case CPU_PENTIUMPRO: + if (!EAX) + { + EAX = 0x00000002; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_SEP | CPUID_CMOV; + } + else if (EAX == 2) + { + } + else + EAX = 0; + break; + + case CPU_PENTIUM2: + if (!EAX) + { + EAX = 0x00000002; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_SEP | CPUID_CMOV; + // EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_CMOV; + // EDX = 0x0183FBFF; + } + else if (EAX == 2) + { + EAX = 0x03020101; + EBX = ECX = 0; + EDX = 0x0C040843; + } + else + EAX = 0; + break; + + case CPU_PENTIUM2D: + if (!EAX) + { + EAX = 0x00000002; + EBX = 0x756e6547; + EDX = 0x49656e69; + ECX = 0x6c65746e; + } + else if (EAX == 1) + { + EAX = CPUID; + EBX = ECX = 0; + EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_SEP | CPUID_FXSR | CPUID_CMOV; + // EDX = CPUID_FPU | CPUID_TSC | CPUID_MSR | CPUID_CMPXCHG8B | CPUID_MMX | CPUID_FXSR | CPUID_CMOV; + // EDX = 0x0183FBFF; + } + else if (EAX == 2) + { + EAX = 0x03020101; + EBX = ECX = 0; + EDX = 0x0C040844; + } + else + EAX = 0; + break; + + } +} + +void cpu_RDMSR() +{ + switch (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type) + { + case CPU_WINCHIP: + EAX = EDX = 0; + switch (ECX) + { + case 0x02: + EAX = msr.tr1; + break; + case 0x0e: + EAX = msr.tr12; + break; + case 0x10: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + case 0x11: + EAX = msr.cesr; + break; + case 0x107: + EAX = msr.fcr; + break; + case 0x108: + EAX = msr.fcr2 & 0xffffffff; + EDX = msr.fcr2 >> 32; + break; + case 0x10a: + EAX = cpu_multi & 3; + break; + } + break; + + case CPU_K5: + case CPU_5K86: + case CPU_K6: + EAX = EDX = 0; + switch (ECX) + { + case 0x0e: + EAX = msr.tr12; + break; + case 0x10: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + case 0x83: + EAX = ecx83_msr & 0xffffffff; + EDX = ecx83_msr >> 32; + break; + case 0xC0000081: + EAX = star & 0xffffffff; + EDX = star >> 32; + break; + case 0xC0000084: + EAX = sfmask & 0xffffffff; + EDX = sfmask >> 32; + break; + default: +#ifndef RELEASE_BUILD + pclog("Invalid MSR: %08X\n", ECX); +#endif + x86gpf(NULL, 0); + break; + } + break; + + case CPU_PENTIUM: + case CPU_PENTIUMMMX: + EAX = EDX = 0; + switch (ECX) + { + case 0x10: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + } + break; + case CPU_Cx6x86: + case CPU_Cx6x86L: + case CPU_CxGX1: + case CPU_Cx6x86MX: + switch (ECX) + { + case 0x10: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + } + break; + + case CPU_PENTIUMPRO: + case CPU_PENTIUM2: + case CPU_PENTIUM2D: + EAX = EDX = 0; + // pclog("RDMSR, ECX=%08X\n", ECX); + switch (ECX) + { + case 0x10: + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + break; + case 0x17: + if (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type != CPU_PENTIUM2D) goto i686_invalid_rdmsr; + EAX = ecx17_msr & 0xffffffff; + EDX = ecx17_msr >> 32; + break; + case 0x1B: + EAX = apic_base_msr & 0xffffffff; + EDX = apic_base_msr >> 32; + break; + case 0x2A: + EAX = 0xC5800000; + EDX = 0; + break; + case 0x79: + EAX = ecx79_msr & 0xffffffff; + EDX = ecx79_msr >> 32; + break; + case 0x88 ... 0x8B: + EAX = ecx8x_msr[ECX - 0x88] & 0xffffffff; + EDX = ecx8x_msr[ECX - 0x88] >> 32; + break; + case 0xFE: + EAX = mtrr_cap_msr & 0xffffffff; + EDX = mtrr_cap_msr >> 32; + break; + case 0x116: + EAX = ecx116_msr & 0xffffffff; + EDX = ecx116_msr >> 32; + break; + case 0x118 ... 0x11B: + EAX = ecx11x_msr[ECX - 0x118] & 0xffffffff; + EDX = ecx11x_msr[ECX - 0x118] >> 32; + break; + case 0x11E: + EAX = ecx11e_msr & 0xffffffff; + EDX = ecx11e_msr >> 32; + break; + case 0x174: + if (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_rdmsr; + EAX &= 0xFFFF0000; + EAX |= cs_msr; + break; + case 0x175: + if (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_rdmsr; + EAX = esp_msr; + break; + case 0x176: + if (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_rdmsr; + EAX = eip_msr; + break; + case 0x1E0: + EAX = ecx1e0_msr & 0xffffffff; + EDX = ecx1e0_msr >> 32; + break; + case 0x200 ... 0x20F: + if (ECX & 1) + { + EAX = mtrr_physmask_msr[(ECX - 0x200) >> 1] & 0xffffffff; + EDX = mtrr_physmask_msr[(ECX - 0x200) >> 1] >> 32; + } + else + { + EAX = mtrr_physbase_msr[(ECX - 0x200) >> 1] & 0xffffffff; + EDX = mtrr_physbase_msr[(ECX - 0x200) >> 1] >> 32; + } + break; + case 0x250: + EAX = mtrr_fix64k_8000_msr & 0xffffffff; + EDX = mtrr_fix64k_8000_msr >> 32; + break; + case 0x258: + EAX = mtrr_fix16k_8000_msr & 0xffffffff; + EDX = mtrr_fix16k_8000_msr >> 32; + break; + case 0x259: + EAX = mtrr_fix16k_a000_msr & 0xffffffff; + EDX = mtrr_fix16k_a000_msr >> 32; + break; + case 0x268 ... 0x26F: + // ((ECX - 0x268) * 0x8000) + EAX = mtrr_fix4k_msr[ECX - 0x268] & 0xffffffff; + EDX = mtrr_fix4k_msr[ECX - 0x268] >> 32; + break; + case 0x277: + EAX = pat_msr & 0xffffffff; + EDX = pat_msr >> 32; + break; + case 0x2FF: + EAX = mtrr_deftype_msr & 0xffffffff; + EDX = mtrr_deftype_msr >> 32; + break; + default: +i686_invalid_rdmsr: +#ifndef RELEASE_BUILD + pclog("Invalid MSR: %08X\n", ECX); +#endif + x86gpf(NULL, 0); + break; + } + break; + } +} + +void cpu_WRMSR() +{ + switch (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type) + { + case CPU_WINCHIP: + switch (ECX) + { + case 0x02: + msr.tr1 = EAX & 2; + break; + case 0x0e: + msr.tr12 = EAX & 0x228; + break; + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + case 0x11: + msr.cesr = EAX & 0xff00ff; + break; + case 0x107: + msr.fcr = EAX; + cpu_hasMMX = EAX & (1 << 9); + if (EAX & (1 << 29)) + CPUID = 0; + else + CPUID = models[model].cpu[cpu_manufacturer].cpus[cpu].cpuid_model; + break; + case 0x108: + msr.fcr2 = EAX | ((uint64_t)EDX << 32); + break; + case 0x109: + msr.fcr3 = EAX | ((uint64_t)EDX << 32); + break; + } + break; + case CPU_K5: + case CPU_5K86: + case CPU_K6: + switch (ECX) + { + case 0x0e: + msr.tr12 = EAX & 0x228; + break; + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + case 0x83: + ecx83_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0xC0000081: + star = EAX | ((uint64_t)EDX << 32); + break; + case 0xC0000084: + sfmask = EAX | ((uint64_t)EDX << 32); + break; + } + break; + + case CPU_PENTIUM: + case CPU_PENTIUMMMX: + switch (ECX) + { + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + } + break; + case CPU_Cx6x86: + case CPU_Cx6x86L: + case CPU_CxGX1: + case CPU_Cx6x86MX: + switch (ECX) + { + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + } + break; + + case CPU_PENTIUMPRO: + case CPU_PENTIUM2: + case CPU_PENTIUM2D: + // pclog("WRMSR, ECX=%08X\n", ECX); + switch (ECX) + { + case 0x10: + tsc = EAX | ((uint64_t)EDX << 32); + break; + case 0x17: + if (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type != CPU_PENTIUM2D) goto i686_invalid_wrmsr; + ecx17_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x1B: + apic_base_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x79: + ecx79_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x88 ... 0x8B: + ecx8x_msr[ECX - 0x88] = EAX | ((uint64_t)EDX << 32); + break; + case 0xFE: + mtrr_cap_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x116: + ecx116_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x118 ... 0x011B: + ecx11x_msr[ECX - 0x118] = EAX | ((uint64_t)EDX << 32); + break; + case 0x11E: + ecx11e_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x174: + if (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_wrmsr; + // pclog("WRMSR SYSENTER_CS: old=%04X, new=%04X\n", cs_msr, (uint16_t) (EAX & 0xFFFF)); + cs_msr = EAX & 0xFFFF; + break; + case 0x175: + if (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_wrmsr; + // pclog("WRMSR SYSENTER_ESP: old=%08X, new=%08X\n", esp_msr, EAX); + esp_msr = EAX; + break; + case 0x176: + if (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_PENTIUMPRO) goto i686_invalid_wrmsr; + // pclog("WRMSR SYSENTER_EIP: old=%08X, new=%08X\n", eip_msr, EAX); + eip_msr = EAX; + break; + case 0x1E0: + ecx1e0_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x200 ... 0x20F: + if (ECX & 1) + mtrr_physmask_msr[(ECX - 0x200) >> 1] = EAX | ((uint64_t)EDX << 32); + else + mtrr_physbase_msr[(ECX - 0x200) >> 1] = EAX | ((uint64_t)EDX << 32); + break; + case 0x250: + mtrr_fix64k_8000_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x258: + mtrr_fix16k_8000_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x259: + mtrr_fix16k_a000_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x268 ... 0x26F: + // ((ECX - 0x268) * 0x8000) + mtrr_fix4k_msr[ECX - 0x268] = EAX | ((uint64_t)EDX << 32); + break; + case 0x277: + pat_msr = EAX | ((uint64_t)EDX << 32); + break; + case 0x2FF: + mtrr_deftype_msr = EAX | ((uint64_t)EDX << 32); + break; + default: +i686_invalid_wrmsr: +#ifndef RELEASE_BUILD + pclog("Invalid MSR: %08X\n", ECX); +#endif + x86gpf(NULL, 0); + break; + } + break; + } +} + +static int cyrix_addr; + +void cyrix_write(uint16_t addr, uint8_t val, void *priv) +{ + if (!(addr & 1)) + cyrix_addr = val; + else switch (cyrix_addr) + { + case 0xc0: /*CCR0*/ + ccr0 = val; + break; + case 0xc1: /*CCR1*/ + ccr1 = val; + break; + case 0xc2: /*CCR2*/ + ccr2 = val; + break; + case 0xc3: /*CCR3*/ + ccr3 = val; + break; + case 0xe8: /*CCR4*/ + if ((ccr3 & 0xf0) == 0x10) + { + ccr4 = val; + if (models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type >= CPU_Cx6x86) + { + if (val & 0x80) + CPUID = models[model].cpu[cpu_manufacturer].cpus[cpu].cpuid_model; + else + CPUID = 0; + } + } + break; + case 0xe9: /*CCR5*/ + if ((ccr3 & 0xf0) == 0x10) + ccr5 = val; + break; + case 0xea: /*CCR6*/ + if ((ccr3 & 0xf0) == 0x10) + ccr6 = val; + break; + } +} + +uint8_t cyrix_read(uint16_t addr, void *priv) +{ + if (addr & 1) + { + switch (cyrix_addr) + { + case 0xc0: return ccr0; + case 0xc1: return ccr1; + case 0xc2: return ccr2; + case 0xc3: return ccr3; + case 0xe8: return ((ccr3 & 0xf0) == 0x10) ? ccr4 : 0xff; + case 0xe9: return ((ccr3 & 0xf0) == 0x10) ? ccr5 : 0xff; + case 0xea: return ((ccr3 & 0xf0) == 0x10) ? ccr6 : 0xff; + case 0xfe: return models[model].cpu[cpu_manufacturer].cpus[cpu].cyrix_id & 0xff; + case 0xff: return models[model].cpu[cpu_manufacturer].cpus[cpu].cyrix_id >> 8; + } + if ((cyrix_addr & 0xf0) == 0xc0) return 0xff; + if (cyrix_addr == 0x20 && models[model].cpu[cpu_manufacturer].cpus[cpu].cpu_type == CPU_Cx5x86) return 0xff; + } + return 0xff; +} + +void x86_setopcodes(OpFn *opcodes, OpFn *opcodes_0f, OpFn *dynarec_opcodes, OpFn *dynarec_opcodes_0f) +{ + x86_opcodes = opcodes; + x86_opcodes_0f = opcodes_0f; + x86_dynarec_opcodes = dynarec_opcodes; + x86_dynarec_opcodes_0f = dynarec_opcodes_0f; +} diff --git a/src/cpu.h b/src/cpu.h new file mode 100644 index 000000000..a6d20a365 --- /dev/null +++ b/src/cpu.h @@ -0,0 +1,146 @@ +#ifndef _CPU_H_ +#define _CPU_H_ + +extern int cpu, cpu_manufacturer; + +/*808x class CPUs*/ +#define CPU_8088 0 +#define CPU_8086 1 + +/*286 class CPUs*/ +#define CPU_286 2 + +/*386 class CPUs*/ +#define CPU_386SX 3 +#define CPU_386DX 4 +#define CPU_486SLC 5 +#define CPU_486DLC 6 + +/*486 class CPUs*/ +#define CPU_i486SX 7 +#define CPU_Am486SX 8 +#define CPU_Cx486S 9 +#define CPU_i486DX 10 +#define CPU_Am486DX 11 +#define CPU_Cx486DX 12 +#define CPU_Cx5x86 13 + +/*586 class CPUs*/ +#define CPU_WINCHIP 14 +#define CPU_PENTIUM 15 +#define CPU_PENTIUMMMX 16 +#define CPU_Cx6x86 17 +#define CPU_Cx6x86MX 18 +#define CPU_Cx6x86L 19 +#define CPU_CxGX1 20 +#define CPU_K5 21 +#define CPU_5K86 22 +#define CPU_K6 23 + +/*686 class CPUs*/ +#define CPU_PENTIUMPRO 24 +#define CPU_PENTIUM2 25 +#define CPU_PENTIUM2D 26 + +#define MANU_INTEL 0 +#define MANU_AMD 1 +#define MANU_CYRIX 2 +#define MANU_IDT 3 + +extern int timing_rr; +extern int timing_mr, timing_mrl; +extern int timing_rm, timing_rml; +extern int timing_mm, timing_mml; +extern int timing_bt, timing_bnt; + +extern int timing_int, timing_int_rm, timing_int_v86, timing_int_pm, timing_int_pm_outer; +extern int timing_iret_rm, timing_iret_v86, timing_iret_pm, timing_iret_pm_outer; +extern int timing_call_rm, timing_call_pm, timing_call_pm_gate, timing_call_pm_gate_inner; +extern int timing_retf_rm, timing_retf_pm, timing_retf_pm_outer; +extern int timing_jmp_rm, timing_jmp_pm, timing_jmp_pm_gate; + + +typedef struct +{ + char name[32]; + int cpu_type; + int speed; + int rspeed; + int multi; + int pci_speed; + uint32_t edx_reset; + uint32_t cpuid_model; + uint16_t cyrix_id; + int cpu_flags; +} CPU; + +extern CPU cpus_8088[]; +extern CPU cpus_8086[]; +extern CPU cpus_286[]; +extern CPU cpus_i386[]; +extern CPU cpus_Am386[]; +extern CPU cpus_486SDLC[]; +extern CPU cpus_i486[]; +extern CPU cpus_Am486[]; +extern CPU cpus_Cx486[]; +extern CPU cpus_WinChip[]; +extern CPU cpus_Pentium5V[]; +extern CPU cpus_Pentium5V50[]; +extern CPU cpus_PentiumS5[]; +extern CPU cpus_K5[]; +extern CPU cpus_K56[]; +extern CPU cpus_Pentium[]; +extern CPU cpus_6x86[]; +extern CPU cpus_PentiumPro[]; +extern CPU cpus_Pentium2[]; +extern CPU cpus_Pentium2D[]; + +extern CPU cpus_pcjr[]; +extern CPU cpus_pc1512[]; +extern CPU cpus_ibmat[]; +extern CPU cpus_ps1_m2011[]; +extern CPU cpus_acer[]; + +extern int cpu_iscyrix; +extern int cpu_16bitbus; +extern int cpu_busspeed; +extern int cpu_multi; + +extern int cpu_hasrdtsc; +extern int cpu_hasMSR; +extern int cpu_hasMMX; +extern int cpu_hasCR4; + +#define CR4_TSD (1 << 2) +#define CR4_DE (1 << 3) +#define CR4_MCE (1 << 6) +#define CR4_PCE (1 << 8) +#define CR4_OSFXSR (1 << 9) + +extern uint64_t cpu_CR4_mask; + +#define CPU_SUPPORTS_DYNAREC 1 +// #define CPU_REQUIRES_DYNAREC 2 +#define CPU_REQUIRES_DYNAREC 0 + +extern uint64_t tsc; + +void cyrix_write(uint16_t addr, uint8_t val, void *priv); +uint8_t cyrix_read(uint16_t addr, void *priv); + +extern int is8086; + +void cpu_CPUID(); + +void cpu_RDMSR(); +void cpu_WRMSR(); + +extern int cpu_use_dynarec; + +extern int xt_cpu_multi; + +#define ISA_CYCLES_SHIFT 6 +extern int isa_cycles; +#define ISA_CYCLES(x) ((x * isa_cycles) >> ISA_CYCLES_SHIFT) + +#endif diff --git a/src/dac.c b/src/dac.c new file mode 100644 index 000000000..b09b2fe13 --- /dev/null +++ b/src/dac.c @@ -0,0 +1,68 @@ +#include "ibm.h" + +uint8_t dac,dac2; +uint8_t dacctrl; +int lptfifo; +uint8_t dssbuffer[16]; +int dssstart=0,dssend=0; +int dssmode=0; + +void writedac(uint16_t addr, uint8_t val) +{ + if (dssmode) dac2=val; + else dac=val; +} + +void writedacctrl(uint16_t addr, uint8_t val) +{ +// printf("Write DAC ctrl %02X %i\n",val,lptfifo); + if (dacctrl&8 && !(val&8) && (lptfifo!=16)) + { +// dac=dac2; + dssbuffer[dssend++]=dac2; + dssend&=15; + lptfifo++; + } + dacctrl=val; +} + +uint8_t readdacfifo() +{ + if (lptfifo==16) return 0x40; + return 0; +} + +void pollss() +{ + if (lptfifo) + { + dac=dssbuffer[dssstart++]; + dssstart&=15; + lptfifo--; + } +} + +int16_t dacbuffer[SOUNDBUFLEN+20]; +int dacbufferpos=0; +void getdacsamp() +{ + if (dacbufferposSOUNDBUFLEN) dacbufferpos=SOUNDBUFLEN; + for (c=0;c= 256) + fatal("device_add : too many devices\n"); + + current_device = d; + + priv = d->init(); + if (priv == NULL) + fatal("device_add : device init failed\n"); + + devices[c] = d; + device_priv[c] = priv; +} + +void device_close_all() +{ + int c; + + for (c = 0; c < 256; c++) + { + if (devices[c] != NULL) + { + devices[c]->close(device_priv[c]); + devices[c] = device_priv[c] = NULL; + } + } +} + +int device_available(device_t *d) +{ +#ifdef RELEASE_BUILD + if (d->flags & DEVICE_NOT_WORKING) + return 0; +#endif + if (d->available) + return d->available(); + + return 1; +} + +void device_speed_changed() +{ + int c; + + for (c = 0; c < 256; c++) + { + if (devices[c] != NULL) + { + if (devices[c]->speed_changed != NULL) + { + devices[c]->speed_changed(device_priv[c]); + } + } + } + + sound_speed_changed(); +} + +void device_force_redraw() +{ + int c; + + for (c = 0; c < 256; c++) + { + if (devices[c] != NULL) + { + if (devices[c]->force_redraw != NULL) + { + devices[c]->force_redraw(device_priv[c]); + } + } + } +} + +char *device_add_status_info(char *s, int max_len) +{ + int c; + + for (c = 0; c < 256; c++) + { + if (devices[c] != NULL) + { + if (devices[c]->add_status_info != NULL) + devices[c]->add_status_info(s, max_len, device_priv[c]); + } + } +} + +int device_get_config_int(char *s) +{ + device_config_t *config = current_device->config; + + while (config->type != -1) + { + if (!strcmp(s, config->name)) + return config_get_int(current_device->name, s, config->default_int); + + config++; + } + return 0; +} + +char *device_get_config_string(char *s) +{ + device_config_t *config = current_device->config; + + while (config->type != -1) + { + if (!strcmp(s, config->name)) + return config_get_string(current_device->name, s, config->default_string); + + config++; + } + return NULL; +} diff --git a/src/device.h b/src/device.h new file mode 100644 index 000000000..ffb3ea35b --- /dev/null +++ b/src/device.h @@ -0,0 +1,50 @@ +#define CONFIG_STRING 0 +#define CONFIG_INT 1 +#define CONFIG_BINARY 2 +#define CONFIG_SELECTION 3 +#define CONFIG_MIDI 4 + +typedef struct device_config_selection_t +{ + char description[256]; + int value; +} device_config_selection_t; + +typedef struct device_config_t +{ + char name[256]; + char description[256]; + int type; + char default_string[256]; + int default_int; + device_config_selection_t selection[16]; +} device_config_t; + +typedef struct device_t +{ + char name[50]; + uint32_t flags; + void *(*init)(); + void (*close)(void *p); + int (*available)(); + void (*speed_changed)(void *p); + void (*force_redraw)(void *p); + void (*add_status_info)(char *s, int max_len, void *p); + device_config_t *config; +} device_t; + +void device_init(); +void device_add(device_t *d); +void device_close_all(); +int device_available(device_t *d); +void device_speed_changed(); +void device_force_redraw(); +char *device_add_status_info(char *s, int max_len); + +int device_get_config_int(char *name); +char *device_get_config_string(char *name); + +enum +{ + DEVICE_NOT_WORKING = 1 /*Device does not currently work correctly and will be disabled in a release build*/ +}; diff --git a/src/disc.c b/src/disc.c new file mode 100644 index 000000000..44ace5cc5 --- /dev/null +++ b/src/disc.c @@ -0,0 +1,453 @@ +#include "ibm.h" + +#include "config.h" +#include "disc.h" +#include "disc_fdi.h" +#include "disc_img.h" +#include "fdc.h" +#include "fdd.h" +#include "pit.h" +#include "timer.h" +#include "disc_sector.h" + +int disc_drivesel = 0; +int disc_poll_time = 16; + +int poll_time[2] = {16, 16}; + +int disc_track[2]; +int writeprot[2], fwriteprot[2]; + +DRIVE drives[2]; +int drive_type[2]; + +int curdrive = 0; + +int swwp = 0; +int disable_write = 0; + +//char discfns[2][260] = {"", ""}; +int defaultwriteprot = 0; + +int fdc_time; +int disc_time; + +int fdc_ready; + +int drive_empty[2] = {1, 1}; +int disc_changed[2]; + +int bpulses[2] = {0, 0}; + +int motorspin; +int motoron; + +int fdc_indexcount = 52; + +/*void (*fdc_callback)(); +void (*fdc_data)(uint8_t dat); +void (*fdc_spindown)(); +void (*fdc_finishread)(); +void (*fdc_notfound)(); +void (*fdc_datacrcerror)(); +void (*fdc_headercrcerror)(); +void (*fdc_writeprotect)(); +int (*fdc_getdata)(int last); +void (*fdc_sectorid)(uint8_t track, uint8_t side, uint8_t sector, uint8_t size, uint8_t crc1, uint8_t crc2); +void (*fdc_indexpulse)();*/ + +static struct +{ + char *ext; + void (*load)(int drive, char *fn); + void (*close)(int drive); + int size; +} +loaders[]= +{ + {"IMG", img_load, img_close, -1}, + {"IMA", img_load, img_close, -1}, + {"360", img_load, img_close, -1}, + {"XDF", img_load, img_close, -1}, + {"FDI", fdi_load, fdi_close, -1}, + {0,0,0} +}; + +static int driveloaders[4]; + +void disc_load(int drive, char *fn) +{ + int c = 0, size; + char *p; + FILE *f; +// pclog("disc_load %i %s\n", drive, fn); +// setejecttext(drive, ""); + fdd_stepping_motor_on[drive] = fdd_track_diff[drive] = NULL; + if (!fn) return; + p = get_extension(fn); + if (!p) return; +// setejecttext(drive, fn); + pclog("Loading :%i %s %s\n", drive, fn,p); + f = fopen(fn, "rb"); + if (!f) return; + fseek(f, -1, SEEK_END); + size = ftell(f) + 1; + fclose(f); + while (loaders[c].ext) + { + if (!strcasecmp(p, loaders[c].ext) && (size == loaders[c].size || loaders[c].size == -1)) + { + pclog("Loading as %s\n", p); + driveloaders[drive] = c; + loaders[c].load(drive, fn); + drive_empty[drive] = 0; + disc_changed[drive] = 1; + strcpy(discfns[drive], fn); + return; + } + c++; + } + pclog("Couldn't load %s %s\n",fn,p); + drive_empty[drive] = 1; + discfns[drive][0] = 0; +} + +void disc_close(int drive) +{ +// pclog("disc_close %i\n", drive); + if (loaders[driveloaders[drive]].close) loaders[driveloaders[drive]].close(drive); + drive_empty[drive] = 1; + discfns[drive][0] = 0; + drives[drive].hole = NULL; + drives[drive].poll = NULL; + drives[drive].seek = NULL; + drives[drive].readsector = NULL; + drives[drive].writesector = NULL; + drives[drive].readaddress = NULL; + drives[drive].format = NULL; + drives[drive].realtrack = NULL; + drives[drive].stop = NULL; + fdd_stepping_motor_on[drive] = fdd_track_diff[drive] = 0; +} + +int disc_notfound=0; +int not_found[2] = {0, 0}; +static int disc_period = 32; + +int disc_hole(int drive) +{ + drive ^= fdd_swap; + + if (drives[drive].hole) + { + return drives[drive].hole(drive); + } + else + { + return 0; + } +} + +int disc_byteperiod(int drive) +{ + drive ^= fdd_swap; + + if (drives[drive].byteperiod) + { + return drives[drive].byteperiod(drive); + } + else + { + return 32; + } +} + +#define ACCURATE_TIMER_USEC ((((double) cpuclock) / 1000000.0) * (double)(1 << TIMER_SHIFT)) + +uint32_t byte_pulses = 0; + +#if 0 +void disc_time_adjust() +{ + if (disc_byteperiod(disc_drivesel ^ fdd_swap) == 26) + disc_poll_time -= ((160.0 / 6.0) * ACCURATE_TIMER_USEC); + else + disc_poll_time -= 25.0 * ((double) disc_byteperiod(disc_drivesel ^ fdd_swap)) * ACCURATE_TIMER_USEC; +} + +void disc_poll() +{ + // disc_poll_time += disc_period * TIMER_USEC; + if (disc_byteperiod(disc_drivesel ^ fdd_swap) == 26) + disc_poll_time += ((160.0 / 6.0) * ACCURATE_TIMER_USEC); + else + disc_poll_time += ((double) disc_byteperiod(disc_drivesel ^ fdd_swap)) * ACCURATE_TIMER_USEC; + + byte_pulses++; + if ((byte_pulses > 6250) && (byte_pulses <= 6275)) pclog("Byte pulses is now %i!\n", byte_pulses); + + if (drives[disc_drivesel].poll) + drives[disc_drivesel].poll(disc_drivesel); + + if (disc_notfound) + { + disc_notfound--; + if (!disc_notfound) + fdc_notfound(); + } +} +#endif + +// #define TIMER_SUB 441 // 736 +// #define TIMER_SUB 0 +#define TIMER_SUB 0 + +double dt[2] = {0.0, 0.0}; +double dt2[2] = {0.0, 0.0}; + +void disc_poll_ex(int poll_drive) +{ + int dp = 0; + double pm = 1.0; + + int dbp = disc_byteperiod(poll_drive ^ fdd_swap); + double ddbp = (double) dbp; + + double dtime = 0.0; + + double dusec = (double) TIMER_USEC; + double dsub = (double) TIMER_SUB; + + if (dbp == 26) ddbp = 160.0 / 6.0; + + if (not_found[poll_drive]) + { + not_found[poll_drive]--; + if (!not_found[poll_drive]) + fdc_notfound(); + } + else + { + if (drives[poll_drive].poll) + dp = drives[poll_drive].poll(poll_drive); + } + +#if 0 + if (dp == 2) + { + pm = 15.0 / 16.0; + pclog("SYNC byte detected\n"); + } +#endif + + dtime = (ddbp * pm * dusec) - dsub; + + poll_time[poll_drive] += (int) dtime; + + dt[poll_drive] += dtime; + if (dp) dt2[poll_drive] += dtime; + + if (dp) bpulses[poll_drive]++; + + // if (!dp && (byte_pulses == 10416)) + if (bpulses[poll_drive] == raw_tsize[poll_drive]) + { + pclog("Sent %i byte pulses for drive %c (time: %lf | %lf)\n", raw_tsize[poll_drive], 0x41 + poll_drive, dt[poll_drive], dt2[poll_drive]); + // poll_time[poll_drive] += (dbp * (2.0 / 3.0) * pm * TIMER_USEC) - TIMER_SUB; + // dt[poll_drive] = dt2[poll_drive] = bpulses[poll_drive] = motor_on[poll_drive] = 0; + // disc_stop(poll_drive ^ fdd_swap); /* Send drive to idle state after enough byte pulses have been sent. */ + /* Disc state is already set to idle on finish or error anyway. */ + } +} + +void disc_poll_0() +{ + disc_poll_ex(0); +} + +void disc_poll_1() +{ + disc_poll_ex(1); +} + +int disc_get_bitcell_period(int rate) +{ + int bit_rate; + + switch (rate) + { + case 0: /*High density*/ + bit_rate = 500; + break; + case 1: /*Double density (360 rpm)*/ + bit_rate = 300; + break; + case 2: /*Double density*/ + bit_rate = 250; + break; + case 3: /*Extended density*/ + bit_rate = 1000; + break; + } + + return 1000000 / bit_rate*2; /*Bitcell period in ns*/ +} + + +void disc_set_rate(int drive, int drvden, int rate) +{ + switch (rate) + { + case 0: /*High density*/ + disc_period = 16; + break; + case 1: + switch(drvden) + { + case 0: /*Double density (360 rpm)*/ + disc_period = 26; + break; + case 1: /*High density (360 rpm)*/ + disc_period = 16; + break; + case 2: + disc_period = 4; + break; + } + case 2: /*Double density*/ + disc_period = 32; + break; + case 3: /*Extended density*/ + disc_period = 8; + break; + } +} + +void disc_reset() +{ + curdrive = 0; + disc_period = 32; + fdd_stepping_motor_on[0] = fdd_track_diff[0] = 0; + fdd_stepping_motor_on[1] = fdd_track_diff[1] = 0; + // timer_add(disc_poll, &disc_poll_time, &motoron, NULL); + timer_add(disc_poll_0, &(poll_time[0]), &(motor_on[0]), NULL); + timer_add(disc_poll_1, &(poll_time[1]), &(motor_on[1]), NULL); +} + +void disc_init() +{ +// pclog("disc_init %p\n", drives); + drives[0].poll = drives[1].poll = 0; + drives[0].seek = drives[1].seek = 0; + drives[0].readsector = drives[1].readsector = 0; + disc_reset(); +} + +int oldtrack[2] = {0, 0}; +void disc_seek(int drive, int track) +{ +// pclog("disc_seek: drive=%i track=%i\n", drive, track); + if (drives[drive].seek) + drives[drive].seek(drive, track); +// if (track != oldtrack[drive]) +// fdc_discchange_clear(drive); +// ddnoise_seek(track - oldtrack[drive]); +// oldtrack[drive] = track; +} + +void disc_readsector(int drive, int sector, int track, int side, int density, int sector_size) +{ + drive ^= fdd_swap; + + if (drives[drive].readsector) + { + drives[drive].readsector(drive, sector, track, side, density, sector_size); + pclog("Byte pulses: %i\n", bpulses[drive]); + bpulses[drive] = 0; + dt[drive] = dt2[drive] = 0; + // motor_on[drive] = 1; + poll_time[drive] = 0; + } + else + not_found[drive] = 1000; +#if 0 + disc_notfound = 1000; +#endif +} + +void disc_writesector(int drive, int sector, int track, int side, int density, int sector_size) +{ + drive ^= fdd_swap; + + if (drives[drive].writesector) + { + drives[drive].writesector(drive, sector, track, side, density, sector_size); + bpulses[drive] = 0; + dt[drive] = dt2[drive] = 0; + // motor_on[drive] = 1; + poll_time[drive] = 0; + } + else + not_found[drive] = 1000; +#if 0 + disc_notfound = 1000; +#endif +} + +void disc_readaddress(int drive, int track, int side, int density) +{ + drive ^= fdd_swap; + + if (drives[drive].readaddress) + { + drives[drive].readaddress(drive, track, side, density); + bpulses[drive] = 0; + dt[drive] = dt2[drive] = 0; + // motor_on[drive] = 1; + poll_time[drive] = 0; + } +} + +void disc_format(int drive, int track, int side, int density, uint8_t fill) +{ + drive ^= fdd_swap; + + if (drives[drive].format) + { + drives[drive].format(drive, track, side, density, fill); + bpulses[drive] = 0; + dt[drive] = dt2[drive] = 0; + // motor_on[drive] = 1; + poll_time[drive] = 0; + } + else + not_found[drive] = 1000; +#if 0 + disc_notfound = 1000; +#endif +} + +int disc_realtrack(int drive, int track) +{ + drive ^= fdd_swap; + + if (drives[drive].realtrack) + return drives[drive].realtrack(drive, track); + else + return track; +} + +void disc_stop(int drive) +{ + drive ^= fdd_swap; + + if (drives[drive].stop) + drives[drive].stop(drive); +} + +void disc_set_drivesel(int drive) +{ + drive ^= fdd_swap; + + disc_drivesel = drive; +} diff --git a/src/disc.h b/src/disc.h new file mode 100644 index 000000000..eca729570 --- /dev/null +++ b/src/disc.h @@ -0,0 +1,83 @@ +typedef struct +{ + void (*seek)(int drive, int track); + void (*readsector)(int drive, int sector, int track, int side, int density, int sector_size); + void (*writesector)(int drive, int sector, int track, int side, int density, int sector_size); + void (*readaddress)(int drive, int track, int side, int density); + void (*format)(int drive, int track, int side, int density, uint8_t fill); + int (*hole)(int drive); + int (*byteperiod)(int drive); + void (*stop)(int drive); + int (*poll)(int drive); + int (*realtrack)(int drive, int track); +} DRIVE; + +extern DRIVE drives[2]; + +extern int curdrive; + +void disc_load(int drive, char *fn); +void disc_new(int drive, char *fn); +void disc_close(int drive); +void disc_init(); +void disc_reset(); +void disc_poll(); +void disc_seek(int drive, int track); +void disc_readsector(int drive, int sector, int track, int side, int density, int sector_size); +void disc_writesector(int drive, int sector, int track, int side, int density, int sector_size); +void disc_readaddress(int drive, int track, int side, int density); +void disc_format(int drive, int track, int side, int density, uint8_t fill); +void disc_time_adjust(); +int disc_realtrack(int drive, int track); +int disc_hole(int drive); +int disc_byteperiod(int drive); +void disc_stop(int drive); +int disc_empty(int drive); +void disc_set_rate(int drive, int drvden, int rate); +void disc_set_drivesel(int drive); +extern int disc_time; +extern int disc_poll_time; +extern int poll_time[2]; +extern int disc_drivesel; +extern int disc_notfound; +extern int not_found[2]; + +void fdc_callback(); +int fdc_data(uint8_t dat); +void fdc_spindown(); +void fdc_finishread(); +void fdc_notfound(); +void fdc_datacrcerror(); +void fdc_headercrcerror(); +void fdc_writeprotect(); +int fdc_getdata(int last); +void fdc_sectorid(uint8_t track, uint8_t side, uint8_t sector, uint8_t size, uint8_t crc1, uint8_t crc2); +void fdc_indexpulse(); +/*extern int fdc_time; +extern int fdc_ready; +extern int fdc_indexcount;*/ + +extern int motorspin; +extern int motoron; + +extern int motor_on[2]; + +extern int swwp; +extern int disable_write; + +extern int defaultwriteprot; +//extern char discfns[4][260]; + +extern int writeprot[2], fwriteprot[2]; +extern int disc_track[2]; +extern int disc_changed[2]; +extern int drive_empty[2]; +extern int drive_type[2]; + +extern uint32_t byte_pulses; + +extern int bpulses[2]; + +/*Used in the Read A Track command. Only valid for disc_readsector(). */ +#define SECTOR_FIRST -2 +#define SECTOR_NEXT -1 diff --git a/src/disc_fdi.c b/src/disc_fdi.c new file mode 100644 index 000000000..1bda2ff44 --- /dev/null +++ b/src/disc_fdi.c @@ -0,0 +1,513 @@ +#include +#include +#include "ibm.h" +#include "disc.h" +#include "disc_fdi.h" +#include "fdi2raw.h" + +static struct +{ + FILE *f; + FDI *h; + uint8_t track_data[2][4][256*1024]; + + int sides; + int tracklen[2][4]; + int trackindex[2][4]; + + int lasttrack; +} fdi[2]; + +static uint8_t fdi_timing[256*1024]; +#if 0 +static int fdi_pos; +static int fdi_revs; + +static int fdi_sector, fdi_track, fdi_side, fdi_drive, fdi_density, fdi_n; +static int fdi_inread, fdi_inwrite, fdi_readpos, fdi_inreadaddr; +#endif + +static int fdi_pos[2]; +static int fdi_revs[2]; + +static int fdi_sector[2], fdi_track[2], fdi_side[2], fdi_drive[2], fdi_density[2], fdi_n[2]; +static int fdi_inread[2], fdi_inwrite[2], fdi_readpos[2], fdi_inreadaddr[2]; + +static uint16_t CRCTable[256]; + +static int pollbytesleft[2]={0, 0},pollbitsleft[2]={0, 0}; + +int fdi_realtrack(int drive, int track) +{ + return track; +} + +static void fdi_setupcrc(uint16_t poly, uint16_t rvalue) +{ + int c = 256, bc; + uint16_t crctemp; + + while(c--) + { + crctemp = c << 8; + bc = 8; + + while(bc--) + { + if(crctemp & 0x8000) + { + crctemp = (crctemp << 1) ^ poly; + } + else + { + crctemp <<= 1; + } + } + + CRCTable[c] = crctemp; + } +} + +void fdi_init() +{ +// printf("FDI reset\n"); + memset(&fdi, 0, sizeof(fdi)); + fdi_setupcrc(0x1021, 0xcdb4); +} + +int fdi_hole(int drive) +{ + switch (fdi2raw_get_bit_rate(fdi[drive].h)) + { + case 1000: + return 2; + case 500: + return 1; + default: + return 0; + } +} + +int fdi_byteperiod(int drive) +{ + switch (fdi2raw_get_bit_rate(fdi[drive].h)) + { + case 1000: + return 8; + case 500: + return 16; + case 300: + return 26; + case 250: + return 32; + default: + return 0; + } +} + +void fdi_load(int drive, char *fn) +{ + writeprot[drive] = fwriteprot[drive] = 1; + fdi[drive].f = fopen(fn, "rb"); + if (!fdi[drive].f) return; + fdi[drive].h = fdi2raw_header(fdi[drive].f); +// if (!fdih[drive]) printf("Failed to load!\n"); + fdi[drive].lasttrack = fdi2raw_get_last_track(fdi[drive].h); + fdi[drive].sides = fdi2raw_get_last_head(fdi[drive].h) + 1; +// printf("Last track %i\n",fdilasttrack[drive]); + drives[drive].seek = fdi_seek; + drives[drive].readsector = fdi_readsector; + drives[drive].writesector = fdi_writesector; + drives[drive].readaddress = fdi_readaddress; + drives[drive].hole = fdi_hole; + drives[drive].byteperiod = fdi_byteperiod; + drives[drive].poll = fdi_poll; + drives[drive].format = fdi_format; + drives[drive].stop = fdi_stop; + drives[drive].realtrack = fdi_realtrack; +// pclog("Loaded as FDI\n"); +} + +void fdi_close(int drive) +{ + if (fdi[drive].h) + fdi2raw_header_free(fdi[drive].h); + if (fdi[drive].f) + fclose(fdi[drive].f); + fdi[drive].f = NULL; +} + +void fdi_seek(int drive, int track) +{ + int c; + int density; + + if (!fdi[drive].f) + return; +// printf("Track start %i\n",track); + if (track < 0) + track = 0; + if (track > fdi[drive].lasttrack) + track = fdi[drive].lasttrack - 1; + + for (density = 0; density < 4; density++) + { + int c = fdi2raw_loadtrack(fdi[drive].h, (uint16_t *)fdi[drive].track_data[0][density], + (uint16_t *)fdi_timing, + track * fdi[drive].sides, + &fdi[drive].tracklen[0][density], + &fdi[drive].trackindex[0][density], NULL, density); + if (!c) + memset(fdi[drive].track_data[0][density], 0, fdi[drive].tracklen[0][density]); + + if (fdi[drive].sides == 2) + { + c = fdi2raw_loadtrack(fdi[drive].h, (uint16_t *)fdi[drive].track_data[1][density], + (uint16_t *)fdi_timing, + (track * fdi[drive].sides) + 1, + &fdi[drive].tracklen[1][density], + &fdi[drive].trackindex[1][density], NULL, density); + if (!c) + memset(fdi[drive].track_data[1][density], 0, fdi[drive].tracklen[1][density]); + } + else + { + memset(fdi[drive].track_data[1][density], 0, 65536); + fdi[drive].tracklen[0][density] = fdi[drive].tracklen[1][density] = 10000; + } + } +} + +void fdi_writeback(int drive, int track) +{ + return; +} + +void fdi_readsector(int drive, int sector, int track, int side, int rate, int sector_size) +{ + fdi_revs[drive] = 0; + fdi_sector[drive] = sector; + fdi_track[drive] = track; + fdi_side[drive] = side; + fdi_n[drive] = sector_size; + // fdi_drive = drive; + if (rate == 2) + fdi_density[drive] = 1; + if (rate == 0) + fdi_density[drive] = 2; + if (rate == 3) + fdi_density[drive] = 3; + +// pclog("FDI Read sector %i %i %i %i %i\n",drive,side,track,sector, fdi_density); +// if (pollbytesleft) +// pclog("In the middle of a sector!\n"); + + fdi_inread[drive] = 1; + fdi_inwrite[drive] = 0; + fdi_inreadaddr[drive] = 0; + fdi_readpos[drive] = 0; +} + +void fdi_writesector(int drive, int sector, int track, int side, int rate, int sector_size) +{ + fdi_revs[drive] = 0; + fdi_sector[drive] = sector; + fdi_track[drive] = track; + fdi_side[drive] = side; + fdi_n[drive] = sector_size; + // fdi_drive = drive; + if (rate == 2) + fdi_density[drive] = 1; + if (rate == 0) + fdi_density[drive] = 2; + if (rate == 3) + fdi_density[drive] = 3; +// pclog("Write sector %i %i %i %i\n",drive,side,track,sector); + + fdi_inread[drive] = 0; + fdi_inwrite[drive] = 1; + fdi_inreadaddr[drive] = 0; + fdi_readpos[drive] = 0; +} + +void fdi_readaddress(int drive, int track, int side, int rate) +{ + fdi_revs[drive] = 0; + fdi_track[drive] = track; + fdi_side[drive] = side; + // fdi_drive = drive; + if (rate == 2) + fdi_density[drive] = 1; + if (rate == 0) + fdi_density[drive] = 2; + if (rate == 3) + fdi_density[drive] = 3; +// pclog("Read address %i %i %i %i %i %p\n",drive,side,track, rate, fdi_density, &fdi_inreadaddr); + + fdi_inread[drive] = 0; + fdi_inwrite[drive] = 0; + fdi_inreadaddr[drive] = 1; + fdi_readpos[drive] = 0; +} + +void fdi_format(int drive, int track, int side, int rate, uint8_t fill) +{ + fdi_revs[drive] = 0; + fdi_track[drive] = track; + fdi_side[drive] = side; + // fdi_drive = drive; + if (rate == 2) + fdi_density[drive] = 1; + if (rate == 0) + fdi_density[drive] = 2; + if (rate == 3) + fdi_density[drive] = 3; +// pclog("Format %i %i %i\n",drive,side,track); + + fdi_inread[drive] = 0; + fdi_inwrite[drive] = 1; + fdi_inreadaddr[drive] = 0; + fdi_readpos[drive] = 0; +} + +static uint16_t fdi_buffer[2]; +static int readidpoll[2]={0, 0},readdatapoll[2]={0, 0},fdi_nextsector[2]={0, 0},inreadop[2]={0, 0}; +static uint8_t fdi_sectordat[2][1026]; +static int lastfdidat[2][2],sectorcrc[2][2]; +static int sectorsize[2],fdc_sectorsize[2]; +static int ddidbitsleft[2]={0, 0}; + +static uint8_t decodefm(uint16_t dat) +{ + uint8_t temp; + temp = 0; + if (dat & 0x0001) temp |= 1; + if (dat & 0x0004) temp |= 2; + if (dat & 0x0010) temp |= 4; + if (dat & 0x0040) temp |= 8; + if (dat & 0x0100) temp |= 16; + if (dat & 0x0400) temp |= 32; + if (dat & 0x1000) temp |= 64; + if (dat & 0x4000) temp |= 128; + return temp; +} + +void fdi_stop(int drive) +{ +// pclog("fdi_stop\n"); + fdi_inread[drive] = fdi_inwrite[drive] = fdi_inreadaddr[drive] = 0; + fdi_nextsector[drive] = ddidbitsleft[drive] = pollbitsleft[drive] = 0; +} + +static uint16_t crc[2]; + +static void calccrc(int drive, uint8_t byte) +{ + crc[drive] = (crc[drive] << 8) ^ CRCTable[(crc[drive] >> 8)^byte]; +} + +static int fdi_indextime_blank[2] = {6250 * 8, 6250 * 8}; +int fdi_poll(int drive) +{ + int tempi, c; + int bitcount; + + for (bitcount = 0; bitcount < 16; bitcount++) + { + if (fdi_pos[drive] >= fdi[drive].tracklen[fdi_side[drive]][fdi_density[drive]]) + { + fdi_pos[drive] = 0; + if (fdi[drive].tracklen[fdi_side[drive]][fdi_density[drive]]) + fdc_indexpulse(); + else + { + fdi_indextime_blank[drive]--; + if (!fdi_indextime_blank[drive]) + { + fdi_indextime_blank[drive] = 6250 * 8; + fdc_indexpulse(); + } + } + } + tempi = fdi[drive].track_data[fdi_side[drive]][fdi_density[drive]][((fdi_pos[drive] >> 3) & 0xFFFF) ^ 1] & (1 << (7 - (fdi_pos[drive] & 7))); + fdi_pos[drive]++; + fdi_buffer[drive] <<= 1; + fdi_buffer[drive] |= (tempi ? 1 : 0); + if (fdi_inwrite[drive]) + { + fdi_inwrite[drive] = 0; + fdc_writeprotect(); + return 1; + } + if (!fdi_inread[drive] && !fdi_inreadaddr[drive]) + return 1; + if (fdi_pos[drive] == fdi[drive].trackindex[fdi_side[drive]][fdi_density[drive]]) + { + fdi_revs[drive]++; + if (fdi_revs[drive] == 3) + { +// pclog("Not found!\n"); + fdc_notfound(); + fdi_inread[drive] = fdi_inreadaddr[drive] = 0; + return 1; + } + if (fdi_sector[drive] == SECTOR_FIRST) + fdi_sector[drive] = SECTOR_NEXT; + } + if (pollbitsleft[drive]) + { + pollbitsleft[drive]--; + if (!pollbitsleft[drive]) + { + pollbytesleft[drive]--; + if (pollbytesleft[drive]) pollbitsleft[drive] = 16; /*Set up another word if we need it*/ + if (readidpoll[drive]) + { + fdi_sectordat[drive][5 - pollbytesleft[drive]] = decodefm(fdi_buffer[drive]); + if (fdi_inreadaddr[drive] && !fdc_sectorid)// && pollbytesleft[drive] > 1) + { +// rpclog("inreadaddr - %02X\n", fdi_sectordat[drive][5 - pollbytesleft][drive]); + fdc_data(fdi_sectordat[drive][5 - pollbytesleft[drive]]); + } + if (!pollbytesleft[drive]) + { +// pclog("Header over %i,%i %i,%i\n", fdi_sectordat[drive][0], fdi_sectordat[drive][2], fdi_track[drive], fdi_sector[drive]); + if ((fdi_sectordat[drive][0] == fdi_track[drive] && (fdi_sectordat[drive][3] == fdi_n[drive]) && (fdi_sectordat[drive][2] == fdi_sector[drive] || fdi_sector[drive] == SECTOR_NEXT)) || fdi_inreadaddr[drive]) + { + crc[drive] = (fdi_density) ? 0xcdb4 : 0xffff; + calccrc(drive, 0xFE); + for (c = 0; c < 4; c++) + calccrc(drive, fdi_sectordat[drive][c]); + + if ((crc[drive] >> 8) != fdi_sectordat[drive][4] || (crc[drive] & 0xFF) != fdi_sectordat[drive][5]) + { +// pclog("Header CRC error : %02X %02X %02X %02X\n",crc[drive]>>8,crc[drive]&0xFF,fdi_sectordat[drive][4],fdi_sectordat[drive][5]); +// dumpregs(); +// exit(-1); + inreadop[drive] = 0; + if (fdi_inreadaddr[drive]) + { +// rpclog("inreadaddr - %02X\n", fdi_sector[drive]); +// fdc_data(fdi_sector[drive]); + if (fdc_sectorid) + fdc_sectorid(fdi_sectordat[drive][0], fdi_sectordat[drive][1], fdi_sectordat[drive][2], fdi_sectordat[drive][3], fdi_sectordat[drive][4], fdi_sectordat[drive][5]); + else + fdc_finishread(drive); + } + else fdc_headercrcerror(); + return 1; + } +// pclog("Sector %i,%i %i,%i\n", fdi_sectordat[drive][0], fdi_sectordat[drive][2], fdi_track[drive], fdi_sector[drive]); + if (fdi_sectordat[drive][0] == fdi_track[drive] && (fdi_sectordat[drive][2] == fdi_sector[drive] || fdi_sector[drive] == SECTOR_NEXT) && fdi_inread[drive] && !fdi_inreadaddr[drive]) + { + fdi_nextsector[drive] = 1; + readidpoll[drive] = 0; + sectorsize[drive] = (1 << (fdi_sectordat[drive][3] + 7)) + 2; + fdc_sectorsize[drive] = fdi_sectordat[drive][3]; + } + if (fdi_inreadaddr[drive]) + { + if (fdc_sectorid) + fdc_sectorid(fdi_sectordat[drive][0], fdi_sectordat[drive][1], fdi_sectordat[drive][2], fdi_sectordat[drive][3], fdi_sectordat[drive][4], fdi_sectordat[drive][5]); + else + fdc_finishread(drive); + fdi_inreadaddr[drive] = 0; + } + } + } + } + if (readdatapoll[drive]) + { +// pclog("readdatapoll %i %02x\n", pollbytesleft[drive], decodefm(fdi_buffer[drive])); + if (pollbytesleft[drive] > 1) + { + calccrc(drive, decodefm(fdi_buffer[drive])); + } + else + sectorcrc[drive][1 - pollbytesleft[drive]] = decodefm(fdi_buffer[drive]); + if (!pollbytesleft[drive]) + { + fdi_inread[drive] = 0; +//#if 0 + if ((crc[drive] >> 8) != sectorcrc[drive][0] || (crc[drive] & 0xFF) != sectorcrc[drive][1])// || (fditrack[drive]==79 && fdisect[drive]==4 && fdc_side[drive]&1)) + { +// pclog("Data CRC error : %02X %02X %02X %02X %i %04X %02X%02X\n",crc[drive]>>8,crc[drive]&0xFF,sectorcrc[0],sectorcrc[1],fdi_pos,crc,sectorcrc[0],sectorcrc[1]); + inreadop[drive] = 0; + fdc_data(decodefm(lastfdidat[drive][1])); + fdc_finishread(drive); + fdc_datacrcerror(); + readdatapoll[drive] = 0; + return 1; + } +//#endif +// pclog("End of FDI read %02X %02X %02X %02X\n",crc[drive]>>8,crc[drive]&0xFF,sectorcrc[0],sectorcrc[1]); + fdc_data(decodefm(lastfdidat[drive][1])); + fdc_finishread(drive); + } + else if (lastfdidat[drive][1] != 0) + fdc_data(decodefm(lastfdidat[drive][1])); + lastfdidat[drive][1] = lastfdidat[drive][0]; + lastfdidat[drive][0] = fdi_buffer[drive]; + if (!pollbytesleft[drive]) + readdatapoll[drive] = 0; + } + } + } + if (fdi_buffer[drive] == 0x4489 && fdi_density[drive]) + { +// rpclog("Found sync\n"); + ddidbitsleft[drive] = 17; + } + + if (fdi_buffer[drive] == 0xF57E && !fdi_density[drive]) + { + pollbytesleft[drive] = 6; + pollbitsleft[drive] = 16; + readidpoll[drive] = 1; + } + if ((fdi_buffer[drive] == 0xF56F || fdi_buffer[drive] == 0xF56A) && !fdi_density[drive]) + { + if (fdi_nextsector[drive]) + { + pollbytesleft[drive] = sectorsize[drive]; + pollbitsleft[drive] = 16; + readdatapoll[drive] = 1; + fdi_nextsector[drive] = 0; + crc[drive] = 0xffff; + if (fdi_buffer[drive] == 0xF56A) calccrc(drive, 0xF8); + else calccrc(drive, 0xFB); + lastfdidat[drive][0] = lastfdidat[drive][1] = 0; + } + } + if (ddidbitsleft[drive]) + { + ddidbitsleft[drive]--; + if (!ddidbitsleft[drive] && !readdatapoll[drive]) + { +// printf("ID bits over %04X %02X %i\n",fdibuffer[drive],decodefm(fdibuffer[drive]),fdipos[drive]); + if (decodefm(fdi_buffer[drive]) == 0xFE) + { +// printf("Sector header %i %i\n", fdi_inread[drive], fdi_inreadaddr[drive]); + pollbytesleft[drive] = 6; + pollbitsleft[drive] = 16; + readidpoll[drive] = 1; + } + else if (decodefm(fdi_buffer[drive]) == 0xFB) + { +// printf("Data header %i %i\n", fdi_inread[drive], fdi_inreadaddr[drive]); + if (fdi_nextsector[drive]) + { + pollbytesleft[drive] = sectorsize[drive]; + pollbitsleft[drive] = 16; + readdatapoll[drive] = 1; + fdi_nextsector[drive] = 0; + crc[drive] = 0xcdb4; + if (fdi_buffer[drive] == 0xF56A) calccrc(drive, 0xF8); + else calccrc(drive, 0xFB); + lastfdidat[drive][0] = lastfdidat[drive][1] = 0; + } + } + } + } + } +} diff --git a/src/disc_fdi.h b/src/disc_fdi.h new file mode 100644 index 000000000..f62fb165f --- /dev/null +++ b/src/disc_fdi.h @@ -0,0 +1,13 @@ +void fdi_init(); +void fdi_load(int drive, char *fn); +void fdi_close(int drive); +void fdi_seek(int drive, int track); +void fdi_readsector(int drive, int sector, int track, int side, int density, int sector_size); +void fdi_writesector(int drive, int sector, int track, int side, int density, int sector_size); +void fdi_readaddress(int drive, int sector, int side, int density); +void fdi_format(int drive, int sector, int side, int density, uint8_t fill); +int fdi_hole(int drive); +int fdi_byteperiod(int drive); +void fdi_stop(int drive); +int fdi_poll(int drive); +int fdi_realtrack(int track, int drive); diff --git a/src/disc_img.c b/src/disc_img.c new file mode 100644 index 000000000..8700ceb18 --- /dev/null +++ b/src/disc_img.c @@ -0,0 +1,702 @@ +#include "ibm.h" +#include "fdd.h" +#include "disc.h" +#include "disc_img.h" +#include "disc_sector.h" + +static struct +{ + FILE *f; + // uint8_t track_data[2][20*1024]; + uint8_t track_data[2][50000]; + int sectors, tracks, sides; + int sector_size; + int rate; + int xdf_type; /* 0 = not XDF, 1-5 = one of the five XDF types */ + int hole; + int byte_period; + double bitcell_period_300rpm; +} img[2]; + +#if 0 +static uint8_t xdf_track0[5][3]; +static uint8_t xdf_spt[5]; +static uint8_t xdf_map[5][24][3]; +#endif +static uint8_t xdf_track0[3][3]; +static uint8_t xdf_spt[3]; +static uint8_t xdf_map[3][24][3]; +static uint16_t xdf_track0_layout[3][92] = { { 0x8100, 0x8200, 0x8300, 0x8400, 0x8500, 0x8600, 0x8700, 0x8800, + 0x8101, 0x8201, 0x0100, 0x0200, 0x0300, 0x0400, 0x0500, 0x0600, + 0x0700, 0x0800, 0, 0x8301, 0x8401, 0x8501, 0x8601, 0x8701, + 0x8801, 0x8901, 0x8A01, 0x8B01, 0x8C01, 0x8D01, 0x8E01, 0x8F01, + 0x9001 }, /* 5.25" 2HD */ + { 0x8100, 0x8200, 0x8300, 0x8400, 0x8500, 0x8600, 0x8700, 0x8800, + 0x8900, 0x8A00, 0x8B00, 0x8101, 0x0100, 0x0200, 0x0300, 0x0400, + 0x0500, 0x0600, 0x0700, 0x0800, 0, 0, 0, 0x8201, + 0x8301, 0x8401, 0x8501, 0x8601, 0x8701, 0x8801, 0x8901, 0x8A01, + 0x8B01, 0x8C01, 0x8D01, 0x8E01, 0x8F01, 0, 0, 0, + 0, 0, 0x9001, 0x9101, 0x9201, 0x9301 }, /* 3.5" 2HD */ + { 0x8100, 0x8200, 0x8300, 0x8400, 0x8500, 0x8600, 0x8700, 0x8800, + 0x8900, 0x8A00, 0x8B00, 0x8C00, 0x0100, 0x0200, 0x0300, 0x0400, + 0x0500, 0x0600, 0x0700, 0x0800, 0x9500, 0x9600, 0x9700, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0x8D00, 0x8E00, 0x8F00, 0x9000, 0, 0, + 0, 0, 0, 0, 0, 0x9800, 0x9900, 0x9A00, + 0x9B00, 0x9C00, 0x9D00, 0x9E00, 0x8101, 0x8201, 0x8301, 0x8401, + 0x8501, 0x8601, 0x8701, 0x9100, 0x9200, 0x9300, 0x9400, 0x8801, + 0x8901, 0x8A01, 0x8B01, 0x8C01, 0x8D01, 0x8E01, 0x8F01, 0x9001, + 0x9101, 0x9201, 0x9301, 0x9401, 0x9501, 0x9601, 0x9701, 0x9801, + 0x9901, 0x9A01, 0x9B01, 0x9C01, 0x9D01, 0x9E01, 0x9F01, 0xA001, + 0xA101, 0xA201, 0xA301, 0xA401 }, /* 3.5" 2ED - sectors 0x91 to 0x94 of side 0 are not written to the IMG file but + we read them in from the null-filled areas in order to have them as XDFCOPY + still expects their existence even if it does nothing with them. */ + }; + +/* First dimension is possible sector sizes (0 = 128, 7 = 16384), second is possible bit rates (250/360, 250, 300, 500/360, 500, 1000). */ +/* Disks formatted at 250 kbps @ 360 RPM can be read with a 360 RPM single-RPM 5.25" drive by setting the rate to 250 kbps. + Disks formatted at 300 kbps @ 300 RPM can be read with any 300 RPM single-RPM drive by setting the rate rate to 300 kbps. */ +static uint8_t maximum_sectors[8][6] = { { 26, 31, 38, 53, 64, 118 }, /* 128 */ + { 15, 19, 23, 32, 38, 73 }, /* 256 */ + { 7, 10, 12, 19, 23, 46 }, /* 512 */ + { 3, 5, 6, 9, 11, 22 }, /* 1024 */ + { 2, 2, 3, 4, 5, 11 }, /* 2048 */ + { 1, 1, 1, 2, 2, 5 }, /* 4096 */ + { 0, 0, 0, 1, 1, 3 }, /* 8192 */ + { 0, 0, 0, 0, 0, 1 } }; /* 16384 */ + +static int gap3_sizes[5][8][256] = { [0][1][16] = 0x54, + [0][2][18] = 0x6C, + [0][2][19] = 0x48, + [0][2][20] = 0x2A, + [0][2][21] = 0x0C, + // [0][2][23] = 0x7A, + [0][2][23] = 0x01, + // [0][2][24] = 0x38, + [2][1][10] = 0x32, + [2][1][11] = 0x0C, + [2][1][15] = 0x36, + [2][1][16] = 0x32, + [2][2][8] = 0x58, + [2][2][9] = 0x50, + [2][2][10] = 0x2E, + [2][2][11] = 0x02, + [2][2][21] = 0x1C, + [2][3][4] = 0xF0, + [2][3][5] = 0x74, + [3][2][36] = 0x53, + [3][2][39] = 0x20, + // [3][2][46] = 0x0E, + [3][2][46] = 0x01, + // [3][2][48] = 0x51, + [4][1][32] = 0x36, + [4][2][15] = 0x54, + [4][2][17] = 0x23, + [4][2][18] = 0x02, + // [4][2][19] = 0x29, + [4][2][19] = 0x01, + [4][3][8] = 0x74, + [4][3][9] = 0x74, + [4][3][10] = 0x74 +}; + +/* Needed for formatting! */ +int img_realtrack(int drive, int track) +{ +#ifdef MAINLINE + if ((img[drive].tracks <= 41) && fdd_doublestep_40(drive)) +#else + if ((img[drive].tracks <= 43) && fdd_doublestep_40(drive)) +#endif + track /= 2; + + return track; +} + +void img_writeback(int drive, int track); + +static int img_sector_size_code(int drive) +{ + switch(img[drive].sector_size) + { + case 128: + return 0; + case 256: + return 1; + default: + case 512: + return 2; + case 1024: + return 3; + case 2048: + return 4; + case 4096: + return 5; + case 8192: + return 6; + case 16384: + return 7; + } +} + +static int sector_size_code(int sector_size) +{ + switch(sector_size) + { + case 128: + return 0; + case 256: + return 1; + default: + case 512: + return 2; + case 1024: + return 3; + case 2048: + return 4; + case 4096: + return 5; + case 8192: + return 6; + case 16384: + return 7; + } +} + +void img_init() +{ + memset(img, 0, sizeof(img)); +// adl[0] = adl[1] = 0; +} + +static void add_to_map(uint8_t *arr, uint8_t p1, uint8_t p2, uint8_t p3) +{ + arr[0] = p1; + arr[1] = p2; + arr[2] = p3; +} + +static int xdf_maps_initialized = 0; + +static void initialize_xdf_maps() +{ + // XDF 5.25" 2HD + /* Adds, in this order: sectors per FAT, sectors per each side of track 0, difference between that and virtual sector number specified in BPB. */ + add_to_map(xdf_track0[0], 9, 17, 2); + xdf_spt[0] = 3; + /* Adds, in this order: side, sequential order (not used in PCem), sector size. */ + add_to_map(xdf_map[0][0], 0, 0, 3); + add_to_map(xdf_map[0][1], 0, 2, 6); + add_to_map(xdf_map[0][2], 1, 0, 2); + add_to_map(xdf_map[0][3], 0, 1, 2); + add_to_map(xdf_map[0][4], 1, 2, 6); + add_to_map(xdf_map[0][5], 1, 1, 3); + + // XDF 3.5" 2HD + add_to_map(xdf_track0[1], 11, 19, 4); + xdf_spt[1] = 4; + add_to_map(xdf_map[1][0], 0, 0, 3); + add_to_map(xdf_map[1][1], 0, 2, 4); + add_to_map(xdf_map[1][2], 1, 3, 6); + add_to_map(xdf_map[1][3], 0, 1, 2); + add_to_map(xdf_map[1][4], 1, 1, 2); + add_to_map(xdf_map[1][5], 0, 3, 6); + add_to_map(xdf_map[1][6], 1, 0, 4); + add_to_map(xdf_map[1][7], 1, 2, 3); + + // XDF 3.5" 2ED + add_to_map(xdf_track0[2], 22, 37, 9); + xdf_spt[2] = 4; + add_to_map(xdf_map[2][0], 0, 0, 3); + add_to_map(xdf_map[2][1], 0, 1, 4); + add_to_map(xdf_map[2][2], 0, 2, 5); + add_to_map(xdf_map[2][3], 0, 3, 7); + add_to_map(xdf_map[2][4], 1, 0, 3); + add_to_map(xdf_map[2][5], 1, 1, 4); + add_to_map(xdf_map[2][6], 1, 2, 5); + add_to_map(xdf_map[2][7], 1, 3, 7); + +#if 0 + // XXDF 3.5" 2HD + add_to_map(xdf_track0[3], 12, 20, 4); + xdf_spt[3] = 2; + add_to_map(xdf_map[3][0], 0, 0, 5); + add_to_map(xdf_map[3][1], 1, 1, 6); + add_to_map(xdf_map[3][2], 0, 1, 6); + add_to_map(xdf_map[3][3], 1, 0, 5); + + // XXDF 3.5" 2ED + add_to_map(xdf_track0[4], 21, 39, 9); + xdf_spt[4] = 2; + add_to_map(xdf_map[4][0], 0, 0, 6); + add_to_map(xdf_map[4][1], 1, 1, 7); + add_to_map(xdf_map[4][2], 0, 1, 7); + add_to_map(xdf_map[4][3], 1, 0, 6); +#endif + + xdf_maps_initialized = 1; +} + +void img_load(int drive, char *fn) +{ + int size; + double bit_rate_300; + uint16_t bpb_bps; + uint16_t bpb_total; + uint8_t bpb_mid; /* Media type ID. */ + uint8_t bpb_sectors; + uint8_t bpb_sides; + uint32_t bpt; + uint8_t max_spt; /* Used for XDF detection. */ + int temp_rate; + + if (!xdf_maps_initialized) initialize_xdf_maps(); /* Initialize XDF maps, will need them to properly register sectors in tracks. */ + + writeprot[drive] = 0; + img[drive].f = fopen(fn, "rb+"); + if (!img[drive].f) + { + img[drive].f = fopen(fn, "rb"); + if (!img[drive].f) + return; + writeprot[drive] = 1; + } + fwriteprot[drive] = writeprot[drive]; + + /* Read the BPB */ + fseek(img[drive].f, 0x0B, SEEK_SET); + fread(&bpb_bps, 1, 2, img[drive].f); + fseek(img[drive].f, 0x13, SEEK_SET); + fread(&bpb_total, 1, 2, img[drive].f); + fseek(img[drive].f, 0x15, SEEK_SET); + bpb_mid = fgetc(img[drive].f); + fseek(img[drive].f, 0x18, SEEK_SET); + bpb_sectors = fgetc(img[drive].f); + fseek(img[drive].f, 0x1A, SEEK_SET); + bpb_sides = fgetc(img[drive].f); + + fseek(img[drive].f, -1, SEEK_END); + size = ftell(img[drive].f) + 1; + + img[drive].sides = 2; + img[drive].sector_size = 512; + + img[drive].hole = 0; + + pclog("BPB reports %i sides and %i bytes per sector\n", bpb_sides, bpb_bps); + + if ((bpb_sides < 1) || (bpb_sides > 2) || (bpb_bps < 128) || (bpb_bps > 2048)) + { + /* The BPB is giving us a wacky number of sides and/or bytes per sector, therefore it is most probably + not a BPB at all, so we have to guess the parameters from file size. */ + + if (size <= (160*1024)) { img[drive].sectors = 8; img[drive].tracks = 40; img[drive].sides = 1; bit_rate_300 = 250; raw_tsize[drive] = 6250; } + else if (size <= (180*1024)) { img[drive].sectors = 9; img[drive].tracks = 40; img[drive].sides = 1; bit_rate_300 = 250; raw_tsize[drive] = 6250; } + else if (size <= (320*1024)) { img[drive].sectors = 8; img[drive].tracks = 40; bit_rate_300 = 250; raw_tsize[drive] = 6250; } + else if (size <= (360*1024)) { img[drive].sectors = 9; img[drive].tracks = 40; bit_rate_300 = 250; raw_tsize[drive] = 6250; } /*Double density*/ + else if (size <= (640*1024)) { img[drive].sectors = 8; img[drive].tracks = 80; bit_rate_300 = 250; raw_tsize[drive] = 6250; } /*Double density 640k*/ + else if (size < (1024*1024)) { img[drive].sectors = 9; img[drive].tracks = 80; bit_rate_300 = 250; raw_tsize[drive] = 6250; } /*Double density*/ + else if (size <= 1228800) { img[drive].sectors = 15; img[drive].tracks = 80; bit_rate_300 = (500.0 * 300.0) / 360.0; raw_tsize[drive] = 10416; } /*High density 1.2MB*/ + else if (size <= 1261568) { img[drive].sectors = 8; img[drive].tracks = 77; img[drive].sector_size = 1024; bit_rate_300 = (500.0 * 300.0) / 360.0; raw_tsize[drive] = 10416; } /*High density 1.25MB Japanese format*/ + else if (size <= (0x1A4000-1)) { img[drive].sectors = 18; img[drive].tracks = 80; bit_rate_300 = 500; raw_tsize[drive] = 12500; } /*High density (not supported by Tandy 1000)*/ + else if (size <= 1556480) { img[drive].sectors = 19; img[drive].tracks = 80; bit_rate_300 = 500; raw_tsize[drive] = 12500; } /*High density (not supported by Tandy 1000)*/ + else if (size <= 1638400) { img[drive].sectors = 10; img[drive].tracks = 80; img[drive].sector_size = 1024; bit_rate_300 = 500; raw_tsize[drive] = 12500; } /*High density (not supported by Tandy 1000)*/ + // else if (size == 1884160) { img[drive].sectors = 23; img[drive].tracks = 80; bit_rate_300 = 500; } /*XDF format - used by OS/2 Warp*/ + // else if (size == 1763328) { img[drive].sectors = 21; img[drive].tracks = 82; bit_rate_300 = 500; } /*XDF format - used by OS/2 Warp*/ + else if (size <= 2000000) { img[drive].sectors = 21; img[drive].tracks = 80; bit_rate_300 = 500; raw_tsize[drive] = 12500; } /*DMF format - used by Windows 95 - changed by OBattler to 2000000, ie. the real unformatted capacity @ 500 kbps and 300 rpm */ + else if (size <= 2949120) { img[drive].sectors = 36; img[drive].tracks = 80; bit_rate_300 = 1000; raw_tsize[drive] = 25000; } /*E density*/ + + img[drive].xdf_type = 0; + } + else + { + /* The BPB readings appear to be valid, so let's set the values. */ + /* Number of tracks = number of total sectors divided by sides times sectors per track. */ + img[drive].tracks = ((uint32_t) bpb_total) / (((uint32_t) bpb_sides) * ((uint32_t) bpb_sectors)); + /* The rest we just set directly from the BPB. */ + img[drive].sectors = bpb_sectors; + img[drive].sides = bpb_sides; + /* Now we calculate bytes per track, which is bpb_sectors * bpb_bps. */ + bpt = (uint32_t) bpb_sectors * (uint32_t) bpb_bps; + /* Now we should be able to calculate the bit rate. */ + pclog("The image has %i bytes per track\n", bpt); + + temp_rate = 2; + if (bpt <= (maximum_sectors[sector_size_code(bpb_bps)][0] * bpb_bps)) + { + bit_rate_300 = ((250.0 * 300.0) / 360.0); + temp_rate = 2; + raw_tsize[drive] = 5208; + } + else if (bpt <= (maximum_sectors[sector_size_code(bpb_bps)][1] * bpb_bps)) + { + bit_rate_300 = 250; + temp_rate = 2; + raw_tsize[drive] = 6250; + } + else if (bpt <= (maximum_sectors[sector_size_code(bpb_bps)][2] * bpb_bps)) + { + bit_rate_300 = 300; + temp_rate = 1; + raw_tsize[drive] = 7500; + } + else if (bpt <= (maximum_sectors[sector_size_code(bpb_bps)][3] * bpb_bps)) + { + bit_rate_300 = (bpb_mid == 0xF0) ? 500 : ((500.0 * 300.0) / 360.0); + if (bpb_bps == 512) max_spt = (bit_rate_300 == 500) ? 21 : 17; + temp_rate = (bit_rate_300 == 500) ? 0 : 4; + raw_tsize[drive] = (bit_rate_300 == 500) ? 12500 : 10416; + } + else if (bpt <= (maximum_sectors[sector_size_code(bpb_bps)][4] * bpb_bps)) + { + bit_rate_300 = 500; + if (bpb_bps == 512) max_spt = 21; + pclog("max_spt is %i\n", max_spt); + temp_rate = 0; + raw_tsize[drive] = 12500; + } + else if (bpt <= (maximum_sectors[sector_size_code(bpb_bps)][5] * bpb_bps)) + { + bit_rate_300 = 1000; + if (bpb_bps == 512) max_spt = 41; + temp_rate = 3; + raw_tsize[drive] = 25000; + } + else /* Image too big, eject */ + { + pclog("Image is bigger than can fit on an ED floppy, ejecting...\n"); + fclose(img[drive].f); + return; + } + + if (bpb_bps == 512) /* BPB reports 512 bytes per sector, let's see if it's XDF or not */ + { + if (bit_rate_300 <= 300) /* Double-density disk, not XDF */ + { + img[drive].xdf_type = 0; + } + else + { + pclog("bpb_sectors is %i\n", bpb_sectors); + if (bpb_sectors > max_spt) + { + switch(bpb_sectors) + { + case 19: /* High density XDF @ 360 rpm */ + img[drive].xdf_type = 1; + break; + case 23: /* High density XDF @ 300 rpm */ + img[drive].xdf_type = 2; + pclog("XDF type is 2 @ %i kbps\n", bit_rate_300); + break; +#if 0 + case 24: /* High density XXDF @ 300 rpm */ + img[drive].xdf_type = 4; + break; +#endif + case 46: /* Extended density XDF */ + img[drive].xdf_type = 3; + break; +#if 0 + case 48: /* Extended density XXDF */ + img[drive].xdf_type = 5; + break; +#endif + default: /* Unknown, as we're beyond maximum sectors, get out */ + fclose(img[drive].f); + return; + } + } + else /* Amount of sectors per track that fits into a track, therefore not XDF */ + { + img[drive].xdf_type = 0; + } + } + } + else /* BPB reports sector size other than 512, can't possibly be XDF */ + { + img[drive].xdf_type = 0; + } + } + + gap2_size[drive] = (temp_rate == 3) ? 41 : 22; + pclog("GAP2 size: %i bytes\n", gap2_size[drive]); + gap3_size[drive] = gap3_sizes[temp_rate][sector_size_code(img[drive].sector_size)][img[drive].sectors]; + if (gap3_size) + { + pclog("GAP3 size: %i bytes\n", gap3_size[drive]); + } + else + { + // fclose(img[drive].f); + gap3_size[drive] = 40; + pclog("WARNING: Floppy image of unknown format was inserted into drive %c:!\n", drive + 0x41); + } + gap4_size[drive] = raw_tsize[drive] - (((pre_gap + gap2_size[drive] + pre_data + data_size + post_gap + gap3_size[drive]) * img[drive].sectors) + pre_track); + pclog("GAP4 size: %i bytes\n", gap4_size[drive]); + if (img[drive].xdf_type) + { + gap4_size[drive] = 1; + } + + if (bit_rate_300 == 250) + { + img[drive].hole = 0; + /* If drive does not support 300 RPM, the medium is to be read at a period of 26 (300 kbps). */ + img[drive].byte_period = 29; + } + else if (bit_rate_300 == 300) + { + img[drive].hole = 0; + img[drive].byte_period = 26; + } + else if (bit_rate_300 == 1000) + { + img[drive].hole = 2; + img[drive].byte_period = 8; + } + else if (bit_rate_300 < 250) + { + img[drive].hole = 0; + img[drive].byte_period = 32; + } + else + { + img[drive].hole = 1; + img[drive].byte_period = 16; + } + + if (img[drive].xdf_type) /* In case of XDF-formatted image, write-protect */ + { + writeprot[drive] = 1; + fwriteprot[drive] = writeprot[drive]; + } + + drives[drive].seek = img_seek; + drives[drive].readsector = disc_sector_readsector; + drives[drive].writesector = disc_sector_writesector; + drives[drive].readaddress = disc_sector_readaddress; + drives[drive].hole = img_hole; + drives[drive].byteperiod = img_byteperiod; + drives[drive].poll = disc_sector_poll; + drives[drive].format = disc_sector_format; + drives[drive].realtrack = img_realtrack; + drives[drive].stop = disc_sector_stop; + disc_sector_writeback[drive] = img_writeback; + + img[drive].bitcell_period_300rpm = 1000000.0 / bit_rate_300*2.0; + pclog("bit_rate_300=%g\n", bit_rate_300); + pclog("bitcell_period_300=%g\n", img[drive].bitcell_period_300rpm); +// img[drive].bitcell_period_300rpm = disc_get_bitcell_period(img[drive].rate); + pclog("img_load %d %p sectors=%i tracks=%i sides=%i sector_size=%i hole=%i\n", drive, drives, img[drive].sectors, img[drive].tracks, img[drive].sides, img[drive].sector_size, img[drive].hole); +} + +int img_hole(int drive) +{ + return img[drive].hole; +} + +int img_byteperiod(int drive) +{ + if (img[drive].byte_period == 29) + { + return (fdd_get_type(drive) & 1) ? 32 : 26; + } + return img[drive].byte_period; +} + +void img_close(int drive) +{ + if (img[drive].f) + fclose(img[drive].f); + img[drive].f = NULL; +} + +void img_seek(int drive, int track) +{ + int side; + int current_xdft = img[drive].xdf_type - 1; + + uint8_t sectors_fat, effective_sectors, sector_gap; /* Needed for XDF */ + + if (!img[drive].f) + return; + // pclog("Seek drive=%i track=%i sectors=%i sector_size=%i sides=%i\n", drive, track, img[drive].sectors,img[drive].sector_size, img[drive].sides); +// pclog(" %i %i\n", drive_type[drive], img[drive].tracks); +#ifdef MAINLINE + if ((img[drive].tracks <= 41) && fdd_doublestep_40(drive)) +#else + if ((img[drive].tracks <= 43) && fdd_doublestep_40(drive)) +#endif + track /= 2; + + // pclog("Disk seeked to track %i\n", track); + disc_track[drive] = track; + + if (img[drive].sides == 2) + { + fseek(img[drive].f, track * img[drive].sectors * img[drive].sector_size * 2, SEEK_SET); + // pclog("Seek: Current file position (H0) is: %08X\n", ftell(img[drive].f)); + fread(img[drive].track_data[0], img[drive].sectors * img[drive].sector_size, 1, img[drive].f); + // pclog("Seek: Current file position (H1) is: %08X\n", ftell(img[drive].f)); + fread(img[drive].track_data[1], img[drive].sectors * img[drive].sector_size, 1, img[drive].f); + } + else + { + fseek(img[drive].f, track * img[drive].sectors * img[drive].sector_size, SEEK_SET); + fread(img[drive].track_data[0], img[drive].sectors * img[drive].sector_size, 1, img[drive].f); + } + + disc_sector_reset(drive, 0); + disc_sector_reset(drive, 1); + + int sector, current_pos, sh, sr, spos, sside; + + if (img[drive].xdf_type) + { + sectors_fat = xdf_track0[current_xdft][0]; + effective_sectors = xdf_track0[current_xdft][1]; + sector_gap = xdf_track0[current_xdft][2]; + + if (!track) + { + /* Track 0, register sectors according to track 0 layout. */ + current_pos = 0; + for (sector = 0; sector < (img[drive].sectors * 2); sector++) + { + if (xdf_track0_layout[current_xdft][sector]) + { + sh = xdf_track0_layout[current_xdft][sector] & 0xFF; + sr = xdf_track0_layout[current_xdft][sector] >> 8; + spos = current_pos; + sside = 0; + if (spos > (img[drive].sectors * img[drive].sector_size)) + { + spos -= (img[drive].sectors * img[drive].sector_size); + sside = 1; + } + disc_sector_add(drive, sh, track, sh, sr, 2, + img[drive].bitcell_period_300rpm, + &img[drive].track_data[sside][spos]); + } + current_pos += 512; + } +#if 0 + /* Track 0, register sectors according to track 0 map. */ + /* First, the "Side 0" buffer, will also contain one sector from side 1. */ + current_pos = 0; + for (sector = 0; sector < sectors_fat; sector++) + { + if ((sector+0x81) >= 0x91) + { + disc_sector_add(drive, 0, track, 0, sector+0x85, 2, + img[drive].bitcell_period_300rpm, + &img[drive].track_data[0][current_pos]); + } + else + { + disc_sector_add(drive, 0, track, 0, sector+0x81, 2, + img[drive].bitcell_period_300rpm, + &img[drive].track_data[0][current_pos]); + } + current_pos += 512; + } + disc_sector_add(drive, 1, track, 1, 0x81, 2, + img[drive].bitcell_period_300rpm, + &img[drive].track_data[0][current_pos]); + current_pos += 512; + for (sector = 0; sector < 7; sector++) + { + disc_sector_add(drive, 0, track, 0, sector+1, 2, + img[drive].bitcell_period_300rpm, + &img[drive].track_data[0][current_pos]); + current_pos += 512; + } + disc_sector_add(drive, 0, track, 0, 0x9B, 2, + img[drive].bitcell_period_300rpm, + &img[drive].track_data[0][current_pos]); + current_pos += 512; + disc_sector_add(drive, 0, track, 0, 0x9C, 2, + img[drive].bitcell_period_300rpm, + &img[drive].track_data[0][current_pos]); + current_pos += 512; + disc_sector_add(drive, 0, track, 0, 0x9D, 2, + img[drive].bitcell_period_300rpm, + &img[drive].track_data[0][current_pos]); + current_pos += 512; + disc_sector_add(drive, 0, track, 0, 0x9E, 2, + img[drive].bitcell_period_300rpm, + &img[drive].track_data[0][current_pos]); + current_pos += 512; + /* Now the "Side 1" buffer, will also contain one sector from side 0. */ + current_pos = 0; + for (sector = 0; (sector < effective_sectors - 1); sector++) + { + disc_sector_add(drive, 1, track, 1, sector+0x82, 2, + img[drive].bitcell_period_300rpm, + &img[drive].track_data[1][current_pos]); + current_pos += 512; + } + disc_sector_add(drive, 0, track, 0, 8, 2, + img[drive].bitcell_period_300rpm, + &img[drive].track_data[1][current_pos]); + current_pos += 512; +#endif + } + else + { + /* Non-zero track, this will have sectors of various sizes. */ + /* First, the "Side 0" buffer. */ + current_pos = 0; + for (sector = 0; sector < xdf_spt[current_xdft]; sector++) + { + disc_sector_add(drive, xdf_map[current_xdft][sector][0], track, xdf_map[current_xdft][sector][0], + xdf_map[current_xdft][sector][2] + 0x80, xdf_map[current_xdft][sector][2], + img[drive].bitcell_period_300rpm, + &img[drive].track_data[0][current_pos]); + current_pos += (128 << xdf_map[current_xdft][sector][2]); + } + /* Then, the "Side 1" buffer. */ + current_pos = 0; + for (sector = xdf_spt[current_xdft]; sector < (xdf_spt[current_xdft] << 1); sector++) + { + disc_sector_add(drive, xdf_map[current_xdft][sector][0], track, xdf_map[current_xdft][sector][0], + xdf_map[current_xdft][sector][2] + 0x80, xdf_map[current_xdft][sector][2], + img[drive].bitcell_period_300rpm, + &img[drive].track_data[1][current_pos]); + current_pos += (128 << xdf_map[current_xdft][sector][2]); + } + } + } + else + { + for (side = 0; side < img[drive].sides; side++) + { + for (sector = 0; sector < img[drive].sectors; sector++) + disc_sector_add(drive, side, track, side, sector+1, img_sector_size_code(drive), + img[drive].bitcell_period_300rpm, + &img[drive].track_data[side][sector * img[drive].sector_size]); + } + } +} +void img_writeback(int drive, int track) +{ + if (!img[drive].f) + return; + + if (img[drive].xdf_type) + return; /*Should never happen*/ + + if (img[drive].sides == 2) + { + fseek(img[drive].f, track * img[drive].sectors * img[drive].sector_size * 2, SEEK_SET); + fwrite(img[drive].track_data[0], img[drive].sectors * img[drive].sector_size, 1, img[drive].f); + fwrite(img[drive].track_data[1], img[drive].sectors * img[drive].sector_size, 1, img[drive].f); + } + else + { + fseek(img[drive].f, track * img[drive].sectors * img[drive].sector_size, SEEK_SET); + fwrite(img[drive].track_data[0], img[drive].sectors * img[drive].sector_size, 1, img[drive].f); + } +} + diff --git a/src/disc_img.h b/src/disc_img.h new file mode 100644 index 000000000..df23c724f --- /dev/null +++ b/src/disc_img.h @@ -0,0 +1,13 @@ +void img_init(); +void img_load(int drive, char *fn); +void img_close(int drive); +void img_seek(int drive, int track); +void img_readsector(int drive, int sector, int track, int side, int density); +void img_writesector(int drive, int sector, int track, int side, int density); +void img_readaddress(int drive, int sector, int side, int density); +void img_format(int drive, int sector, int side, int density); +int img_hole(int drive); +int img_byteperiod(int drive); +void img_stop(int drive); +void img_poll(); +int img_realtrack(int track, int drive); diff --git a/src/disc_sector.c b/src/disc_sector.c new file mode 100644 index 000000000..b06b3e75d --- /dev/null +++ b/src/disc_sector.c @@ -0,0 +1,525 @@ +#include "ibm.h" +#include "disc.h" +#include "disc_sector.h" +#include "fdd.h" + +/*Handling for 'sector based' image formats (like .IMG) as opposed to 'stream based' formats (eg .FDI)*/ + +#define MAX_SECTORS 256 + +typedef struct +{ + uint8_t c, h, r, n; + int rate; + uint8_t *data; +} sector_t; + +static sector_t disc_sector_data[2][2][MAX_SECTORS]; +static int disc_sector_count[2][2]; +void (*disc_sector_writeback[2])(int drive, int track); + +enum +{ + STATE_IDLE, + STATE_READ_FIND_SECTOR, + STATE_READ_SECTOR, + STATE_READ_FIND_FIRST_SECTOR, + STATE_READ_FIRST_SECTOR, + STATE_READ_FIND_NEXT_SECTOR, + STATE_READ_NEXT_SECTOR, + STATE_WRITE_FIND_SECTOR, + STATE_WRITE_SECTOR, + STATE_READ_FIND_ADDRESS, + STATE_READ_ADDRESS, + STATE_FORMAT_FIND, + STATE_FORMAT +}; + +static int processed_bytes[2] = {0, 0}; + +static int disc_sector_state[2] = {0, 0}; +static int disc_sector_track[2] = {0, 0}; +static int disc_sector_side[2] = {0, 0}; +// static int disc_sector_drive[2] = {0, 0}; +static int disc_sector_sector[2] = {0, 0}; +static int disc_sector_n[2] = {0, 0}; +static int disc_intersector_delay[2] = {0, 0}; +static int disc_postdata_delay[2] = {0, 0}; +static int disc_track_delay[2] = {0, 0}; +static int disc_gap4_delay[2] = {0, 0}; +static uint8_t disc_sector_fill[2] = {0, 0}; +static int cur_sector[2], cur_byte[2]; +static int index_count[2]; + +int gap2 = length_gap2; +int gap3 = length_gap3; +int gap3_0 = length_gap3_0; +int gap4 = raw_track_size - (((pre_gap + length_gap2 + pre_data + data_size + post_gap + length_gap3) * no_sectors) + pre_track); +int gap4_0 = raw_track_size_0 - (((pre_gap + length_gap2 + pre_data + data_size + post_gap + length_gap3_0) * no_sectors_0) + pre_track); + +int raw_tsize[2] = {6250, 6250}; +int gap2_size[2] = {22, 22}; +int gap3_size[2] = {0, 0}; +int gap4_size[2] = {0, 0}; + +void disc_sector_reset(int drive, int side) +{ + disc_sector_count[drive][side] = 0; + + disc_intersector_delay[drive] = 0; + disc_postdata_delay[drive] = 0; + disc_track_delay[drive] = 0; + disc_gap4_delay[drive] = 0; + cur_sector[drive] = 0; + cur_byte[drive] = 0; + index_count[drive] = 0; +} + +void disc_sector_add(int drive, int side, uint8_t c, uint8_t h, uint8_t r, uint8_t n, int rate, uint8_t *data) +{ + sector_t *s = &disc_sector_data[drive][side][disc_sector_count[drive][side]]; +//pclog("disc_sector_add: drive=%i side=%i %i r=%i\n", drive, side, disc_sector_count[drive][side],r ); + if (disc_sector_count[drive][side] >= MAX_SECTORS) + return; + + s->c = c; + s->h = h; + s->r = r; + s->n = n; + s->rate = rate; + s->data = data; + + disc_sector_count[drive][side]++; +} + +static int get_bitcell_period(int drive) +{ + return (disc_sector_data[drive][disc_sector_side[drive]][cur_sector[drive]].rate * 300) / fdd_getrpm(drive); +} + +void disc_sector_readsector(int drive, int sector, int track, int side, int rate, int sector_size) +{ + pclog("disc_sector_readsector: fdc_period=%i img_period=%i rate=%i sector=%i track=%i side=%i\n", fdc_get_bitcell_period(), get_bitcell_period(drive), rate, sector, track, side); + pclog("pre_track=%i, pre_sector=%i, gap4=%i\n", pre_track, post_gap + gap3 + pre_gap + gap2 + pre_data, gap4); + + if (sector == SECTOR_FIRST) + disc_sector_state[drive] = STATE_READ_FIND_FIRST_SECTOR; + else if (sector == SECTOR_NEXT) + disc_sector_state[drive] = STATE_READ_FIND_NEXT_SECTOR; + else + disc_sector_state[drive] = STATE_READ_FIND_SECTOR; + disc_sector_track[drive] = track; + disc_sector_side[drive] = side; + // disc_sector_drive = drive; + disc_sector_sector[drive] = sector; + disc_sector_n[drive] = sector_size; + if ((cur_sector[drive] == 0) && (cur_byte[drive] == 0) && !disc_track_delay[drive]) disc_track_delay[drive] = pre_track; + index_count[drive] = 0; + processed_bytes[drive] = 0; + // pclog("Disk poll time is: %i\n", disc_poll_time); +} + +void disc_sector_writesector(int drive, int sector, int track, int side, int rate, int sector_size) +{ + pclog("disc_sector_writesector: fdc_period=%i img_period=%i rate=%i\n", fdc_get_bitcell_period(), get_bitcell_period(drive), rate); + + disc_sector_state[drive] = STATE_WRITE_FIND_SECTOR; + disc_sector_track[drive] = track; + disc_sector_side[drive] = side; + // disc_sector_drive = drive; + disc_sector_sector[drive] = sector; + disc_sector_n[drive] = sector_size; + if ((cur_sector[drive] == 0) && (cur_byte[drive] == 0) && !disc_track_delay[drive]) disc_track_delay[drive] = pre_track; + index_count[drive] = 0; + processed_bytes[drive] = 0; +} + +void disc_sector_readaddress(int drive, int track, int side, int rate) +{ + pclog("disc_sector_readaddress: fdc_period=%i img_period=%i rate=%i track=%i side=%i\n", fdc_get_bitcell_period(), get_bitcell_period(drive), rate, track, side); + + disc_sector_state[drive] = STATE_READ_FIND_ADDRESS; + disc_sector_track[drive] = track; + disc_sector_side[drive] = side; + // disc_sector_drive = drive; + if ((cur_sector[drive] == 0) && (cur_byte[drive] == 0) && !disc_track_delay[drive]) + { + disc_track_delay[drive] = pre_track; + index_count[drive] = -1; + } + else + index_count[drive] = 0; + + processed_bytes[drive] = 0; +} + +void disc_sector_format(int drive, int track, int side, int rate, uint8_t fill) +{ + disc_sector_state[drive] = STATE_FORMAT_FIND; + disc_sector_track[drive] = track; + disc_sector_side[drive] = side; + // disc_sector_drive = drive; + disc_sector_fill[drive] = fill; + index_count[drive] = 0; +} + +void disc_sector_stop(int drive) +{ + disc_sector_state[drive] = STATE_IDLE; +} + +static void index_pulse(int drive) +{ + if (disc_sector_state[drive] != STATE_IDLE) fdc_indexpulse(); +} + +static int advance_byte(int drive) +{ + /* 0 = regular byte, 1 = missing clock pulse */ + int type = 0; + + processed_bytes[drive]++; + // pclog("advance_byte(%i): %i\n", drive, processed_bytes[drive]); + if (disc_postdata_delay[drive]) + { + disc_postdata_delay[drive]--; + return type; + } + if (disc_gap4_delay[drive]) + { + disc_gap4_delay[drive]--; + return type; + } + if (disc_track_delay[drive]) + { + if ((disc_track_delay[drive] >= (pre_track - 92)) && (disc_track_delay[drive] <= (pre_track - 94))) type = 1; + if (disc_track_delay[drive] == pre_track) + { + // pclog("Track index pulse!\n"); + index_pulse(drive); + index_count[drive]++; + } + disc_track_delay[drive]--; + if (type) pclog("advance_byte(): Track sync\n"); + return type; + } + if (disc_intersector_delay[drive]) + { + if ((disc_intersector_delay[drive] >= (pre_gap + gap2_size[drive] + pre_data - 12)) && (disc_intersector_delay[drive] <= (pre_gap + gap2_size[drive] + pre_data - 14))) type = 1; + if ((disc_intersector_delay[drive] >= (pre_gap + gap2_size[drive] + pre_data - 56)) && (disc_intersector_delay[drive] <= (pre_gap + gap2_size[drive] + pre_data - 58))) type = 2; + disc_intersector_delay[drive]--; + if (type == 1) pclog("advance_byte(): Sector address sync\n"); + if (type == 2) pclog("advance_byte(): Sector sync\n"); + return type; + } + cur_byte[drive]++; + if (cur_byte[drive] >= (128 << disc_sector_data[drive][disc_sector_side[drive]][cur_sector[drive]].n)) + { + cur_byte[drive] = 0; + cur_sector[drive]++; + disc_postdata_delay[drive] = post_gap + (gap3_size[drive]); + if (cur_sector[drive] >= disc_sector_count[drive][disc_sector_side[drive]]) + { + cur_sector[drive] = 0; + disc_gap4_delay[drive] = (gap4_size[drive]); + disc_track_delay[drive] = pre_track; + disc_intersector_delay[drive] = pre_gap + gap2_size[drive] + pre_data; + } + else + { + disc_gap4_delay[drive] = 0; + disc_track_delay[drive] = 0; + disc_intersector_delay[drive] = pre_gap + gap2_size[drive] + pre_data; + } + } + return type; +} + +int head_byte(int drive, int h) +{ + return (fdd_get_head(drive) << 2) | h; +} + +int disc_sector_poll(int drive) +{ + sector_t *s; + int data; + + int do_period = 0; + + int sector_type = 0; + + if (cur_sector[drive] >= disc_sector_count[drive][disc_sector_side[drive]]) + cur_sector[drive] = 0; + if (cur_byte[drive] >= (128 << disc_sector_data[drive][disc_sector_side[drive]][cur_sector[drive]].n)) + cur_byte[drive] = 0; + + /* Note: Side to read from should be chosen from FDC head select rather than from the sector ID. */ + s = &disc_sector_data[drive][disc_sector_side[drive]][cur_sector[drive]]; + + if (fdd_stepping_motor_on[drive]) + { + /* If stepping motor is on, turn off data separator. */ + sector_type = advance_byte(drive); + do_period = 1; + + do_period = do_period ? ((sector_type > 0) ? 2 : 1) : 0; + return do_period; + } + + switch (disc_sector_state[drive]) + { + case STATE_IDLE: + sector_type = advance_byte(drive); + do_period = 1; + break; + + case STATE_READ_FIND_SECTOR: +/* pclog("STATE_READ_FIND_SECTOR: cur_sector=%i cur_byte=%i sector=%i,%i side=%i,%i track=%i,%i period=%i,%i\n", + cur_sector[drive], cur_byte[drive], + disc_sector_sector[drive], s->r, + disc_sector_side[drive], s->h, + disc_sector_track[drive], s->c, + fdc_get_bitcell_period(), get_bitcell_period(drive));*/ + if (index_count[drive] > 1) + { +// pclog("Find sector not found\n"); + pclog("READ: Sector (%i %i %i %i) not found (last: %i %i %i) (period=%i,%i)\n", s->c, s->h, s->r, s->n, disc_sector_track, disc_sector_side, disc_sector_sector, fdc_get_bitcell_period(), get_bitcell_period(drive)); + fdc_notfound(); + disc_sector_state[drive] = STATE_IDLE; + break; + } +/* pclog("%i %i %i %i %i\n", cur_byte[drive], disc_sector_track[drive] != s->c, + disc_sector_side[drive] != s->h, + disc_sector_sector[drive] != s->r, + fdc_get_bitcell_period() != get_bitcell_period(drive));*/ + if (cur_byte[drive] || disc_sector_track[drive] != s->c || + disc_sector_side[drive] != s->h || + disc_sector_sector[drive] != s->r || + disc_sector_n[drive] != s->n || + (fdc_get_bitcell_period() != get_bitcell_period(drive)) || + !fdd_can_read_medium(drive ^ fdd_swap) || + disc_intersector_delay[drive] || disc_track_delay[drive]) + { + // pclog("Poll: Find sector advance byte!\n"); + sector_type = advance_byte(drive); + do_period = 1; + break; + } + disc_sector_state[drive] = STATE_READ_SECTOR; + case STATE_READ_SECTOR: +// pclog("STATE_READ_SECTOR: cur_byte=%i %i\n", cur_byte[drive], disc_intersector_delay[drive]); + if (fdc_data(s->data[cur_byte[drive]])) + { +// pclog("fdc_data failed\n"); + return 0; + } + sector_type = advance_byte(drive); + do_period = 1; + if (!cur_byte[drive]) + { + disc_sector_state[drive] = STATE_IDLE; + pclog("Processed bytes: %i, byte pulses: %i\n", processed_bytes[drive], bpulses[drive]); + // pclog("Disk poll time is: %i\n", disc_poll_time); + fdc_finishread(drive); + } + break; + + case STATE_READ_FIND_FIRST_SECTOR: + if (!fdd_can_read_medium(drive ^ fdd_swap)) + { + pclog("Medium is of a density not supported by the drive\n"); + fdc_notfound(); + disc_sector_state[drive] = STATE_IDLE; + break; + } + if (cur_byte[drive] || !index_count[drive] || fdc_get_bitcell_period() != get_bitcell_period(drive) || + disc_intersector_delay[drive] || disc_track_delay[drive]) + { + // pclog("Poll: Find sector advance byte!\n"); + sector_type = advance_byte(drive); + do_period = 1; + break; + } + disc_sector_state[drive] = STATE_READ_FIRST_SECTOR; + case STATE_READ_FIRST_SECTOR: + if (fdc_data(s->data[cur_byte[drive]])) + return 0; + sector_type = advance_byte(drive); + do_period = 1; + if (!cur_byte[drive]) + { + disc_sector_state[drive] = STATE_IDLE; + pclog("Processed bytes: %i, byte pulses: %i\n", processed_bytes[drive], bpulses[drive]); + // pclog("Disk poll time is: %i\n", disc_poll_time); + fdc_finishread(drive); + } + break; + + case STATE_READ_FIND_NEXT_SECTOR: + if (!fdd_can_read_medium(drive ^ fdd_swap)) + { + pclog("Medium is of a density not supported by the drive\n"); + fdc_notfound(); + disc_sector_state[drive] = STATE_IDLE; + break; + } + if (index_count[drive] > 0) + { + pclog("Find next sector hit end of track\n"); + fdc_notfound(); + disc_sector_state[drive] = STATE_IDLE; + break; + } + if (cur_byte[drive] || (fdc_get_bitcell_period() != get_bitcell_period(drive)) || + disc_intersector_delay[drive] || disc_track_delay[drive]) + { + // pclog("Poll: Find sector advance byte!\n"); + sector_type = advance_byte(drive); + do_period = 1; + break; + } + disc_sector_state[drive] = STATE_READ_NEXT_SECTOR; + case STATE_READ_NEXT_SECTOR: + if (fdc_data(s->data[cur_byte[drive]])) + break; + sector_type = advance_byte(drive); + do_period = 1; + if (!cur_byte[drive]) + { + disc_sector_state[drive] = STATE_IDLE; + pclog("Processed bytes: %i, byte pulses: %i\n", processed_bytes[drive], bpulses[drive]); + // pclog("Disk poll time is: %i\n", disc_poll_time); + fdc_finishread(drive); + } + break; + + case STATE_WRITE_FIND_SECTOR: + if (!fdd_can_read_medium(drive ^ fdd_swap)) + { + // pclog("Medium is of a density not supported by the drive\n"); + fdc_notfound(); + disc_sector_state[drive] = STATE_IDLE; + break; + } + if (writeprot[drive] || swwp) + { + fdc_writeprotect(); + return 0; + } + if (index_count[drive] > 1) + { + // pclog("Write find sector not found\n"); + pclog("WRITE: Sector (%i %i %i %i) not found\n", s->c, s->h, s->r, s->n); + fdc_notfound(); + disc_sector_state[drive] = STATE_IDLE; + break; + } + if (cur_byte[drive] || disc_sector_track[drive] != s->c || + disc_sector_side[drive] != s->h || + disc_sector_sector[drive] != s->r || + disc_sector_n[drive] != s->n || + (fdc_get_bitcell_period() != get_bitcell_period(drive)) || + disc_intersector_delay[drive] || disc_track_delay[drive]) + { + // pclog("Poll: Find sector advance byte!\n"); + sector_type = advance_byte(drive); + do_period = 1; + break; + } + disc_sector_state[drive] = STATE_WRITE_SECTOR; + case STATE_WRITE_SECTOR: + data = fdc_getdata(cur_byte[drive] == ((128 << s->n) - 1)); + if (data == -1) + break; + if (!disable_write) s->data[cur_byte[drive]] = data; + sector_type = advance_byte(drive); + do_period = 1; + if (!cur_byte[drive]) + { + disc_sector_state[drive] = STATE_IDLE; + if (!disable_write) disc_sector_writeback[drive](drive, disc_sector_track[drive]); + pclog("Processed bytes: %i, byte pulses: %i\n", processed_bytes[drive], bpulses[drive]); + // pclog("Disk poll time is: %i\n", disc_poll_time); + fdc_finishread(drive); + } + break; + + case STATE_READ_FIND_ADDRESS: + if (!fdd_can_read_medium(drive ^ fdd_swap)) + { + pclog("Medium is of a density not supported by the drive\n"); + fdc_notfound(); + disc_sector_state[drive] = STATE_IDLE; + break; + } + if (index_count[drive] > 0) + { + pclog("Find next sector hit end of track\n"); + fdc_notfound(); + disc_sector_state[drive] = STATE_IDLE; + break; + } + if (cur_byte[drive] || (fdc_get_bitcell_period() != get_bitcell_period(drive)) || + disc_intersector_delay[drive] || disc_track_delay[drive]) + { + // pclog("Poll: Find sector advance byte!\n"); + sector_type = advance_byte(drive); + do_period = 1; + break; + } + disc_sector_state[drive] = STATE_READ_ADDRESS; + case STATE_READ_ADDRESS: + fdc_sectorid(s->c, s->h, s->r, s->n, 0, 0); + disc_sector_state[drive] = STATE_IDLE; + break; + + case STATE_FORMAT_FIND: + if (writeprot[drive] || swwp) + { + fdc_writeprotect(); + return 0; + } + if (!index_count[drive] || (fdc_get_bitcell_period() != get_bitcell_period(drive)) || + disc_intersector_delay[drive] || disc_track_delay[drive]) + { + sector_type = advance_byte(drive); + do_period = 1; + break; + } + if (!(fdd_can_read_medium(drive ^ fdd_swap))) + { + pclog("Medium is of a density not supported by the drive\n"); + fdc_notfound(); + disc_sector_state[drive] = STATE_IDLE; + break; + } + if (fdc_get_bitcell_period() != get_bitcell_period(drive)) + { + pclog("Bitcell period mismatch\n"); + fdc_notfound(); + disc_sector_state[drive] = STATE_IDLE; + break; + } + disc_sector_state[drive] = STATE_FORMAT; + case STATE_FORMAT: + if (!disc_intersector_delay[drive] && fdc_get_bitcell_period() == get_bitcell_period(drive) && !disable_write) + s->data[cur_byte[drive]] = disc_sector_fill[drive]; + sector_type = advance_byte(drive); + do_period = 1; + if (index_count[drive] == 2) + { + if (!disable_write) disc_sector_writeback[drive](drive, disc_sector_track[drive]); + pclog("Processed bytes: %i, byte pulses: %i\n", processed_bytes[drive], bpulses[drive]); + // pclog("Disk poll time is: %i\n", disc_poll_time); + fdc_finishread(drive); + disc_sector_state[drive] = STATE_IDLE; + } + break; + } + + // if (do_period) pclog("disc_sector_poll(%i) = %i\n", drive, sector_type); + do_period = do_period ? ((sector_type > 0) ? 2 : 1) : 0; + return do_period; +} + diff --git a/src/disc_sector.h b/src/disc_sector.h new file mode 100644 index 000000000..b95b7e129 --- /dev/null +++ b/src/disc_sector.h @@ -0,0 +1,43 @@ +void disc_sector_reset(int drive, int side); +void disc_sector_add(int drive, int side, uint8_t c, uint8_t h, uint8_t r, uint8_t n, int rate, uint8_t *data); +void disc_sector_readsector(int drive, int sector, int track, int side, int density, int sector_size); +void disc_sector_writesector(int drive, int sector, int track, int side, int density, int sector_size); +void disc_sector_readaddress(int drive, int sector, int side, int density); +void disc_sector_format(int drive, int sector, int side, int density, uint8_t fill); +void disc_sector_stop(int drive); +int disc_sector_poll(int drive); +void disc_sector_stop(int drive); + +#define length_gap0 80 +#define length_gap1 50 +#define length_sync 12 +#define length_am 4 +#define length_crc 2 +#define length_gap2 22 +#define length_gap3 84 // 88 +#define length_gap3_0 108 +#define no_sectors 15 // 8 +#define no_sectors_0 18 +#define raw_track_size 10416 // 6250 +#define raw_track_size_0 12500 + +#define IBM +#define MFM +#ifdef IBM +#define pre_gap1 length_gap0 + length_sync + length_am +#else +#define pre_gap1 0 +#endif + +#define pre_track pre_gap1 + length_gap1 +#define pre_gap length_sync + length_am + 4 + length_crc // 22 +#define pre_data length_sync + length_am // 16 +#define data_size 512 +#define post_gap length_crc + +extern int raw_tsize[2]; +extern int gap2_size[2]; +extern int gap3_size[2]; +extern int gap4_size[2]; + +extern void (*disc_sector_writeback[2])(int drive, int track); diff --git a/src/dma.c b/src/dma.c new file mode 100644 index 000000000..c05e6d94e --- /dev/null +++ b/src/dma.c @@ -0,0 +1,389 @@ +#include "ibm.h" + +#include "dma.h" +#include "fdc.h" +#include "io.h" +#include "mem.h" +#include "video.h" + +static uint8_t dmaregs[16]; +static int dmaon[4]; +static uint8_t dma16regs[16]; +static int dma16on[4]; +static uint8_t dmapages[16]; + +void dma_reset() +{ + int c; + dma.wp = 0; + for (c = 0; c < 16; c++) + dmaregs[c] = 0; + for (c = 0; c < 4; c++) + { + dma.mode[c] = 0; + dma.ac[c] = 0; + dma.cc[c] = 0; + dma.ab[c] = 0; + dma.cb[c] = 0; + } + dma.m = 0; + + dma16.wp = 0; + for (c = 0; c < 16; c++) + dma16regs[c] = 0; + for (c = 0; c < 4; c++) + { + dma16.mode[c] = 0; + dma16.ac[c] = 0; + dma16.cc[c] = 0; + dma16.ab[c] = 0; + dma16.cb[c] = 0; + } + dma16.m = 0; +} + +uint8_t dma_read(uint16_t addr, void *priv) +{ + uint8_t temp; +// printf("Read DMA %04X %04X:%04X %i %02X\n",addr,CS,pc, pic_intpending, pic.pend); + switch (addr & 0xf) + { + case 0: case 2: case 4: case 6: /*Address registers*/ + dma.wp ^= 1; + if (dma.wp) + return dma.ac[(addr >> 1) & 3] & 0xff; + return dma.ac[(addr >> 1) & 3] >> 8; + + case 1: case 3: case 5: case 7: /*Count registers*/ + dma.wp ^= 1; + if (dma.wp) temp = dma.cc[(addr >> 1) & 3] & 0xff; + else temp = dma.cc[(addr >> 1) & 3] >> 8; + return temp; + + case 8: /*Status register*/ + temp = dma.stat; + dma.stat = 0; + return temp; + + case 0xd: + return 0; + } +// printf("Bad DMA read %04X %04X:%04X\n",addr,CS,pc); + return dmaregs[addr & 0xf]; +} + +void dma_write(uint16_t addr, uint8_t val, void *priv) +{ +// printf("Write DMA %04X %02X %04X:%04X\n",addr,val,CS,pc); + dmaregs[addr & 0xf] = val; + switch (addr & 0xf) + { + case 0: case 2: case 4: case 6: /*Address registers*/ + dma.wp ^= 1; + if (dma.wp) dma.ab[(addr >> 1) & 3] = (dma.ab[(addr >> 1) & 3] & 0xff00) | val; + else dma.ab[(addr >> 1) & 3] = (dma.ab[(addr >> 1) & 3] & 0x00ff) | (val << 8); + dma.ac[(addr >> 1) & 3] = dma.ab[(addr >> 1) & 3]; + dmaon[(addr >> 1) & 3] = 1; + return; + + case 1: case 3: case 5: case 7: /*Count registers*/ + dma.wp ^= 1; + if (dma.wp) dma.cb[(addr >> 1) & 3] = (dma.cb[(addr >> 1) & 3] & 0xff00) | val; + else dma.cb[(addr >> 1) & 3] = (dma.cb[(addr >> 1) & 3] & 0x00ff) | (val << 8); + dma.cc[(addr >> 1) & 3] = dma.cb[(addr >> 1) & 3]; + dmaon[(addr >> 1) & 3] = 1; + return; + + case 8: /*Control register*/ + dma.command = val; + return; + + case 0xa: /*Mask*/ + if (val & 4) dma.m |= (1 << (val & 3)); + else dma.m &= ~(1 << (val & 3)); + return; + + case 0xb: /*Mode*/ + dma.mode[val & 3] = val; + return; + + case 0xc: /*Clear FF*/ + dma.wp = 0; + return; + + case 0xd: /*Master clear*/ + dma.wp = 0; + dma.m = 0xf; + return; + + case 0xf: /*Mask write*/ + dma.m = val & 0xf; + return; + } +} + +uint8_t dma16_read(uint16_t addr, void *priv) +{ + uint8_t temp; +// printf("Read DMA %04X %04X:%04X\n",addr,cs>>4,pc); + addr >>= 1; + switch (addr & 0xf) + { + case 0: case 2: case 4: case 6: /*Address registers*/ + dma16.wp ^= 1; + if (dma16.wp) + return dma16.ac[(addr >> 1) & 3] & 0xff; + return dma16.ac[(addr >> 1) & 3] >> 8; + + case 1: case 3: case 5: case 7: /*Count registers*/ + dma16.wp ^= 1; + if (dma16.wp) temp = dma16.cc[(addr >> 1) & 3] & 0xff; + else temp = dma16.cc[(addr >> 1) & 3] >> 8; + return temp; + + case 8: /*Status register*/ + temp = dma16.stat; + dma16.stat = 0; + return temp; + } + return dma16regs[addr & 0xf]; +} + +void dma16_write(uint16_t addr, uint8_t val, void *priv) +{ +// printf("Write dma16 %04X %02X %04X:%04X\n",addr,val,CS,pc); + addr >>= 1; + dma16regs[addr & 0xf] = val; + switch (addr & 0xf) + { + case 0: case 2: case 4: case 6: /*Address registers*/ + dma16.wp ^= 1; + if (dma16.wp) dma16.ab[(addr >> 1) & 3] = (dma16.ab[(addr >> 1) & 3] & 0xff00) | val; + else dma16.ab[(addr >> 1) & 3] = (dma16.ab[(addr >> 1) & 3] & 0x00ff) | (val << 8); + dma16.ac[(addr >> 1) & 3] = dma16.ab[(addr >> 1) & 3]; + dma16on[(addr >> 1) & 3] = 1; + return; + + case 1: case 3: case 5: case 7: /*Count registers*/ + dma16.wp ^= 1; + if (dma16.wp) dma16.cb[(addr >> 1) & 3] = (dma16.cb[(addr >> 1) & 3] & 0xff00) | val; + else dma16.cb[(addr >> 1) & 3] = (dma16.cb[(addr >> 1) & 3] & 0x00ff) | (val << 8); + dma16.cc[(addr >> 1) & 3] = dma16.cb[(addr >> 1) & 3]; + dma16on[(addr >> 1) & 3] = 1; + return; + + case 8: /*Control register*/ + return; + + case 0xa: /*Mask*/ + if (val & 4) dma16.m |= (1 << (val & 3)); + else dma16.m &= ~(1 << (val & 3)); + return; + + case 0xb: /*Mode*/ + dma16.mode[val & 3] = val; + return; + + case 0xc: /*Clear FF*/ + dma16.wp = 0; + return; + + case 0xd: /*Master clear*/ + dma16.wp = 0; + dma16.m = 0xf; + return; + + case 0xf: /*Mask write*/ + dma16.m = val&0xf; + return; + } +} + + +void dma_page_write(uint16_t addr, uint8_t val, void *priv) +{ + dmapages[addr & 0xf] = val; + switch (addr & 0xf) + { + case 1: + dma.page[2] = (AT) ? val : val & 0xf; + break; + case 2: + dma.page[3] = (AT) ? val : val & 0xf; + break; + case 3: + dma.page[1] = (AT) ? val : val & 0xf; + break; + case 0xb: + dma16.page[1] = val; + break; + } +} + +uint8_t dma_page_read(uint16_t addr, void *priv) +{ + return dmapages[addr & 0xf]; +} + +void dma_init() +{ + io_sethandler(0x0000, 0x0010, dma_read, NULL, NULL, dma_write, NULL, NULL, NULL); + io_sethandler(0x0080, 0x0008, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL); +} + +void dma16_init() +{ + io_sethandler(0x00C0, 0x0020, dma16_read, NULL, NULL, dma16_write, NULL, NULL, NULL); + io_sethandler(0x0088, 0x0008, dma_page_read, NULL, NULL, dma_page_write, NULL, NULL, NULL); +} + + +uint8_t _dma_read(uint32_t addr) +{ + return mem_readb_phys(addr); +} + +void _dma_write(uint32_t addr, uint8_t val) +{ + mem_writeb_phys(addr, val); + mem_invalidate_range(addr, addr); +} + +int dma_channel_read(int channel) +{ + uint16_t temp; + int tc = 0; + + if (dma.command & 0x04) + return DMA_NODATA; + + if (!AT) + refreshread(); + + if (channel < 4) + { + if (dma.m & (1 << channel)) + return DMA_NODATA; + if ((dma.mode[channel] & 0xC) != 8) + return DMA_NODATA; + + temp = _dma_read(dma.ac[channel] + (dma.page[channel] << 16)); //ram[(dma.ac[2]+(dma.page[2]<<16))&rammask]; + + if (dma.mode[channel] & 0x20) dma.ac[channel]--; + else dma.ac[channel]++; + dma.cc[channel]--; + if (dma.cc[channel] < 0) + { + tc = 1; + if (dma.mode[channel] & 0x10) /*Auto-init*/ + { + dma.cc[channel] = dma.cb[channel]; + dma.ac[channel] = dma.ab[channel]; + } + else + dma.m |= (1 << channel); + dma.stat |= (1 << channel); + } + + if (tc) + return temp | DMA_OVER; + return temp; + } + else + { + channel &= 3; + if (dma16.m & (1 << channel)) + return DMA_NODATA; + if ((dma16.mode[channel] & 0xC) != 8) + return DMA_NODATA; + + temp = _dma_read((dma16.ac[channel] << 1) + ((dma16.page[channel] & ~1) << 16)) | + (_dma_read((dma16.ac[channel] << 1) + ((dma16.page[channel] & ~1) << 16) + 1) << 8); + + if (dma16.mode[channel] & 0x20) dma16.ac[channel]--; + else dma16.ac[channel]++; + dma16.cc[channel]--; + if (dma16.cc[channel] < 0) + { + tc = 1; + if (dma16.mode[channel] & 0x10) /*Auto-init*/ + { + dma16.cc[channel] = dma16.cb[channel]; + dma16.ac[channel] = dma16.ab[channel]; + } + else + dma16.m |= (1 << channel); + dma16.stat |= (1 << channel); + } + + if (tc) + return temp | DMA_OVER; + return temp; + } +} + +int dma_channel_write(int channel, uint16_t val) +{ + if (dma.command & 0x04) + return DMA_NODATA; + + if (!AT) + refreshread(); + + if (channel < 4) + { + if (dma.m & (1 << channel)) + return DMA_NODATA; + if ((dma.mode[channel] & 0xC) != 4) + return DMA_NODATA; + + _dma_write(dma.ac[channel] + (dma.page[channel] << 16), val); + + if (dma.mode[channel]&0x20) dma.ac[channel]--; + else dma.ac[channel]++; + dma.cc[channel]--; + if (dma.cc[channel] < 0) + { + if (dma.mode[channel] & 0x10) /*Auto-init*/ + { + dma.cc[channel] = dma.cb[channel]; + dma.ac[channel] = dma.ab[channel]; + } + else + dma.m |= (1 << channel); + dma.stat |= (1 << channel); + } + + if (dma.m & (1 << channel)) + return DMA_OVER; + } + else + { + channel &= 3; + if (dma16.m & (1 << channel)) + return DMA_NODATA; + if ((dma16.mode[channel] & 0xC) != 4) + return DMA_NODATA; + + _dma_write((dma16.ac[channel] << 1) + ((dma16.page[channel] & ~1) << 16), val); + _dma_write((dma16.ac[channel] << 1) + ((dma16.page[channel] & ~1) << 16) + 1, val >> 8); + + if (dma16.mode[channel]&0x20) dma16.ac[channel]--; + else dma16.ac[channel]++; + dma16.cc[channel]--; + if (dma16.cc[channel] < 0) + { + if (dma16.mode[channel] & 0x10) /*Auto-init*/ + { + dma16.cc[channel] = dma16.cb[channel] + 1; + dma16.ac[channel] = dma16.ab[channel]; + } + dma16.m |= (1 << channel); + dma16.stat |= (1 << channel); + } + + if (dma.m & (1 << channel)) + return DMA_OVER; + } + return 0; +} diff --git a/src/dma.h b/src/dma.h new file mode 100644 index 000000000..451d8d6d3 --- /dev/null +++ b/src/dma.h @@ -0,0 +1,16 @@ +void dma_init(); +void dma16_init(); +void dma_reset(); + +#define DMA_NODATA -1 +#define DMA_OVER 0x10000 + +void readdma0(); +int readdma1(); +uint8_t readdma2(); +int readdma3(); + +void writedma2(uint8_t temp); + +int dma_channel_read(int channel); +int dma_channel_write(int channel, uint16_t val); diff --git a/src/dosbox/dbopl.cpp b/src/dosbox/dbopl.cpp new file mode 100644 index 000000000..b8c065453 --- /dev/null +++ b/src/dosbox/dbopl.cpp @@ -0,0 +1,1521 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +/* + DOSBox implementation of a combined Yamaha YMF262 and Yamaha YM3812 emulator. + Enabling the opl3 bit will switch the emulator to stereo opl3 output instead of regular mono opl2 + Except for the table generation it's all integer math + Can choose different types of generators, using muls and bigger tables, try different ones for slower platforms + The generation was based on the MAME implementation but tried to have it use less memory and be faster in general + MAME uses much bigger envelope tables and this will be the biggest cause of it sounding different at times + + //TODO Don't delay first operator 1 sample in opl3 mode + //TODO Maybe not use class method pointers but a regular function pointers with operator as first parameter + //TODO Fix panning for the Percussion channels, would any opl3 player use it and actually really change it though? + //TODO Check if having the same accuracy in all frequency multipliers sounds better or not + + //DUNNO Keyon in 4op, switch to 2op without keyoff. +*/ + +/* $Id: dbopl.cpp,v 1.10 2009-06-10 19:54:51 harekiet Exp $ */ + +#include +#include +#include +//#include "dosbox.h" +#include "dbopl.h" + + +#ifndef PI +#define PI 3.14159265358979323846 +#endif + +namespace DBOPL { + +#define OPLRATE ((double)(14318180.0 / 288.0)) +#define TREMOLO_TABLE 52 + +//Try to use most precision for frequencies +//Else try to keep different waves in synch +//#define WAVE_PRECISION 1 +#ifndef WAVE_PRECISION +//Wave bits available in the top of the 32bit range +//Original adlib uses 10.10, we use 10.22 +#define WAVE_BITS 10 +#else +//Need some extra bits at the top to have room for octaves and frequency multiplier +//We support to 8 times lower rate +//128 * 15 * 8 = 15350, 2^13.9, so need 14 bits +#define WAVE_BITS 14 +#endif +#define WAVE_SH ( 32 - WAVE_BITS ) +#define WAVE_MASK ( ( 1 << WAVE_SH ) - 1 ) + +//Use the same accuracy as the waves +#define LFO_SH ( WAVE_SH - 10 ) +//LFO is controlled by our tremolo 256 sample limit +#define LFO_MAX ( 256 << ( LFO_SH ) ) + + +//Maximum amount of attenuation bits +//Envelope goes to 511, 9 bits +#if (DBOPL_WAVE == WAVE_TABLEMUL ) +//Uses the value directly +#define ENV_BITS ( 9 ) +#else +//Add 3 bits here for more accuracy and would have to be shifted up either way +#define ENV_BITS ( 9 ) +#endif +//Limits of the envelope with those bits and when the envelope goes silent +#define ENV_MIN 0 +#define ENV_EXTRA ( ENV_BITS - 9 ) +#define ENV_MAX ( 511 << ENV_EXTRA ) +#define ENV_LIMIT ( ( 12 * 256) >> ( 3 - ENV_EXTRA ) ) +#define ENV_SILENT( _X_ ) ( (_X_) >= ENV_LIMIT ) + +//Attack/decay/release rate counter shift +#define RATE_SH 24 +#define RATE_MASK ( ( 1 << RATE_SH ) - 1 ) +//Has to fit within 16bit lookuptable +#define MUL_SH 16 + +//Check some ranges +#if ENV_EXTRA > 3 +#error Too many envelope bits +#endif + + +//How much to substract from the base value for the final attenuation +static const Bit8u KslCreateTable[16] = { + //0 will always be be lower than 7 * 8 + 64, 32, 24, 19, + 16, 12, 11, 10, + 8, 6, 5, 4, + 3, 2, 1, 0, +}; + +#define M(_X_) ((Bit8u)( (_X_) * 2)) +static const Bit8u FreqCreateTable[16] = { + M(0.5), M(1 ), M(2 ), M(3 ), M(4 ), M(5 ), M(6 ), M(7 ), + M(8 ), M(9 ), M(10), M(10), M(12), M(12), M(15), M(15) +}; +#undef M + +//We're not including the highest attack rate, that gets a special value +static const Bit8u AttackSamplesTable[13] = { + 69, 55, 46, 40, + 35, 29, 23, 20, + 19, 15, 11, 10, + 9 +}; +//On a real opl these values take 8 samples to reach and are based upon larger tables +static const Bit8u EnvelopeIncreaseTable[13] = { + 4, 5, 6, 7, + 8, 10, 12, 14, + 16, 20, 24, 28, + 32, +}; + +#if ( DBOPL_WAVE == WAVE_HANDLER ) || ( DBOPL_WAVE == WAVE_TABLELOG ) +static Bit16u ExpTable[ 256 ]; +#endif + +#if ( DBOPL_WAVE == WAVE_HANDLER ) +//PI table used by WAVEHANDLER +static Bit16u SinTable[ 512 ]; +#endif + +#if ( DBOPL_WAVE > WAVE_HANDLER ) +//Layout of the waveform table in 512 entry intervals +//With overlapping waves we reduce the table to half it's size + +// | |//\\|____|WAV7|//__|/\ |____|/\/\| +// |\\//| | |WAV7| | \/| | | +// |06 |0126|17 |7 |3 |4 |4 5 |5 | + +//6 is just 0 shifted and masked + +static Bit16s WaveTable[ 8 * 512 ]; +//Distance into WaveTable the wave starts +static const Bit16u WaveBaseTable[8] = { + 0x000, 0x200, 0x200, 0x800, + 0xa00, 0xc00, 0x100, 0x400, + +}; +//Mask the counter with this +static const Bit16u WaveMaskTable[8] = { + 1023, 1023, 511, 511, + 1023, 1023, 512, 1023, +}; + +//Where to start the counter on at keyon +static const Bit16u WaveStartTable[8] = { + 512, 0, 0, 0, + 0, 512, 512, 256, +}; +#endif + +#if ( DBOPL_WAVE == WAVE_TABLEMUL ) +static Bit16u MulTable[ 384 ]; +#endif + +static Bit8u KslTable[ 8 * 16 ]; +static Bit8u TremoloTable[ TREMOLO_TABLE ]; +//Start of a channel behind the chip struct start +static Bit16u ChanOffsetTable[32]; +//Start of an operator behind the chip struct start +static Bit16u OpOffsetTable[64]; + +//The lower bits are the shift of the operator vibrato value +//The highest bit is right shifted to generate -1 or 0 for negation +//So taking the highest input value of 7 this gives 3, 7, 3, 0, -3, -7, -3, 0 +static const Bit8s VibratoTable[ 8 ] = { + 1 - 0x00, 0 - 0x00, 1 - 0x00, 30 - 0x00, + 1 - 0x80, 0 - 0x80, 1 - 0x80, 30 - 0x80 +}; + +//Shift strength for the ksl value determined by ksl strength +static const Bit8u KslShiftTable[4] = { + 31,1,2,0 +}; + +//Generate a table index and table shift value using input value from a selected rate +static void EnvelopeSelect( Bit8u val, Bit8u& index, Bit8u& shift ) { + if ( val < 13 * 4 ) { //Rate 0 - 12 + shift = 12 - ( val >> 2 ); + index = val & 3; + } else if ( val < 15 * 4 ) { //rate 13 - 14 + shift = 0; + index = val - 12 * 4; + } else { //rate 15 and up + shift = 0; + index = 12; + } +} + +#if ( DBOPL_WAVE == WAVE_HANDLER ) +/* + Generate the different waveforms out of the sine/exponetial table using handlers +*/ +static inline Bits MakeVolume( Bitu wave, Bitu volume ) { + Bitu total = wave + volume; + Bitu index = total & 0xff; + Bitu sig = ExpTable[ index ]; + Bitu exp = total >> 8; +#if 0 + //Check if we overflow the 31 shift limit + if ( exp >= 32 ) { + LOG_MSG( "WTF %d %d", total, exp ); + } +#endif + return (sig >> exp); +}; + +static Bits DB_FASTCALL WaveForm0( Bitu i, Bitu volume ) { + Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0 + Bitu wave = SinTable[i & 511]; + return (MakeVolume( wave, volume ) ^ neg) - neg; +} +static Bits DB_FASTCALL WaveForm1( Bitu i, Bitu volume ) { + Bit32u wave = SinTable[i & 511]; + wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 ); + return MakeVolume( wave, volume ); +} +static Bits DB_FASTCALL WaveForm2( Bitu i, Bitu volume ) { + Bitu wave = SinTable[i & 511]; + return MakeVolume( wave, volume ); +} +static Bits DB_FASTCALL WaveForm3( Bitu i, Bitu volume ) { + Bitu wave = SinTable[i & 255]; + wave |= ( ( (i ^ 256 ) & 256) - 1) >> ( 32 - 12 ); + return MakeVolume( wave, volume ); +} +static Bits DB_FASTCALL WaveForm4( Bitu i, Bitu volume ) { + //Twice as fast + i <<= 1; + Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0 + Bitu wave = SinTable[i & 511]; + wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 ); + return (MakeVolume( wave, volume ) ^ neg) - neg; +} +static Bits DB_FASTCALL WaveForm5( Bitu i, Bitu volume ) { + //Twice as fast + i <<= 1; + Bitu wave = SinTable[i & 511]; + wave |= ( ( (i ^ 512 ) & 512) - 1) >> ( 32 - 12 ); + return MakeVolume( wave, volume ); +} +static Bits DB_FASTCALL WaveForm6( Bitu i, Bitu volume ) { + Bits neg = 0 - (( i >> 9) & 1);//Create ~0 or 0 + return (MakeVolume( 0, volume ) ^ neg) - neg; +} +static Bits DB_FASTCALL WaveForm7( Bitu i, Bitu volume ) { + //Negative is reversed here + Bits neg = (( i >> 9) & 1) - 1; + Bitu wave = (i << 3); + //When negative the volume also runs backwards + wave = ((wave ^ neg) - neg) & 4095; + return (MakeVolume( wave, volume ) ^ neg) - neg; +} + +static const WaveHandler WaveHandlerTable[8] = { + WaveForm0, WaveForm1, WaveForm2, WaveForm3, + WaveForm4, WaveForm5, WaveForm6, WaveForm7 +}; + +#endif + +/* + Operator +*/ + +//We zero out when rate == 0 +inline void Operator::UpdateAttack( const Chip* chip ) { + Bit8u rate = reg60 >> 4; + if ( rate ) { + Bit8u val = (rate << 2) + ksr; + attackAdd = chip->attackRates[ val ]; + rateZero &= ~(1 << ATTACK); + } else { + attackAdd = 0; + rateZero |= (1 << ATTACK); + } +} +inline void Operator::UpdateDecay( const Chip* chip ) { + Bit8u rate = reg60 & 0xf; + if ( rate ) { + Bit8u val = (rate << 2) + ksr; + decayAdd = chip->linearRates[ val ]; + rateZero &= ~(1 << DECAY); + } else { + decayAdd = 0; + rateZero |= (1 << DECAY); + } +} +inline void Operator::UpdateRelease( const Chip* chip ) { + Bit8u rate = reg80 & 0xf; + if ( rate ) { + Bit8u val = (rate << 2) + ksr; + releaseAdd = chip->linearRates[ val ]; + rateZero &= ~(1 << RELEASE); + if ( !(reg20 & MASK_SUSTAIN ) ) { + rateZero &= ~( 1 << SUSTAIN ); + } + } else { + rateZero |= (1 << RELEASE); + releaseAdd = 0; + if ( !(reg20 & MASK_SUSTAIN ) ) { + rateZero |= ( 1 << SUSTAIN ); + } + } +} + +inline void Operator::UpdateAttenuation( ) { + Bit8u kslBase = (Bit8u)((chanData >> SHIFT_KSLBASE) & 0xff); + Bit32u tl = reg40 & 0x3f; + Bit8u kslShift = KslShiftTable[ reg40 >> 6 ]; + //Make sure the attenuation goes to the right bits + totalLevel = tl << ( ENV_BITS - 7 ); //Total level goes 2 bits below max + totalLevel += ( kslBase << ENV_EXTRA ) >> kslShift; +} + +void Operator::UpdateFrequency( ) { + Bit32u freq = chanData & (( 1 << 10 ) - 1); + Bit32u block = (chanData >> 10) & 0xff; +#ifdef WAVE_PRECISION + block = 7 - block; + waveAdd = ( freq * freqMul ) >> block; +#else + waveAdd = ( freq << block ) * freqMul; +#endif + if ( reg20 & MASK_VIBRATO ) { + vibStrength = (Bit8u)(freq >> 7); + +#ifdef WAVE_PRECISION + vibrato = ( vibStrength * freqMul ) >> block; +#else + vibrato = ( vibStrength << block ) * freqMul; +#endif + } else { + vibStrength = 0; + vibrato = 0; + } +} + +void Operator::UpdateRates( const Chip* chip ) { + //Mame seems to reverse this where enabling ksr actually lowers + //the rate, but pdf manuals says otherwise? + Bit8u newKsr = (Bit8u)((chanData >> SHIFT_KEYCODE) & 0xff); + if ( !( reg20 & MASK_KSR ) ) { + newKsr >>= 2; + } + if ( ksr == newKsr ) + return; + ksr = newKsr; + UpdateAttack( chip ); + UpdateDecay( chip ); + UpdateRelease( chip ); +} + +INLINE Bit32s Operator::RateForward( Bit32u add ) { + rateIndex += add; + Bit32s ret = rateIndex >> RATE_SH; + rateIndex = rateIndex & RATE_MASK; + return ret; +} + +template< Operator::State yes> +Bits Operator::TemplateVolume( ) { + Bit32s vol = volume; + Bit32s change; + switch ( yes ) { + case OFF: + return ENV_MAX; + case ATTACK: + change = RateForward( attackAdd ); + if ( !change ) + return vol; + vol += ( (~vol) * change ) >> 3; + if ( vol < ENV_MIN ) { + volume = ENV_MIN; + rateIndex = 0; + SetState( DECAY ); + return ENV_MIN; + } + break; + case DECAY: + vol += RateForward( decayAdd ); + if ( GCC_UNLIKELY(vol >= sustainLevel) ) { + //Check if we didn't overshoot max attenuation, then just go off + if ( GCC_UNLIKELY(vol >= ENV_MAX) ) { + volume = ENV_MAX; + SetState( OFF ); + return ENV_MAX; + } + //Continue as sustain + rateIndex = 0; + SetState( SUSTAIN ); + } + break; + case SUSTAIN: + if ( reg20 & MASK_SUSTAIN ) { + return vol; + } + //In sustain phase, but not sustaining, do regular release + case RELEASE: + vol += RateForward( releaseAdd );; + if ( GCC_UNLIKELY(vol >= ENV_MAX) ) { + volume = ENV_MAX; + SetState( OFF ); + return ENV_MAX; + } + break; + } + volume = vol; + return vol; +} + +static const VolumeHandler VolumeHandlerTable[5] = { + &Operator::TemplateVolume< Operator::OFF >, + &Operator::TemplateVolume< Operator::RELEASE >, + &Operator::TemplateVolume< Operator::SUSTAIN >, + &Operator::TemplateVolume< Operator::DECAY >, + &Operator::TemplateVolume< Operator::ATTACK > +}; + +INLINE Bitu Operator::ForwardVolume() { + return currentLevel + (this->*volHandler)(); +} + + +INLINE Bitu Operator::ForwardWave() { + waveIndex += waveCurrent; + return waveIndex >> WAVE_SH; +} + +void Operator::Write20( const Chip* chip, Bit8u val ) { + Bit8u change = (reg20 ^ val ); + if ( !change ) + return; + reg20 = val; + //Shift the tremolo bit over the entire register, saved a branch, YES! + tremoloMask = (Bit8s)(val) >> 7; + tremoloMask &= ~(( 1 << ENV_EXTRA ) -1); + //Update specific features based on changes + if ( change & MASK_KSR ) { + UpdateRates( chip ); + } + //With sustain enable the volume doesn't change + if ( reg20 & MASK_SUSTAIN || ( !releaseAdd ) ) { + rateZero |= ( 1 << SUSTAIN ); + } else { + rateZero &= ~( 1 << SUSTAIN ); + } + //Frequency multiplier or vibrato changed + if ( change & (0xf | MASK_VIBRATO) ) { + freqMul = chip->freqMul[ val & 0xf ]; + UpdateFrequency(); + } +} + +void Operator::Write40( const Chip* /*chip*/, Bit8u val ) { + if (!(reg40 ^ val )) + return; + reg40 = val; + UpdateAttenuation( ); +} + +void Operator::Write60( const Chip* chip, Bit8u val ) { + Bit8u change = reg60 ^ val; + reg60 = val; + if ( change & 0x0f ) { + UpdateDecay( chip ); + } + if ( change & 0xf0 ) { + UpdateAttack( chip ); + } +} + +void Operator::Write80( const Chip* chip, Bit8u val ) { + Bit8u change = (reg80 ^ val ); + if ( !change ) + return; + reg80 = val; + Bit8u sustain = val >> 4; + //Turn 0xf into 0x1f + sustain |= ( sustain + 1) & 0x10; + sustainLevel = sustain << ( ENV_BITS - 5 ); + if ( change & 0x0f ) { + UpdateRelease( chip ); + } +} + +void Operator::WriteE0( const Chip* chip, Bit8u val ) { + if ( !(regE0 ^ val) ) + return; + //in opl3 mode you can always selet 7 waveforms regardless of waveformselect + Bit8u waveForm = val & ( ( 0x3 & chip->waveFormMask ) | (0x7 & chip->opl3Active ) ); + regE0 = val; +#if ( DBOPL_WAVE == WAVE_HANDLER ) + waveHandler = WaveHandlerTable[ waveForm ]; +#else + waveBase = WaveTable + WaveBaseTable[ waveForm ]; + waveStart = WaveStartTable[ waveForm ] << WAVE_SH; + waveMask = WaveMaskTable[ waveForm ]; +#endif +} + +INLINE void Operator::SetState( Bit8u s ) { + state = s; + volHandler = VolumeHandlerTable[ s ]; +} + +INLINE bool Operator::Silent() const { + if ( !ENV_SILENT( totalLevel + volume ) ) + return false; + if ( !(rateZero & ( 1 << state ) ) ) + return false; + return true; +} + +INLINE void Operator::Prepare( const Chip* chip ) { + currentLevel = totalLevel + (chip->tremoloValue & tremoloMask); + waveCurrent = waveAdd; + if ( vibStrength >> chip->vibratoShift ) { + Bit32s add = vibrato >> chip->vibratoShift; + //Sign extend over the shift value + Bit32s neg = chip->vibratoSign; + //Negate the add with -1 or 0 + add = ( add ^ neg ) - neg; + waveCurrent += add; + } +} + +void Operator::KeyOn( Bit8u mask ) { + if ( !keyOn ) { + //Restart the frequency generator +#if ( DBOPL_WAVE > WAVE_HANDLER ) + waveIndex = waveStart; +#else + waveIndex = 0; +#endif + rateIndex = 0; + SetState( ATTACK ); + } + keyOn |= mask; +} + +void Operator::KeyOff( Bit8u mask ) { + keyOn &= ~mask; + if ( !keyOn ) { + if ( state != OFF ) { + SetState( RELEASE ); + } + } +} + +INLINE Bits Operator::GetWave( Bitu index, Bitu vol ) { +#if ( DBOPL_WAVE == WAVE_HANDLER ) + return waveHandler( index, vol << ( 3 - ENV_EXTRA ) ); +#elif ( DBOPL_WAVE == WAVE_TABLEMUL ) + return (waveBase[ index & waveMask ] * MulTable[ vol >> ENV_EXTRA ]) >> MUL_SH; +#elif ( DBOPL_WAVE == WAVE_TABLELOG ) + Bit32s wave = waveBase[ index & waveMask ]; + Bit32u total = ( wave & 0x7fff ) + vol << ( 3 - ENV_EXTRA ); + Bit32s sig = ExpTable[ total & 0xff ]; + Bit32u exp = total >> 8; + Bit32s neg = wave >> 16; + return ((sig ^ neg) - neg) >> exp; +#else +#error "No valid wave routine" +#endif +} + +Bits INLINE Operator::GetSample( Bits modulation ) { + Bitu vol = ForwardVolume(); + if ( ENV_SILENT( vol ) ) { + //Simply forward the wave + waveIndex += waveCurrent; + return 0; + } else { + Bitu index = ForwardWave(); + index += modulation; + return GetWave( index, vol ); + } +} + +Operator::Operator() { + chanData = 0; + freqMul = 0; + waveIndex = 0; + waveAdd = 0; + waveCurrent = 0; + keyOn = 0; + ksr = 0; + reg20 = 0; + reg40 = 0; + reg60 = 0; + reg80 = 0; + regE0 = 0; + SetState( OFF ); + rateZero = (1 << OFF); + sustainLevel = ENV_MAX; + currentLevel = ENV_MAX; + totalLevel = ENV_MAX; + volume = ENV_MAX; + releaseAdd = 0; +} + +/* + Channel +*/ + +Channel::Channel() { + old[0] = old[1] = 0; + chanData = 0; + regB0 = 0; + regC0 = 0; + maskLeft = -1; + maskRight = -1; + feedback = 31; + fourMask = 0; + synthHandler = &Channel::BlockTemplate< sm2FM >; +}; + +void Channel::SetChanData( const Chip* chip, Bit32u data ) { + Bit32u change = chanData ^ data; + chanData = data; + Op( 0 )->chanData = data; + Op( 1 )->chanData = data; + //Since a frequency update triggered this, always update frequency + Op( 0 )->UpdateFrequency(); + Op( 1 )->UpdateFrequency(); + if ( change & ( 0xff << SHIFT_KSLBASE ) ) { + Op( 0 )->UpdateAttenuation(); + Op( 1 )->UpdateAttenuation(); + } + if ( change & ( 0xff << SHIFT_KEYCODE ) ) { + Op( 0 )->UpdateRates( chip ); + Op( 1 )->UpdateRates( chip ); + } +} + +void Channel::UpdateFrequency( const Chip* chip, Bit8u fourOp ) { + //Extrace the frequency bits + Bit32u data = chanData & 0xffff; + Bit32u kslBase = KslTable[ data >> 6 ]; + Bit32u keyCode = ( data & 0x1c00) >> 9; + if ( chip->reg08 & 0x40 ) { + keyCode |= ( data & 0x100)>>8; /* notesel == 1 */ + } else { + keyCode |= ( data & 0x200)>>9; /* notesel == 0 */ + } + //Add the keycode and ksl into the highest bits of chanData + data |= (keyCode << SHIFT_KEYCODE) | ( kslBase << SHIFT_KSLBASE ); + ( this + 0 )->SetChanData( chip, data ); + if ( fourOp & 0x3f ) { + ( this + 1 )->SetChanData( chip, data ); + } +} + +void Channel::WriteA0( const Chip* chip, Bit8u val ) { + Bit8u fourOp = chip->reg104 & chip->opl3Active & fourMask; + //Don't handle writes to silent fourop channels + if ( fourOp > 0x80 ) + return; + Bit32u change = (chanData ^ val ) & 0xff; + if ( change ) { + chanData ^= change; + UpdateFrequency( chip, fourOp ); + } +} + +void Channel::WriteB0( const Chip* chip, Bit8u val ) { + Bit8u fourOp = chip->reg104 & chip->opl3Active & fourMask; + //Don't handle writes to silent fourop channels + if ( fourOp > 0x80 ) + return; + Bitu change = (chanData ^ ( val << 8 ) ) & 0x1f00; + if ( change ) { + chanData ^= change; + UpdateFrequency( chip, fourOp ); + } + //Check for a change in the keyon/off state + if ( !(( val ^ regB0) & 0x20)) + return; + regB0 = val; + if ( val & 0x20 ) { + Op(0)->KeyOn( 0x1 ); + Op(1)->KeyOn( 0x1 ); + if ( fourOp & 0x3f ) { + ( this + 1 )->Op(0)->KeyOn( 1 ); + ( this + 1 )->Op(1)->KeyOn( 1 ); + } + } else { + Op(0)->KeyOff( 0x1 ); + Op(1)->KeyOff( 0x1 ); + if ( fourOp & 0x3f ) { + ( this + 1 )->Op(0)->KeyOff( 1 ); + ( this + 1 )->Op(1)->KeyOff( 1 ); + } + } +} + +void Channel::WriteC0( const Chip* chip, Bit8u val ) { + Bit8u change = val ^ regC0; + if ( !change ) + return; + regC0 = val; + feedback = ( val >> 1 ) & 7; + if ( feedback ) { + //We shift the input to the right 10 bit wave index value + feedback = 9 - feedback; + } else { + feedback = 31; + } + //Select the new synth mode + if ( chip->opl3Active ) { + //4-op mode enabled for this channel + if ( (chip->reg104 & fourMask) & 0x3f ) { + Channel* chan0, *chan1; + //Check if it's the 2nd channel in a 4-op + if ( !(fourMask & 0x80 ) ) { + chan0 = this; + chan1 = this + 1; + } else { + chan0 = this - 1; + chan1 = this; + } + + Bit8u synth = ( (chan0->regC0 & 1) << 0 )| (( chan1->regC0 & 1) << 1 ); + switch ( synth ) { + case 0: + chan0->synthHandler = &Channel::BlockTemplate< sm3FMFM >; + break; + case 1: + chan0->synthHandler = &Channel::BlockTemplate< sm3AMFM >; + break; + case 2: + chan0->synthHandler = &Channel::BlockTemplate< sm3FMAM >; + break; + case 3: + chan0->synthHandler = &Channel::BlockTemplate< sm3AMAM >; + break; + } + //Disable updating percussion channels + } else if ((fourMask & 0x40) && ( chip->regBD & 0x20) ) { + + //Regular dual op, am or fm + } else if ( val & 1 ) { + synthHandler = &Channel::BlockTemplate< sm3AM >; + } else { + synthHandler = &Channel::BlockTemplate< sm3FM >; + } + maskLeft = ( val & 0x10 ) ? -1 : 0; + maskRight = ( val & 0x20 ) ? -1 : 0; + //opl2 active + } else { + //Disable updating percussion channels + if ( (fourMask & 0x40) && ( chip->regBD & 0x20 ) ) { + + //Regular dual op, am or fm + } else if ( val & 1 ) { + synthHandler = &Channel::BlockTemplate< sm2AM >; + } else { + synthHandler = &Channel::BlockTemplate< sm2FM >; + } + } +} + +void Channel::ResetC0( const Chip* chip ) { + Bit8u val = regC0; + regC0 ^= 0xff; + WriteC0( chip, val ); +}; + +template< bool opl3Mode> +INLINE void Channel::GeneratePercussion( Chip* chip, Bit32s* output ) { + Channel* chan = this; + + //BassDrum + Bit32s mod = (Bit32u)((old[0] + old[1])) >> feedback; + old[0] = old[1]; + old[1] = Op(0)->GetSample( mod ); + + //When bassdrum is in AM mode first operator is ignoed + if ( chan->regC0 & 1 ) { + mod = 0; + } else { + mod = old[0]; + } + Bit32s sample = Op(1)->GetSample( mod ); + + + //Precalculate stuff used by other outputs + Bit32u noiseBit = chip->ForwardNoise() & 0x1; + Bit32u c2 = Op(2)->ForwardWave(); + Bit32u c5 = Op(5)->ForwardWave(); + Bit32u phaseBit = (((c2 & 0x88) ^ ((c2<<5) & 0x80)) | ((c5 ^ (c5<<2)) & 0x20)) ? 0x02 : 0x00; + + //Hi-Hat + Bit32u hhVol = Op(2)->ForwardVolume(); + if ( !ENV_SILENT( hhVol ) ) { + Bit32u hhIndex = (phaseBit<<8) | (0x34 << ( phaseBit ^ (noiseBit << 1 ))); + sample += Op(2)->GetWave( hhIndex, hhVol ); + } + //Snare Drum + Bit32u sdVol = Op(3)->ForwardVolume(); + if ( !ENV_SILENT( sdVol ) ) { + Bit32u sdIndex = ( 0x100 + (c2 & 0x100) ) ^ ( noiseBit << 8 ); + sample += Op(3)->GetWave( sdIndex, sdVol ); + } + //Tom-tom + sample += Op(4)->GetSample( 0 ); + + //Top-Cymbal + Bit32u tcVol = Op(5)->ForwardVolume(); + if ( !ENV_SILENT( tcVol ) ) { + Bit32u tcIndex = (1 + phaseBit) << 8; + sample += Op(5)->GetWave( tcIndex, tcVol ); + } + sample <<= 1; + if ( opl3Mode ) { + output[0] += sample; + output[1] += sample; + } else { + output[0] += sample; + } +} + +template +Channel* Channel::BlockTemplate( Chip* chip, Bit32u samples, Bit32s* output ) { + switch( mode ) { + case sm2AM: + case sm3AM: + if ( Op(0)->Silent() && Op(1)->Silent() ) { + old[0] = old[1] = 0; + return (this + 1); + } + break; + case sm2FM: + case sm3FM: + if ( Op(1)->Silent() ) { + old[0] = old[1] = 0; + return (this + 1); + } + break; + case sm3FMFM: + if ( Op(3)->Silent() ) { + old[0] = old[1] = 0; + return (this + 2); + } + break; + case sm3AMFM: + if ( Op(0)->Silent() && Op(3)->Silent() ) { + old[0] = old[1] = 0; + return (this + 2); + } + break; + case sm3FMAM: + if ( Op(1)->Silent() && Op(3)->Silent() ) { + old[0] = old[1] = 0; + return (this + 2); + } + break; + case sm3AMAM: + if ( Op(0)->Silent() && Op(2)->Silent() && Op(3)->Silent() ) { + old[0] = old[1] = 0; + return (this + 2); + } + break; + } + //Init the operators with the the current vibrato and tremolo values + Op( 0 )->Prepare( chip ); + Op( 1 )->Prepare( chip ); + if ( mode > sm4Start ) { + Op( 2 )->Prepare( chip ); + Op( 3 )->Prepare( chip ); + } + if ( mode > sm6Start ) { + Op( 4 )->Prepare( chip ); + Op( 5 )->Prepare( chip ); + } + for ( Bitu i = 0; i < samples; i++ ) { + //Early out for percussion handlers + if ( mode == sm2Percussion ) { + GeneratePercussion( chip, output + i ); + continue; //Prevent some unitialized value bitching + } else if ( mode == sm3Percussion ) { + GeneratePercussion( chip, output + i * 2 ); + continue; //Prevent some unitialized value bitching + } + + //Do unsigned shift so we can shift out all bits but still stay in 10 bit range otherwise + Bit32s mod = (Bit32u)((old[0] + old[1])) >> feedback; + old[0] = old[1]; + old[1] = Op(0)->GetSample( mod ); + Bit32s sample; + Bit32s out0 = old[0]; + if ( mode == sm2AM || mode == sm3AM ) { + sample = out0 + Op(1)->GetSample( 0 ); + } else if ( mode == sm2FM || mode == sm3FM ) { + sample = Op(1)->GetSample( out0 ); + } else if ( mode == sm3FMFM ) { + Bits next = Op(1)->GetSample( out0 ); + next = Op(2)->GetSample( next ); + sample = Op(3)->GetSample( next ); + } else if ( mode == sm3AMFM ) { + sample = out0; + Bits next = Op(1)->GetSample( 0 ); + next = Op(2)->GetSample( next ); + sample += Op(3)->GetSample( next ); + } else if ( mode == sm3FMAM ) { + sample = Op(1)->GetSample( out0 ); + Bits next = Op(2)->GetSample( 0 ); + sample += Op(3)->GetSample( next ); + } else if ( mode == sm3AMAM ) { + sample = out0; + Bits next = Op(1)->GetSample( 0 ); + sample += Op(2)->GetSample( next ); + sample += Op(3)->GetSample( 0 ); + } + switch( mode ) { + case sm2AM: + case sm2FM: + if (chip->is_opl3) + { + output[ i * 2 + 0 ] += sample; + output[ i * 2 + 1 ] += sample; + } + else + output[ i ] += sample; + break; + case sm3AM: + case sm3FM: + case sm3FMFM: + case sm3AMFM: + case sm3FMAM: + case sm3AMAM: + output[ i * 2 + 0 ] += sample & maskLeft; + output[ i * 2 + 1 ] += sample & maskRight; + break; + } + } + switch( mode ) { + case sm2AM: + case sm2FM: + case sm3AM: + case sm3FM: + return ( this + 1 ); + case sm3FMFM: + case sm3AMFM: + case sm3FMAM: + case sm3AMAM: + return( this + 2 ); + case sm2Percussion: + case sm3Percussion: + return( this + 3 ); + } + return 0; +} + +/* + Chip +*/ + +Chip::Chip() { + reg08 = 0; + reg04 = 0; + regBD = 0; + reg104 = 0; + opl3Active = 0; +} + +INLINE Bit32u Chip::ForwardNoise() { + noiseCounter += noiseAdd; + Bitu count = noiseCounter >> LFO_SH; + noiseCounter &= WAVE_MASK; + for ( ; count > 0; --count ) { + //Noise calculation from mame + noiseValue ^= ( 0x800302 ) & ( 0 - (noiseValue & 1 ) ); + noiseValue >>= 1; + } + return noiseValue; +} + +INLINE Bit32u Chip::ForwardLFO( Bit32u samples ) { + //Current vibrato value, runs 4x slower than tremolo + vibratoSign = ( VibratoTable[ vibratoIndex >> 2] ) >> 7; + vibratoShift = ( VibratoTable[ vibratoIndex >> 2] & 7) + vibratoStrength; + tremoloValue = TremoloTable[ tremoloIndex ] >> tremoloStrength; + + //Check hom many samples there can be done before the value changes + Bit32u todo = LFO_MAX - lfoCounter; + Bit32u count = (todo + lfoAdd - 1) / lfoAdd; + if ( count > samples ) { + count = samples; + lfoCounter += count * lfoAdd; + } else { + lfoCounter += count * lfoAdd; + lfoCounter &= (LFO_MAX - 1); + //Maximum of 7 vibrato value * 4 + vibratoIndex = ( vibratoIndex + 1 ) & 31; + //Clip tremolo to the the table size + if ( tremoloIndex + 1 < TREMOLO_TABLE ) + ++tremoloIndex; + else + tremoloIndex = 0; + } + return count; +} + + +void Chip::WriteBD( Bit8u val ) { + Bit8u change = regBD ^ val; + if ( !change ) + return; + regBD = val; + //TODO could do this with shift and xor? + vibratoStrength = (val & 0x40) ? 0x00 : 0x01; + tremoloStrength = (val & 0x80) ? 0x00 : 0x02; + if ( val & 0x20 ) { + //Drum was just enabled, make sure channel 6 has the right synth + if ( change & 0x20 ) { + // if ( opl3Active ) { + if ( is_opl3 ) { + chan[6].synthHandler = &Channel::BlockTemplate< sm3Percussion >; + } else { + chan[6].synthHandler = &Channel::BlockTemplate< sm2Percussion >; + } + } + //Bass Drum + if ( val & 0x10 ) { + chan[6].op[0].KeyOn( 0x2 ); + chan[6].op[1].KeyOn( 0x2 ); + } else { + chan[6].op[0].KeyOff( 0x2 ); + chan[6].op[1].KeyOff( 0x2 ); + } + //Hi-Hat + if ( val & 0x1 ) { + chan[7].op[0].KeyOn( 0x2 ); + } else { + chan[7].op[0].KeyOff( 0x2 ); + } + //Snare + if ( val & 0x8 ) { + chan[7].op[1].KeyOn( 0x2 ); + } else { + chan[7].op[1].KeyOff( 0x2 ); + } + //Tom-Tom + if ( val & 0x4 ) { + chan[8].op[0].KeyOn( 0x2 ); + } else { + chan[8].op[0].KeyOff( 0x2 ); + } + //Top Cymbal + if ( val & 0x2 ) { + chan[8].op[1].KeyOn( 0x2 ); + } else { + chan[8].op[1].KeyOff( 0x2 ); + } + //Toggle keyoffs when we turn off the percussion + } else if ( change & 0x20 ) { + //Trigger a reset to setup the original synth handler + chan[6].ResetC0( this ); + chan[6].op[0].KeyOff( 0x2 ); + chan[6].op[1].KeyOff( 0x2 ); + chan[7].op[0].KeyOff( 0x2 ); + chan[7].op[1].KeyOff( 0x2 ); + chan[8].op[0].KeyOff( 0x2 ); + chan[8].op[1].KeyOff( 0x2 ); + } +} + + +#define REGOP( _FUNC_ ) \ + index = ( ( reg >> 3) & 0x20 ) | ( reg & 0x1f ); \ + if ( OpOffsetTable[ index ] ) { \ + Operator* regOp = (Operator*)( ((char *)this ) + OpOffsetTable[ index ] ); \ + regOp->_FUNC_( this, val ); \ + } + +#define REGCHAN( _FUNC_ ) \ + index = ( ( reg >> 4) & 0x10 ) | ( reg & 0xf ); \ + if ( ChanOffsetTable[ index ] ) { \ + Channel* regChan = (Channel*)( ((char *)this ) + ChanOffsetTable[ index ] ); \ + regChan->_FUNC_( this, val ); \ + } + +void Chip::WriteReg( Bit32u reg, Bit8u val ) { + Bitu index; + switch ( (reg & 0xf0) >> 4 ) { + case 0x00 >> 4: + if ( reg == 0x01 ) { + waveFormMask = ( val & 0x20 ) ? 0x7 : 0x0; + } else if ( reg == 0x104 ) { + //Only detect changes in lowest 6 bits + if ( !((reg104 ^ val) & 0x3f) ) + return; + //Always keep the highest bit enabled, for checking > 0x80 + reg104 = 0x80 | ( val & 0x3f ); + } else if ( reg == 0x105 ) { + //MAME says the real opl3 doesn't reset anything on opl3 disable/enable till the next write in another register + if ( !((opl3Active ^ val) & 1 ) ) + return; + opl3Active = ( val & 1 ) ? 0xff : 0; + //Update the 0xc0 register for all channels to signal the switch to mono/stereo handlers + for ( int i = 0; i < 18;i++ ) { + chan[i].ResetC0( this ); + } + } else if ( reg == 0x08 ) { + reg08 = val; + } + case 0x10 >> 4: + break; + case 0x20 >> 4: + case 0x30 >> 4: + REGOP( Write20 ); + break; + case 0x40 >> 4: + case 0x50 >> 4: + REGOP( Write40 ); + break; + case 0x60 >> 4: + case 0x70 >> 4: + REGOP( Write60 ); + break; + case 0x80 >> 4: + case 0x90 >> 4: + REGOP( Write80 ); + break; + case 0xa0 >> 4: + REGCHAN( WriteA0 ); + break; + case 0xb0 >> 4: + if ( reg == 0xbd ) { + WriteBD( val ); + } else { + REGCHAN( WriteB0 ); + } + break; + case 0xc0 >> 4: + REGCHAN( WriteC0 ); + case 0xd0 >> 4: + break; + case 0xe0 >> 4: + case 0xf0 >> 4: + REGOP( WriteE0 ); + break; + } +} + + +Bit32u Chip::WriteAddr( Bit32u port, Bit8u val ) { + switch ( port & 3 ) { + case 0: + return val; + case 2: + if ( opl3Active || (val == 0x05) ) + return 0x100 | val; + else + return val; + } + return 0; +} + +void Chip::GenerateBlock2( Bitu total, Bit32s* output ) { + while ( total > 0 ) { + Bit32u samples = ForwardLFO( total ); + memset(output, 0, sizeof(Bit32s) * samples); + int count = 0; + for( Channel* ch = chan; ch < chan + 9; ) { + count++; + ch = (ch->*(ch->synthHandler))( this, samples, output ); + } + total -= samples; + output += samples; + } +} + +void Chip::GenerateBlock3( Bitu total, Bit32s* output ) { + while ( total > 0 ) { + Bit32u samples = ForwardLFO( total ); + memset(output, 0, sizeof(Bit32s) * samples *2); + int count = 0; + for( Channel* ch = chan; ch < chan + 18; ) { + count++; + ch = (ch->*(ch->synthHandler))( this, samples, output ); + } + total -= samples; + output += samples * 2; + } +} + +void Chip::Setup( Bit32u rate, int chip_is_opl3 ) { + double original = OPLRATE; +// double original = rate; + double scale = original / (double)rate; + + is_opl3 = chip_is_opl3; + + //Noise counter is run at the same precision as general waves + noiseAdd = (Bit32u)( 0.5 + scale * ( 1 << LFO_SH ) ); + noiseCounter = 0; + noiseValue = 1; //Make sure it triggers the noise xor the first time + //The low frequency oscillation counter + //Every time his overflows vibrato and tremoloindex are increased + lfoAdd = (Bit32u)( 0.5 + scale * ( 1 << LFO_SH ) ); + lfoCounter = 0; + vibratoIndex = 0; + tremoloIndex = 0; + + //With higher octave this gets shifted up + //-1 since the freqCreateTable = *2 +#ifdef WAVE_PRECISION + double freqScale = ( 1 << 7 ) * scale * ( 1 << ( WAVE_SH - 1 - 10)); + for ( int i = 0; i < 16; i++ ) { + freqMul[i] = (Bit32u)( 0.5 + freqScale * FreqCreateTable[ i ] ); + } +#else + Bit32u freqScale = (Bit32u)( 0.5 + scale * ( 1 << ( WAVE_SH - 1 - 10))); + for ( int i = 0; i < 16; i++ ) { + freqMul[i] = freqScale * FreqCreateTable[ i ]; + } +#endif + + //-3 since the real envelope takes 8 steps to reach the single value we supply + for ( Bit8u i = 0; i < 76; i++ ) { + Bit8u index, shift; + EnvelopeSelect( i, index, shift ); + linearRates[i] = (Bit32u)( scale * (EnvelopeIncreaseTable[ index ] << ( RATE_SH + ENV_EXTRA - shift - 3 ))); + } + //Generate the best matching attack rate + for ( Bit8u i = 0; i < 62; i++ ) { + Bit8u index, shift; + EnvelopeSelect( i, index, shift ); + //Original amount of samples the attack would take + Bit32s original = (Bit32u)( (AttackSamplesTable[ index ] << shift) / scale); + + Bit32s guessAdd = (Bit32u)( scale * (EnvelopeIncreaseTable[ index ] << ( RATE_SH - shift - 3 ))); + Bit32s bestAdd = guessAdd; + Bit32u bestDiff = 1 << 30; + for( Bit32u passes = 0; passes < 16; passes ++ ) { + Bit32s volume = ENV_MAX; + Bit32s samples = 0; + Bit32u count = 0; + while ( volume > 0 && samples < original * 2 ) { + count += guessAdd; + Bit32s change = count >> RATE_SH; + count &= RATE_MASK; + if ( GCC_UNLIKELY(change) ) { // less than 1 % + volume += ( ~volume * change ) >> 3; + } + samples++; + + } + Bit32s diff = original - samples; + Bit32u lDiff = labs( diff ); + //Init last on first pass + if ( lDiff < bestDiff ) { + bestDiff = lDiff; + bestAdd = guessAdd; + if ( !bestDiff ) + break; + } + //Below our target + if ( diff < 0 ) { + //Better than the last time + Bit32s mul = ((original - diff) << 12) / original; + guessAdd = ((guessAdd * mul) >> 12); + guessAdd++; + } else if ( diff > 0 ) { + Bit32s mul = ((original - diff) << 12) / original; + guessAdd = (guessAdd * mul) >> 12; + guessAdd--; + } + } + attackRates[i] = bestAdd; + } + for ( Bit8u i = 62; i < 76; i++ ) { + //This should provide instant volume maximizing + attackRates[i] = 8 << RATE_SH; + } + //Setup the channels with the correct four op flags + //Channels are accessed through a table so they appear linear here + chan[ 0].fourMask = 0x00 | ( 1 << 0 ); + chan[ 1].fourMask = 0x80 | ( 1 << 0 ); + chan[ 2].fourMask = 0x00 | ( 1 << 1 ); + chan[ 3].fourMask = 0x80 | ( 1 << 1 ); + chan[ 4].fourMask = 0x00 | ( 1 << 2 ); + chan[ 5].fourMask = 0x80 | ( 1 << 2 ); + + chan[ 9].fourMask = 0x00 | ( 1 << 3 ); + chan[10].fourMask = 0x80 | ( 1 << 3 ); + chan[11].fourMask = 0x00 | ( 1 << 4 ); + chan[12].fourMask = 0x80 | ( 1 << 4 ); + chan[13].fourMask = 0x00 | ( 1 << 5 ); + chan[14].fourMask = 0x80 | ( 1 << 5 ); + + //mark the percussion channels + chan[ 6].fourMask = 0x40; + chan[ 7].fourMask = 0x40; + chan[ 8].fourMask = 0x40; + + //Clear Everything in opl3 mode + WriteReg( 0x105, 0x1 ); + for ( int i = 0; i < 512; i++ ) { + if ( i == 0x105 ) + continue; + WriteReg( i, 0xff ); + WriteReg( i, 0x0 ); + } + WriteReg( 0x105, 0x0 ); + //Clear everything in opl2 mode + for ( int i = 0; i < 255; i++ ) { + WriteReg( i, 0xff ); + WriteReg( i, 0x0 ); + } +} + +static bool doneTables = false; +void InitTables( void ) { + if ( doneTables ) + return; + doneTables = true; +#if ( DBOPL_WAVE == WAVE_HANDLER ) || ( DBOPL_WAVE == WAVE_TABLELOG ) + //Exponential volume table, same as the real adlib + for ( int i = 0; i < 256; i++ ) { + //Save them in reverse + ExpTable[i] = (int)( 0.5 + ( pow(2.0, ( 255 - i) * ( 1.0 /256 ) )-1) * 1024 ); + ExpTable[i] += 1024; //or remove the -1 oh well :) + //Preshift to the left once so the final volume can shift to the right + ExpTable[i] *= 2; + } +#endif +#if ( DBOPL_WAVE == WAVE_HANDLER ) + //Add 0.5 for the trunc rounding of the integer cast + //Do a PI sinetable instead of the original 0.5 PI + for ( int i = 0; i < 512; i++ ) { + SinTable[i] = (Bit16s)( 0.5 - log10( sin( (i + 0.5) * (PI / 512.0) ) ) / log10(2.0)*256 ); + } +#endif +#if ( DBOPL_WAVE == WAVE_TABLEMUL ) + //Multiplication based tables + for ( int i = 0; i < 384; i++ ) { + int s = i * 8; + //TODO maybe keep some of the precision errors of the original table? + double val = ( 0.5 + ( pow(2.0, -1.0 + ( 255 - s) * ( 1.0 /256 ) )) * ( 1 << MUL_SH )); + MulTable[i] = (Bit16u)(val); + } + + //Sine Wave Base + for ( int i = 0; i < 512; i++ ) { + WaveTable[ 0x0200 + i ] = (Bit16s)(sin( (i + 0.5) * (PI / 512.0) ) * 4084); + WaveTable[ 0x0000 + i ] = -WaveTable[ 0x200 + i ]; + } + //Exponential wave + for ( int i = 0; i < 256; i++ ) { + WaveTable[ 0x700 + i ] = (Bit16s)( 0.5 + ( pow(2.0, -1.0 + ( 255 - i * 8) * ( 1.0 /256 ) ) ) * 4085 ); + WaveTable[ 0x6ff - i ] = -WaveTable[ 0x700 + i ]; + } +#endif +#if ( DBOPL_WAVE == WAVE_TABLELOG ) + //Sine Wave Base + for ( int i = 0; i < 512; i++ ) { + WaveTable[ 0x0200 + i ] = (Bit16s)( 0.5 - log10( sin( (i + 0.5) * (PI / 512.0) ) ) / log10(2.0)*256 ); + WaveTable[ 0x0000 + i ] = ((Bit16s)0x8000) | WaveTable[ 0x200 + i]; + } + //Exponential wave + for ( int i = 0; i < 256; i++ ) { + WaveTable[ 0x700 + i ] = i * 8; + WaveTable[ 0x6ff - i ] = ((Bit16s)0x8000) | i * 8; + } +#endif + + // | |//\\|____|WAV7|//__|/\ |____|/\/\| + // |\\//| | |WAV7| | \/| | | + // |06 |0126|27 |7 |3 |4 |4 5 |5 | + +#if (( DBOPL_WAVE == WAVE_TABLELOG ) || ( DBOPL_WAVE == WAVE_TABLEMUL )) + for ( int i = 0; i < 256; i++ ) { + //Fill silence gaps + WaveTable[ 0x400 + i ] = WaveTable[0]; + WaveTable[ 0x500 + i ] = WaveTable[0]; + WaveTable[ 0x900 + i ] = WaveTable[0]; + WaveTable[ 0xc00 + i ] = WaveTable[0]; + WaveTable[ 0xd00 + i ] = WaveTable[0]; + //Replicate sines in other pieces + WaveTable[ 0x800 + i ] = WaveTable[ 0x200 + i ]; + //double speed sines + WaveTable[ 0xa00 + i ] = WaveTable[ 0x200 + i * 2 ]; + WaveTable[ 0xb00 + i ] = WaveTable[ 0x000 + i * 2 ]; + WaveTable[ 0xe00 + i ] = WaveTable[ 0x200 + i * 2 ]; + WaveTable[ 0xf00 + i ] = WaveTable[ 0x200 + i * 2 ]; + } +#endif + + //Create the ksl table + for ( int oct = 0; oct < 8; oct++ ) { + int base = oct * 8; + for ( int i = 0; i < 16; i++ ) { + int val = base - KslCreateTable[i]; + if ( val < 0 ) + val = 0; + //*4 for the final range to match attenuation range + KslTable[ oct * 16 + i ] = val * 4; + } + } + //Create the Tremolo table, just increase and decrease a triangle wave + for ( Bit8u i = 0; i < TREMOLO_TABLE / 2; i++ ) { + Bit8u val = i << ENV_EXTRA; + TremoloTable[i] = val; + TremoloTable[TREMOLO_TABLE - 1 - i] = val; + } + //Create a table with offsets of the channels from the start of the chip + DBOPL::Chip* chip = 0; + for ( Bitu i = 0; i < 32; i++ ) { + Bitu index = i & 0xf; + if ( index >= 9 ) { + ChanOffsetTable[i] = 0; + continue; + } + //Make sure the four op channels follow eachother + if ( index < 6 ) { + index = (index % 3) * 2 + ( index / 3 ); + } + //Add back the bits for highest ones + if ( i >= 16 ) + index += 9; + intptr_t blah = reinterpret_cast( &(chip->chan[ index ]) ); + ChanOffsetTable[i] = blah; + } + //Same for operators + for ( Bitu i = 0; i < 64; i++ ) { + if ( i % 8 >= 6 || ( (i / 8) % 4 == 3 ) ) { + OpOffsetTable[i] = 0; + continue; + } + Bitu chNum = (i / 8) * 3 + (i % 8) % 3; + //Make sure we use 16 and up for the 2nd range to match the chanoffset gap + if ( chNum >= 12 ) + chNum += 16 - 12; + Bitu opNum = ( i % 8 ) / 3; + DBOPL::Channel* chan = 0; + intptr_t blah = reinterpret_cast( &(chan->op[opNum]) ); + OpOffsetTable[i] = ChanOffsetTable[ chNum ] + blah; + } +#if 0 + //Stupid checks if table's are correct + for ( Bitu i = 0; i < 18; i++ ) { + Bit32u find = (Bit16u)( &(chip->chan[ i ]) ); + for ( Bitu c = 0; c < 32; c++ ) { + if ( ChanOffsetTable[c] == find ) { + find = 0; + break; + } + } + if ( find ) { + find = find; + } + } + for ( Bitu i = 0; i < 36; i++ ) { + Bit32u find = (Bit16u)( &(chip->chan[ i / 2 ].op[i % 2]) ); + for ( Bitu c = 0; c < 64; c++ ) { + if ( OpOffsetTable[c] == find ) { + find = 0; + break; + } + } + if ( find ) { + find = find; + } + } +#endif +} + +/*Bit32u Handler::WriteAddr( Bit32u port, Bit8u val ) { + return chip.WriteAddr( port, val ); + +} +void Handler::WriteReg( Bit32u addr, Bit8u val ) { + chip.WriteReg( addr, val ); +} + +void Handler::Generate( MixerChannel* chan, Bitu samples ) { + Bit32s buffer[ 512 * 2 ]; + if ( GCC_UNLIKELY(samples > 512) ) + samples = 512; + if ( !chip.opl3Active ) { + chip.GenerateBlock2( samples, buffer ); + chan->AddSamples_m32( samples, buffer ); + } else { + chip.GenerateBlock3( samples, buffer ); + chan->AddSamples_s32( samples, buffer ); + } +} + +void Handler::Init( Bitu rate ) { + InitTables(); + chip.Setup( rate ); +}*/ + + +}; //Namespace DBOPL + diff --git a/src/dosbox/dbopl.h b/src/dosbox/dbopl.h new file mode 100644 index 000000000..b798ce321 --- /dev/null +++ b/src/dosbox/dbopl.h @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2002-2010 The DOSBox Team + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +//#include "adlib.h" +//#include "dosbox.h" +#include +typedef signed int Bits; +typedef unsigned int Bitu; +typedef int8_t Bit8s; +typedef uint8_t Bit8u; +typedef int16_t Bit16s; +typedef uint16_t Bit16u; +typedef int32_t Bit32s; +typedef uint32_t Bit32u; + +#define INLINE inline + +#define GCC_UNLIKELY(x) (x) + +//Use 8 handlers based on a small logatirmic wavetabe and an exponential table for volume +#define WAVE_HANDLER 10 +//Use a logarithmic wavetable with an exponential table for volume +#define WAVE_TABLELOG 11 +//Use a linear wavetable with a multiply table for volume +#define WAVE_TABLEMUL 12 + +//Select the type of wave generator routine +#define DBOPL_WAVE WAVE_TABLEMUL + +namespace DBOPL { + +struct Chip; +struct Operator; +struct Channel; + +#if (DBOPL_WAVE == WAVE_HANDLER) +typedef Bits ( DB_FASTCALL *WaveHandler) ( Bitu i, Bitu volume ); +#endif + +typedef Bits ( DBOPL::Operator::*VolumeHandler) ( ); +typedef Channel* ( DBOPL::Channel::*SynthHandler) ( Chip* chip, Bit32u samples, Bit32s* output ); + +//Different synth modes that can generate blocks of data +typedef enum { + sm2AM, + sm2FM, + sm3AM, + sm3FM, + sm4Start, + sm3FMFM, + sm3AMFM, + sm3FMAM, + sm3AMAM, + sm6Start, + sm2Percussion, + sm3Percussion, +} SynthMode; + +//Shifts for the values contained in chandata variable +enum { + SHIFT_KSLBASE = 16, + SHIFT_KEYCODE = 24, +}; + +struct Operator { +public: + //Masks for operator 20 values + enum { + MASK_KSR = 0x10, + MASK_SUSTAIN = 0x20, + MASK_VIBRATO = 0x40, + MASK_TREMOLO = 0x80, + }; + + typedef enum { + OFF, + RELEASE, + SUSTAIN, + DECAY, + ATTACK, + } State; + + VolumeHandler volHandler; + +#if (DBOPL_WAVE == WAVE_HANDLER) + WaveHandler waveHandler; //Routine that generate a wave +#else + Bit16s* waveBase; + Bit32u waveMask; + Bit32u waveStart; +#endif + Bit32u waveIndex; //WAVE_BITS shifted counter of the frequency index + Bit32u waveAdd; //The base frequency without vibrato + Bit32u waveCurrent; //waveAdd + vibratao + + Bit32u chanData; //Frequency/octave and derived data coming from whatever channel controls this + Bit32u freqMul; //Scale channel frequency with this, TODO maybe remove? + Bit32u vibrato; //Scaled up vibrato strength + Bit32s sustainLevel; //When stopping at sustain level stop here + Bit32s totalLevel; //totalLevel is added to every generated volume + Bit32u currentLevel; //totalLevel + tremolo + Bit32s volume; //The currently active volume + + Bit32u attackAdd; //Timers for the different states of the envelope + Bit32u decayAdd; + Bit32u releaseAdd; + Bit32u rateIndex; //Current position of the evenlope + + Bit8u rateZero; //Bits for the different states of the envelope having no changes + Bit8u keyOn; //Bitmask of different values that can generate keyon + //Registers, also used to check for changes + Bit8u reg20, reg40, reg60, reg80, regE0; + //Active part of the envelope we're in + Bit8u state; + //0xff when tremolo is enabled + Bit8u tremoloMask; + //Strength of the vibrato + Bit8u vibStrength; + //Keep track of the calculated KSR so we can check for changes + Bit8u ksr; +private: + void SetState( Bit8u s ); + void UpdateAttack( const Chip* chip ); + void UpdateRelease( const Chip* chip ); + void UpdateDecay( const Chip* chip ); +public: + void UpdateAttenuation(); + void UpdateRates( const Chip* chip ); + void UpdateFrequency( ); + + void Write20( const Chip* chip, Bit8u val ); + void Write40( const Chip* chip, Bit8u val ); + void Write60( const Chip* chip, Bit8u val ); + void Write80( const Chip* chip, Bit8u val ); + void WriteE0( const Chip* chip, Bit8u val ); + + bool Silent() const; + void Prepare( const Chip* chip ); + + void KeyOn( Bit8u mask); + void KeyOff( Bit8u mask); + + template< State state> + Bits TemplateVolume( ); + + Bit32s RateForward( Bit32u add ); + Bitu ForwardWave(); + Bitu ForwardVolume(); + + Bits GetSample( Bits modulation ); + Bits GetWave( Bitu index, Bitu vol ); +public: + Operator(); +}; + +struct Channel { + Operator op[2]; + inline Operator* Op( Bitu index ) { + return &( ( this + (index >> 1) )->op[ index & 1 ]); + } + SynthHandler synthHandler; + Bit32u chanData; //Frequency/octave and derived values + Bit32s old[2]; //Old data for feedback + + Bit8u feedback; //Feedback shift + Bit8u regB0; //Register values to check for changes + Bit8u regC0; + //This should correspond with reg104, bit 6 indicates a Percussion channel, bit 7 indicates a silent channel + Bit8u fourMask; + Bit8s maskLeft; //Sign extended values for both channel's panning + Bit8s maskRight; + + //Forward the channel data to the operators of the channel + void SetChanData( const Chip* chip, Bit32u data ); + //Change in the chandata, check for new values and if we have to forward to operators + void UpdateFrequency( const Chip* chip, Bit8u fourOp ); + void WriteA0( const Chip* chip, Bit8u val ); + void WriteB0( const Chip* chip, Bit8u val ); + void WriteC0( const Chip* chip, Bit8u val ); + void ResetC0( const Chip* chip ); + + //call this for the first channel + template< bool opl3Mode > + void GeneratePercussion( Chip* chip, Bit32s* output ); + + //Generate blocks of data in specific modes + template + Channel* BlockTemplate( Chip* chip, Bit32u samples, Bit32s* output ); + Channel(); +}; + +struct Chip { + //This is used as the base counter for vibrato and tremolo + Bit32u lfoCounter; + Bit32u lfoAdd; + + + Bit32u noiseCounter; + Bit32u noiseAdd; + Bit32u noiseValue; + + //Frequency scales for the different multiplications + Bit32u freqMul[16]; + //Rates for decay and release for rate of this chip + Bit32u linearRates[76]; + //Best match attack rates for the rate of this chip + Bit32u attackRates[76]; + + //18 channels with 2 operators each + Channel chan[18]; + + Bit8u reg104; + Bit8u reg08; + Bit8u reg04; + Bit8u regBD; + Bit8u vibratoIndex; + Bit8u tremoloIndex; + Bit8s vibratoSign; + Bit8u vibratoShift; + Bit8u tremoloValue; + Bit8u vibratoStrength; + Bit8u tremoloStrength; + //Mask for allowed wave forms + Bit8u waveFormMask; + //0 or -1 when enabled + Bit8s opl3Active; + + int is_opl3; + + //Return the maximum amount of samples before and LFO change + Bit32u ForwardLFO( Bit32u samples ); + Bit32u ForwardNoise(); + + void WriteBD( Bit8u val ); + void WriteReg(Bit32u reg, Bit8u val ); + + Bit32u WriteAddr( Bit32u port, Bit8u val ); + + void GenerateBlock2( Bitu samples, Bit32s* output ); + void GenerateBlock3( Bitu samples, Bit32s* output ); + + void Generate( Bit32u samples ); + void Setup( Bit32u r, int chip_is_opl3 ); + + Chip(); +}; + +/*struct Handler : public Adlib::Handler { + DBOPL::Chip chip; + virtual Bit32u WriteAddr( Bit32u port, Bit8u val ); + virtual void WriteReg( Bit32u addr, Bit8u val ); + virtual void Generate( MixerChannel* chan, Bitu samples ); + virtual void Init( Bitu rate ); +};*/ + +void InitTables( void ); + +}; //Namespace diff --git a/src/fdc.c b/src/fdc.c new file mode 100644 index 000000000..e01dacd45 --- /dev/null +++ b/src/fdc.c @@ -0,0 +1,1668 @@ +#include +#include +#include "ibm.h" + +#include "disc.h" +#include "dma.h" +#include "fdd.h" +#include "io.h" +#include "pic.h" +#include "timer.h" + +extern int motoron; + +extern int motor_on[2] = {0, 0}; + +static int fdc_reset_stat = 0; +/*FDC*/ +typedef struct FDC +{ + uint8_t dor,stat,command,dat,st0; + int head,track[256],sector,drive,lastdrive; + int rw_track; + int pos; + uint8_t params[256]; + uint8_t res[256]; + int pnum,ptot; + int rate; + uint8_t specify[256]; + int eot[256]; + int lock; + int perp; + uint8_t config, pretrk; + int abort; + uint8_t format_dat[256]; + int format_state; + int tc; + int written; + + int pcjr, ps1; + + int watchdog_timer; + int watchdog_count; + + int data_ready; + int inread; + + int dskchg_activelow; + int enable_3f1; + + int bitcell_period; + + int is_nsc; /* 1 = FDC is on a National Semiconductor Super I/O chip, 0 = other FDC. This is needed, + because the National Semiconductor Super I/O chips add some FDC commands. */ + int enh_mode; + int rwc[2]; + int boot_drive; + int densel_polarity; + int densel_force; + int drvrate[2]; + + int dma; + int fifo, tfifo; + int fifobufpos; + int drv2en; + uint8_t fifobuf[16]; + + int seek_params; /* Needed for relative seek. */ +} FDC; + +int skip_pulses[2] = {0, 0}; + +static FDC fdc; + +void fdc_callback(); +int timetolive; +//#define SECTORS 9 +int lastbyte=0; +uint8_t disc_3f7; + +int discmodified[2]; +int discrate[2]; + +int discint; + +#define FDC_STATE_NORMAL 0 +#define FDC_STATE_SEEK 1 + +int fdc_state = 0; + +void fdc_reset() +{ + fdc.stat=0x80; + fdc.pnum=fdc.ptot=0; + fdc.st0=0; + fdc.lock = 0; + fdc.head = 0; + fdc.abort = 0; + fdc_set_skip_pulses(0, 0); + fdc_set_skip_pulses(1, 0); + fdd_stepping_motor_on[0] = fdd_stepping_motor_on[1] = 0; + fdd_track_diff[0] = fdd_track_diff[1] = 0; +#if 0 + if (!AT) + { + fdc.rate = 2; + // fdc_update_rate(); + } +#endif + fdc_state = FDC_STATE_NORMAL; +// pclog("Reset FDC\n"); +} +int ins; + +void fdc_set_skip_pulses(int drive, int val) +{ + skip_pulses[drive] = val; + pclog("Skip pulses for drive %c: is now %i\n", 0x41 + drive, val); +} + +int fdc_skip_pulses(int drive) +{ + return (skip_pulses[drive] ? 1 : 0) || (discint < 0); +} + +void fdc_reset_fifo_buf() +{ + int i = 0; + memset(fdc.fifobuf, 0, 16); + fdc.fifobufpos = 0; +} + +void fdc_fifo_buf_write(int val) +{ + if (fdc.fifobufpos < fdc.tfifo) + { + fdc.fifobuf[fdc.fifobufpos] = val; + fdc.fifobufpos++; + fdc.fifobufpos %= fdc.tfifo; + // pclog("FIFO buffer position = %02X\n", fdc.fifobufpos); + if (fdc.fifobufpos == fdc.tfifo) fdc.fifobufpos = 0; + } +} + +int fdc_fifo_buf_read() +{ + int temp = 0; + if (fdc.fifobufpos < fdc.tfifo) + { + temp = fdc.fifobuf[fdc.fifobufpos]; + fdc.fifobufpos++; + fdc.fifobufpos %= fdc.tfifo; + // pclog("FIFO buffer position = %02X\n", fdc.fifobufpos); + if (fdc.fifobufpos == fdc.tfifo) fdc.fifobufpos = 0; + } + return temp; +} + +/* For DMA mode, just goes ahead in FIFO buffer but doesn't actually read or write anything. */ +void fdc_fifo_buf_dummy() +{ + if (fdc.fifobufpos < fdc.tfifo) + { + fdc.fifobufpos++; + fdc.fifobufpos %= fdc.tfifo; + // pclog("FIFO buffer position = %02X\n", fdc.fifobufpos); + if (fdc.fifobufpos == fdc.tfifo) fdc.fifobufpos = 0; + } +} + +static void fdc_int() +{ + pclog("FDC interrupt issued\n"); + if (!fdc.pcjr) + picint(1 << 6); +} + +static void fdc_watchdog_poll(void *p) +{ + FDC *fdc = (FDC *)p; + + fdc->watchdog_count--; + if (fdc->watchdog_count) + fdc->watchdog_timer += 1000 * TIMER_USEC; + else + { +// pclog("Watchdog timed out\n"); + + fdc->watchdog_timer = 0; + if (fdc->dor & 0x20) + picint(1 << 6); + } +} + +/* fdc.rwc per Winbond W83877F datasheet: + 0 = normal; + 1 = 500 kbps, 360 rpm; + 2 = 500 kbps, 300 rpm; + 3 = 250 kbps + + Drive is only aware of selected rate and densel, so on real hardware, the rate expected by FDC and the rate actually being + processed by drive can mismatch, in which case the FDC won't receive the correct data. +*/ + +int bit_rate = 250; + +void fdc_update_is_nsc(int is_nsc) +{ + fdc.is_nsc = is_nsc; +} + +void fdc_update_enh_mode(int enh_mode) +{ + fdc.enh_mode = enh_mode; +} + +int fdc_get_rwc(int drive) +{ + return fdc.rwc[drive]; +} + +void fdc_update_rwc(int drive, int rwc) +{ + fdc.rwc[drive] = rwc; +} + +int fdc_get_boot_drive() +{ + return fdc.boot_drive; +} + +void fdc_update_boot_drive(int boot_drive) +{ + fdc.boot_drive = boot_drive; +} + +void fdc_update_densel_polarity(int densel_polarity) +{ + fdc.densel_polarity = densel_polarity; +} + +void fdc_update_densel_force(int densel_force) +{ + fdc.densel_force = densel_force; +} + +void fdc_update_drvrate(int drive, int drvrate) +{ + fdc.drvrate[drive] = drvrate; +} + +void fdc_update_drv2en(int drv2en) +{ + fdc.drv2en = drv2en; +} + +void fdc_update_rate(int drive) +{ + if ((fdc.rwc[drive] == 1) || (fdc.rwc[drive] == 2)) + { + bit_rate = 500; + } + else if (fdc.rwc[drive] == 3) + { + bit_rate = 250; + } + else switch (fdc.rate) + { + case 0: /*High density*/ + bit_rate = 500; + break; + case 1: /*Double density (360 rpm)*/ + switch(fdc.drvrate[drive]) + { + case 0: + bit_rate = 300; + break; + case 1: + bit_rate = 500; + break; + case 2: + bit_rate = 2000; + break; + } + break; + case 2: /*Double density*/ + bit_rate = 250; + break; + case 3: /*Extended density*/ + bit_rate = 1000; + break; + } + + fdc.bitcell_period = 1000000 / bit_rate*2; /*Bitcell period in ns*/ + pclog("fdc_update_rate: rate=%i bit_rate=%i bitcell_period=%i\n", fdc.rate, bit_rate, fdc.bitcell_period); +} + +int fdc_get_bitcell_period() +{ + return fdc.bitcell_period; +} + +static int fdc_get_densel(int drive) +{ + switch (fdc.rwc[drive]) + { + case 1: + case 3: + return 0; + case 2: + return 1; + } + + if (!fdc.is_nsc) + { + switch (fdc.densel_force) + { + case 2: + return 1; + case 3: + return 0; + } + } + else + { + switch (fdc.densel_force) + { + case 0: + return 0; + case 1: + return 1; + } + } + + switch (fdc.rate) + { + case 0: + case 3: + return fdc.densel_polarity ? 1 : 0; + case 1: + case 2: + return fdc.densel_polarity ? 0 : 1; + } +} + +static void fdc_rate(int drive) +{ + fdc_update_rate(drive); + disc_set_rate(drive, fdc.drvrate[drive], fdc.rate); + fdd_set_densel(fdc_get_densel(drive)); + // pclog("Drive %i: enh. %i, rate %i, DENSEL %i, RWC %i, drvrate %i, densel polarity %i, NSC %i, densel force %i\n", drive, fdc.enh_mode, fdc.rate, fdc_get_densel(drive), fdc_get_rwc(drive), fdc.drvrate[drive], fdc.densel_polarity, fdc.is_nsc, fdc.densel_force); +} + +void fdc_seek(int drive, int params) +{ + fdd_seek(drive, params); + fdc.stat |= (1 << fdc.drive); + // fdc_state = FDC_STATE_SEEK; + pclog("FDC seek issued\n"); +} + +void fdc_write(uint16_t addr, uint8_t val, void *priv) +{ +// pclog("Write FDC %04X %02X %04X:%04X %i %02X %i rate=%i %i\n",addr,val,cs>>4,pc,ins,fdc.st0,ins,fdc.rate, fdc.data_ready); + int drive; + + // pclog("fdc_write: %04X: %02X\n", addr, val); + switch (addr&7) + { + case 1: return; + case 2: /*DOR*/ +// if (val == 0xD && (cs >> 4) == 0xFC81600 && ins > 769619936) output = 3; +// printf("DOR was %02X\n",fdc.dor); + if (fdc.pcjr) + { + if ((fdc.dor & 0x40) && !(val & 0x40)) + { + fdc.watchdog_timer = 1000 * TIMER_USEC; + fdc.watchdog_count = 1000; + picintc(1 << 6); +// pclog("watchdog set %i %i\n", fdc.watchdog_timer, TIMER_USEC); + } + if ((val & 0x80) && !(fdc.dor & 0x80)) + { + timer_process(); + disctime = 128 * (1 << TIMER_SHIFT); + timer_update_outstanding(); + discint=-1; + fdc_reset(); + } + motor_on[0] = val & 0x01; + fdc.drive = 0; +/* if (motor_on[0]) + output = 3; + else + output = 0;*/ + } + else + { + if (val&4) + { + fdc.stat=0x80; + fdc.pnum=fdc.ptot=0; + } + if ((val&4) && !(fdc.dor&4)) + { + timer_process(); + disctime = 128 * (1 << TIMER_SHIFT); + timer_update_outstanding(); + discint=-1; + fdc_reset(); + } + timer_process(); + fdc.drive = val & 3; + val &= 0x3F; + /* if (fdc.drive > 2) + { + motor_on = 0; + } */ + if (fdc.drive == 1) + { + if ((!fdc.drv2en) || (fdd_get_type(1) == 0)) + { + motor_on[1] = 0; + val &= 0xDF; + } + else + { + motor_on[1] = val & 0x20; + } + } + else if (fdc.drive == 0) + { + if (fdd_get_type(0) == 0) + { + motor_on[0] = 0; + val &= 0xEF; + } + else + { + motor_on[0] = val & 0x10; + } + } + fdc_set_skip_pulses(fdc.drive, 0); + timer_update_outstanding(); + } + fdc.dor=val; +// printf("DOR now %02X\n",val); + return; + case 3: + /* TDR */ + if (fdc.enh_mode) + { + drive = (fdc.dor & 1) ^ fdd_swap; + fdc.rwc[drive] = (val & 0x30) >> 4; + } + return; + case 4: + if (val & 0x80) + { + timer_process(); + disctime = 128 * (1 << TIMER_SHIFT); + timer_update_outstanding(); + discint=-1; + fdc_reset(); + } + return; + case 5: /*Command register*/ + if ((fdc.stat & 0xf0) == 0xb0) + { + if (fdc.pcjr || !fdc.fifo) + { + fdc.dat = val; + fdc.stat &= ~0x80; + } + else + { + fdc_fifo_buf_write(val); + if (fdc.fifobufpos == 0) fdc.stat &= ~0x80; + } + break; + } +// if (fdc.inread) +// rpclog("c82c711_fdc_write : writing while inread! %02X\n", val); +// rpclog("Write command reg %i %i\n",fdc.pnum, fdc.ptot); + if (fdc.pnum==fdc.ptot) + { + fdc.tc = 0; + fdc.data_ready = 0; + + fdc.command=val; +// pclog("Starting FDC command %02X\n",fdc.command); + switch (fdc.command&0x1F) + { + case 1: /*Mode*/ + if (!fdc.is_nsc) goto bad_command; + fdc.pnum=0; + fdc.ptot=4; + fdc.stat=0x90; + fdc.pos=0; + fdc.format_state = 0; + break; + + case 2: /*Read track*/ + fdc.pnum=0; + fdc.ptot=8; + fdc.stat=0x90; + fdc.pos=0; + break; + case 3: /*Specify*/ + fdc.pnum=0; + fdc.ptot=2; + fdc.stat=0x90; + break; + case 4: /*Sense drive status*/ + fdc.pnum=0; + fdc.ptot=1; + fdc.stat=0x90; + break; + case 5: /*Write data*/ +// printf("Write data!\n"); + fdc.pnum=0; + fdc.ptot=8; + fdc.stat=0x90; + fdc.pos=0; +// readflash=1; + break; + case 6: /*Read data*/ + fdc.pnum=0; + fdc.ptot=8; + fdc.stat=0x90; + fdc.pos=0; + break; + case 7: /*Recalibrate*/ + fdc.pnum=0; + fdc.ptot=1; + fdc.stat=0x90; + break; + case 8: /*Sense interrupt status*/ +// printf("Sense interrupt status %i\n",curdrive); + fdc.lastdrive = fdc.drive; +// fdc.stat = 0x10 | (fdc.stat & 0xf); +// fdc_time=1024; + discint = 8; + fdc.pos = 0; + fdc_callback(); + break; + case 10: /*Read sector ID*/ + fdc.pnum=0; + fdc.ptot=1; + fdc.stat=0x90; + fdc.pos=0; + break; + case 0x0d: /*Format track*/ + fdc.pnum=0; + fdc.ptot=5; + fdc.stat=0x90; + fdc.pos=0; + fdc.format_state = 0; + break; + case 15: /*Seek*/ + fdc.pnum=0; + fdc.ptot=2; + fdc.stat=0x90; + fdc.seek_params = val & 0xC0; + break; + case 0x0e: /*Dump registers*/ + fdc.lastdrive = fdc.drive; + discint = 0x0e; + fdc.pos = 0; + fdc_callback(); + break; + case 0x10: /*Get version*/ + fdc.lastdrive = fdc.drive; + discint = 0x10; + fdc.pos = 0; + fdc_callback(); + break; + case 0x12: /*Set perpendicular mode*/ + fdc.pnum=0; + fdc.ptot=1; + fdc.stat=0x90; + fdc.pos=0; + break; + case 0x13: /*Configure*/ + fdc.pnum=0; + fdc.ptot=3; + fdc.stat=0x90; + fdc.pos=0; + break; + case 0x14: /*Unlock*/ + case 0x94: /*Lock*/ + fdc.lastdrive = fdc.drive; + discint = fdc.command; + fdc.pos = 0; + fdc_callback(); + break; + + case 0x18: + if (!fdc.is_nsc) goto bad_command; + fdc.lastdrive = fdc.drive; + discint = 0x10; + fdc.pos = 0; + fdc_callback(); + /* fdc.stat = 0x10; + discint = 0xfc; + fdc_callback(); */ + break; + + default: +bad_command: + // fatal("Bad FDC command %02X\n",val); +// dumpregs(); +// exit(-1); + fdc.stat=0x10; + discint=0xfc; + timer_process(); + disctime = 200 * (1 << TIMER_SHIFT); + timer_update_outstanding(); + break; + } + } + else + { + fdc.params[fdc.pnum++]=val; + if (fdc.pnum==fdc.ptot) + { +// pclog("Got all params %02X\n", fdc.command); + fdc.stat=0x30; + discint=fdc.command&0x1F; + timer_process(); + disctime = 1024 * (1 << TIMER_SHIFT); + timer_update_outstanding(); +// fdc.drive = fdc.params[0] & 3; + disc_drivesel = fdc.drive & 1; + fdc_reset_stat = 0; + disc_set_drivesel(fdc.drive & 1); + switch (discint) + { + case 2: /*Read a track*/ + fdc_set_skip_pulses(fdc.drive ^ fdd_swap, 1); + fdc_rate(fdc.drive); + fdc.head=fdc.params[2]; + fdd_set_head(fdc.drive, (fdc.params[0] & 4) ? 1 : 0); + fdc.sector=fdc.params[3]; + fdc.eot[fdc.drive] = fdc.params[5]; + if (((fdc.drive ^ fdd_swap) == 1) && !fdc.drv2en) + fdc_notfound(); + if (fdc.config & 0x40) + { + if (fdc.params[1] != fdc.track[fdc.drive]) + { + fdc_seek(fdc.drive, fdc.params[1] - fdc.track[fdc.drive]); + fdc.track[fdc.drive] = fdc.params[1]; + } + } + // fdc.track[fdc.drive]=fdc.params[1]; + fdc.rw_track = fdc.params[1]; +// pclog("Read a track track=%i head=%i sector=%i eot=%i\n", fdc.track[fdc.drive], fdc.head, fdc.sector, fdc.eot[fdc.drive]); + fdc_set_skip_pulses(fdc.drive ^ fdd_swap, 0); + + if (fdc_state != FDC_STATE_SEEK) + disc_readsector(fdc.drive, SECTOR_FIRST, fdc.params[1], fdc.head, fdc.rate, fdc.params[4]); + + disctime = (fdc_state == FDC_STATE_SEEK) ? (790 * TIMER_USEC) : 0; + readflash = 1; + fdc.inread = 1; + break; + + case 3: /*Specify*/ + fdc.stat=0x80; + fdc.specify[0] = fdc.params[0]; + fdc.specify[1] = fdc.params[1]; + fdc.dma = (fdc.specify[1] & 1) ^ 1; + disctime = 0; + break; + + case 5: /*Write data*/ + fdc_set_skip_pulses(fdc.drive ^ fdd_swap, 1); + fdc_rate(fdc.drive); + fdc.head=fdc.params[2]; + fdd_set_head(fdc.drive, (fdc.params[0] & 4) ? 1 : 0); + fdc.sector=fdc.params[3]; + fdc.eot[fdc.drive] = fdc.params[5]; + if (((fdc.drive ^ fdd_swap) == 1) && !fdc.drv2en) + fdc_notfound(); + if (fdc.config & 0x40) + { + if (fdc.params[1] != fdc.track[fdc.drive]) + { + fdc_seek(fdc.drive, fdc.params[1] - fdc.track[fdc.drive]); + fdc.track[fdc.drive] = fdc.params[1]; + } + } + // fdc.track[fdc.drive]=fdc.params[1]; + fdc.rw_track = fdc.params[1]; + + fdc_set_skip_pulses(fdc.drive ^ fdd_swap, 0); + + if (fdc_state != FDC_STATE_SEEK) + disc_writesector(fdc.drive, fdc.sector, fdc.params[1], fdc.head, fdc.rate, fdc.params[4]); + + disctime = (fdc_state == FDC_STATE_SEEK) ? (790 * TIMER_USEC) : 0; + fdc.written = 0; + readflash = 1; + fdc.pos = 0; + if (fdc_state != FDC_STATE_SEEK) + { + if (fdc.pcjr) + fdc.stat = 0xb0; + } + break; + + case 6: /*Read data*/ + fdc_set_skip_pulses(fdc.drive ^ fdd_swap, 1); + fdc_rate(fdc.drive); + fdc.head=fdc.params[2]; + fdd_set_head(fdc.drive, (fdc.params[0] & 4) ? 1 : 0); + fdc.sector=fdc.params[3]; + fdc.eot[fdc.drive] = fdc.params[5]; + // pclog("FDC track is %i, requested track is %i\n", fdc.track[fdc.drive], fdc.params[1]); + if (((fdc.drive ^ fdd_swap) == 1) && !fdc.drv2en) + fdc_notfound(); + + if (fdc.config & 0x40) + { + if (fdc.params[1] != fdc.track[fdc.drive]) + { + fdc_seek(fdc.drive, fdc.params[1] - fdc.track[fdc.drive]); + fdc.track[fdc.drive] = fdc.params[1]; + } + } + // fdc.track[fdc.drive]=fdc.params[1]; + fdc.rw_track = fdc.params[1]; + + fdc_set_skip_pulses(fdc.drive ^ fdd_swap, 0); + + if (fdc_state != FDC_STATE_SEEK) + disc_readsector(fdc.drive, fdc.sector, fdc.params[1], fdc.head, fdc.rate, fdc.params[4]); + + disctime = (fdc_state == FDC_STATE_SEEK) ? (790 * TIMER_USEC) : 0; + readflash = 1; + fdc.inread = 1; + break; + + case 7: /*Recalibrate*/ + fdc.stat = 1 << fdc.drive; + disctime = 0; + if (((fdc.drive ^ fdd_swap) == 1) && !fdc.drv2en) + fdc_notfound(); + else + { + // fdc_seek(fdc.drive, SEEK_RECALIBRATE); + fdc_seek(fdc.drive, -79); + } + disctime = 790 * TIMER_USEC; + break; + + case 0x0d: /*Format*/ + fdc_set_skip_pulses(fdc.drive ^ fdd_swap, 1); + fdc_rate(fdc.drive); + fdc.head = (fdc.params[0] & 4) ? 1 : 0; + fdc.format_state = 1; + fdc.pos = 0; + fdc.stat = 0x30; + fdc_set_skip_pulses(fdc.drive ^ fdd_swap, 0); + break; + + case 0xf: /*Seek*/ + fdc.stat = 1 << fdc.drive; + fdc.head = (fdc.params[0] & 4) ? 1 : 0; + disctime = 0; + if (((fdc.drive ^ fdd_swap) == 1) && !fdc.drv2en) + fdc_notfound(); + else + { + // pclog("Seeking (params=%02X, params[1]=%i)...\n", fdc.seek_params, fdc.params[1]); + if (fdc.seek_params & 0x80) + { + if (fdc.seek_params & 0x40) + { + /* Relative seek inwards. */ + fdc_seek(fdc.drive, fdc.params[1]); + } + else + { + /* Relative seek outwards. */ + fdc_seek(fdc.drive, -fdc.params[1]); + } + } + else + { + fdc_seek(fdc.drive, fdc.params[1] - fdc.track[fdc.drive]); + } + } + disctime = 790 * TIMER_USEC; +// pclog("Seek to %i\n", fdc.params[1]); + break; + + case 10: /*Read sector ID*/ + fdc_set_skip_pulses(fdc.drive ^ fdd_swap, 1); + fdc_rate(fdc.drive); + disctime = 0; + fdc.head = (fdc.params[0] & 4) ? 1 : 0; + fdd_set_head(fdc.drive, (fdc.params[0] & 4) ? 1 : 0); +// pclog("Read sector ID %i %i\n", fdc.rate, fdc.drive); + fdc_set_skip_pulses(fdc.drive ^ fdd_swap, 0); + if (((fdc.drive ^ fdd_swap) != 1) || fdc.drv2en) + disc_readaddress(fdc.drive, fdc.track[fdc.drive], fdc.head, fdc.rate); + else + fdc_notfound(); + break; + } + } + } + return; + case 7: + // if (!AT) return; + fdc.rate=val&3; + // pclog("Rate is now: %i\n", fdc.rate); + + disc_3f7=val; + return; + } +// printf("Write FDC %04X %02X\n",addr,val); +// dumpregs(); +// exit(-1); +} + +int paramstogo=0; +uint8_t fdc_read(uint16_t addr, void *priv) +{ + uint8_t temp; + int drive; +// /*if (addr!=0x3f4) */printf("Read FDC %04X %04X:%04X %04X %i %02X %02x %i ",addr,cs>>4,pc,BX,fdc.pos,fdc.st0,fdc.stat,ins); + switch (addr&7) + { + case 1: /*???*/ + drive = (fdc.dor & 1) ^ fdd_swap; + if (!fdc.enable_3f1) + return 0xff; +// temp=0x50; + temp = 0x70; + if (drive) + temp &= ~0x40; + else + temp &= ~0x20; + break; + case 3: + drive = (fdc.dor & 1) ^ fdd_swap; + if (fdc.ps1) + { + /*PS/1 Model 2121 seems return drive type in port 0x3f3, + despite the 82077AA FDC not implementing this. This is + presumably implemented outside the FDC on one of the + motherboard's support chips.*/ + /* NOTE by OBattler: This has to be implemented for + super I/O chips too. */ + if (fdd_is_525(drive)) + temp = 0x20; + else if (fdd_is_ed(drive)) + temp = 0x10; + else + temp = 0x00; + } + else if (!fdc.enh_mode) + temp = 0x20; + else + { + temp = fdc.rwc[drive] << 4; + } + break; + case 4: /*Status*/ + temp=fdc.stat; + break; + case 5: /*Data*/ + if ((fdc.stat & 0xf0) == 0xf0) + { + fdc.stat&=~0x80; + if (fdc.pcjr || !fdc.fifo) + temp = fdc.dat; + else + { + temp = fdc_fifo_buf_read(); + } + break; + } + fdc.stat&=~0x80; + if (paramstogo) + { + paramstogo--; + temp=fdc.res[10 - paramstogo]; +// pclog("Read param %i %02X\n",10-paramstogo,temp); + if (!paramstogo) + { + fdc.stat=0x80; +// fdc.st0=0; + } + else + { + fdc.stat|=0xC0; +// fdc_poll(); + } + } + else + { + if (lastbyte) + fdc.stat = 0x80; + lastbyte=0; + temp=fdc.dat; + fdc.data_ready = 0; + } + if (discint==0xA) + { + timer_process(); + disctime = 1024 * (1 << TIMER_SHIFT); + timer_update_outstanding(); + } + fdc.stat &= 0xf0; + break; + case 7: /*Disk change*/ + drive = (fdc.dor & 1) ^ fdd_swap; + if (fdc.dor & (0x10 << drive)) + temp = (disc_changed[drive] || drive_empty[drive])?0x80:0; + else + temp = 0; + if (fdc.dskchg_activelow) /*PC2086/3086 seem to reverse this bit*/ + temp ^= 0x80; +// printf("- DC %i %02X %02X %i %i - ",fdc.dor & 1, fdc.dor, 0x10 << (fdc.dor & 1), discchanged[fdc.dor & 1], driveempty[fdc.dor & 1]); +// discchanged[fdc.dor&1]=0; + break; + default: + temp=0xFF; +// printf("Bad read FDC %04X\n",addr); +// dumpregs(); +// exit(-1); + } +// /*if (addr!=0x3f4) */printf("%02X rate=%i %i\n",temp,fdc.rate, fdc.data_ready); + // pclog("fdc_read: %04X: %02X\n", addr, temp); + return temp; +} + +void fdc_callback() +{ + int temp; + disctime = 0; +// pclog("fdc_callback %i %i\n", discint, disctime); +// if (fdc.inread) +// rpclog("c82c711_fdc_callback : while inread! %08X %i %02X %i\n", discint, fdc.drive, fdc.st0, ins); + if (fdc_state == FDC_STATE_SEEK) + { + if (!fdd_stepping_motor_on[fdc.drive ^ fdd_swap]) + { + pclog("FDC has stopped seeking\n"); + fdc_state = FDC_STATE_NORMAL; + + fdc.stat &= ~(1 << fdc.drive); + + switch (discint) + { + case 2: + disc_readsector(fdc.drive, SECTOR_FIRST, fdc.params[1], fdc.head, fdc.rate, fdc.params[4]); + disctime = 0; + readflash = 1; + fdc.inread = 1; + return; + case 5: + disc_writesector(fdc.drive, fdc.sector, fdc.params[1], fdc.head, fdc.rate, fdc.params[4]); + disctime = 0; + fdc.written = 0; + readflash = 1; + fdc.pos = 0; + if (fdc.pcjr) + fdc.stat = 0xb0; + return; + case 6: + disc_readsector(fdc.drive, fdc.sector, fdc.params[1], fdc.head, fdc.rate, fdc.params[4]); + disctime = 0; + readflash = 1; + fdc.inread = 1; + return; + case 7: + case 0xf: + break; + default: + return; + } + } + else + { + pclog("FDC is seeking\n"); + return; + } + } + else + { + if (fdd_stepping_motor_on[fdc.drive ^ fdd_swap]) + pclog("FDD is seeking but FDC not\n"); + else + pclog("Neither the FDD nor the FDC is seeking\n"); + } + + switch (discint) + { + case -3: /*End of command with interrupt*/ +// if (output) printf("EOC - interrupt!\n"); +//rpclog("EOC\n"); + fdc_int(); + case -2: /*End of command*/ + fdc.stat = (fdc.stat & 0xf) | 0x80; + return; + case -1: /*Reset*/ +//rpclog("Reset\n"); + fdc_int(); + fdc_reset_stat = 4; + return; + case 1: /*Mode*/ + fdc.stat=0x80; + fdc.densel_force = (fdc.params[2] & 0xC0) >> 6; + return; + + case 2: /*Read track*/ + readflash = 1; + fdc.eot[fdc.drive]--; +// pclog("Read a track callback, eot=%i\n", fdc.eot[fdc.drive]); + if (!fdc.eot[fdc.drive] || fdc.tc) + { +// pclog("Complete\n"); + fdc.inread = 0; + discint=-2; + fdc_int(); + fdc_set_skip_pulses(fdc.drive, 0); + fdc.stat=0xD0; + fdc.res[4]=(fdc.head?4:0)|fdc.drive; + fdc.res[5]=fdc.res[6]=0; + fdc.res[7]=fdc.rw_track; + fdc.res[8]=fdc.head; + fdc.res[9]=fdc.sector; + fdc.res[10]=fdc.params[4]; + paramstogo=7; + return; + } + else + { + if (((fdc.drive ^ fdd_swap) == 1) && !fdc.drv2en) + not_found[fdc.drive ^ fdd_swap] = 1000; +#if 0 + disc_notfound = 1000; +#endif + else + disc_readsector(fdc.drive, SECTOR_NEXT, fdc.rw_track, fdc.head, fdc.rate, fdc.params[4]); + } + fdc.inread = 1; + return; + case 4: /*Sense drive status*/ + fdc.res[10] = (fdc.params[0] & 7) | 0x28; + if (((fdc.drive ^ fdd_swap) != 1) || fdc.drv2en) + { + if (fdd_track0(fdc.drive ^ fdd_swap)) + fdc.res[10] |= 0x10; + } + if (writeprot[fdc.drive]) + fdc.res[10] |= 0x40; + + fdc.stat = (fdc.stat & 0xf) | 0xd0; + paramstogo = 1; + discint = 0; + disctime = 0; + return; + case 5: /*Write data*/ + readflash = 1; + fdc.sector++; + if (fdc.sector > fdc.params[5]) + { + fdc.sector = 1; + if (fdc.command & 0x80) + { + fdc.head ^= 1; + if (!fdc.head) + { + fdc.rw_track++; +// fdc.track[fdc.drive]++; +/* if (fdc.track[fdc.drive] >= 79) + { + fdc.track[fdc.drive] = 79; + fdc.tc = 1; + }*/ + } + } + else + { + fdc.rw_track++; +// fdc.track[fdc.drive]++; + fdc.tc = 1; + } + } + if (fdc.tc) + { + discint=-2; + fdc_int(); + fdc_set_skip_pulses(fdc.drive, 0); + fdc.stat=0xD0; + fdc.res[4]=(fdc.head?4:0)|fdc.drive; + fdc.res[5]=fdc.res[6]=0; + fdc.res[7]=fdc.rw_track; + fdc.res[8]=fdc.head; + fdc.res[9]=fdc.sector; + fdc.res[10]=fdc.params[4]; + paramstogo=7; + return; + } + if (((fdc.drive ^ fdd_swap) == 1) && !fdc.drv2en) + not_found[fdc.drive ^ fdd_swap] = 1000; +#if 0 + disc_notfound = 1000; +#endif + else + disc_writesector(fdc.drive, fdc.sector, fdc.rw_track, fdc.head, fdc.rate, fdc.params[4]); +// ioc_fiq(IOC_FIQ_DISC_DATA); + return; + case 6: /*Read data*/ +// rpclog("Read data %i\n", fdc.tc); + readflash = 1; + fdc_set_skip_pulses(fdc.drive, 1); + fdc.sector++; + if (fdc.sector > fdc.params[5]) + { + fdc.sector = 1; + if (fdc.command & 0x80) + { + fdc.head ^= 1; + if (!fdc.head) + { + fdc.rw_track++; +// fdc.track[fdc.drive]++; +/* if (fdc.track[fdc.drive] >= 79) + { + fdc.track[fdc.drive] = 79; + fdc.tc = 1; + }*/ + } + } + else + { + fdc.rw_track++; +// fdc.track[fdc.drive]++; + fdc.tc = 1; + } + } + if (fdc.tc) + { + fdc.inread = 0; + discint=-2; + fdc_int(); + fdc_set_skip_pulses(fdc.drive, 0); + fdc.stat=0xD0; + fdc.res[4]=(fdc.head?4:0)|fdc.drive; + fdc.res[5]=fdc.res[6]=0; + fdc.res[7]=fdc.rw_track; + fdc.res[8]=fdc.head; + fdc.res[9]=fdc.sector; + fdc.res[10]=fdc.params[4]; + paramstogo=7; + return; + } + fdc_set_skip_pulses(fdc.drive, 0); + if (((fdc.drive ^ fdd_swap) == 1) && !fdc.drv2en) + not_found[fdc.drive ^ fdd_swap] = 1000; +#if 0 + disc_notfound = 1000; +#endif + else + disc_readsector(fdc.drive, fdc.sector, fdc.rw_track, fdc.head, fdc.rate, fdc.params[4]); + fdc.inread = 1; + return; + + case 7: /*Recalibrate*/ + fdc.track[fdc.drive]=0; +// if (!driveempty[fdc.dor & 1]) discchanged[fdc.dor & 1] = 0; + if (fdc.drive <= 1) + fdc.st0 = 0x20 | (fdc.params[0] & 3) | (fdc.head?4:0); + else + fdc.st0 = 0x68 | (fdc.params[0] & 3) | (fdc.head?4:0); + discint=-3; + timer_process(); + disctime = 2048 * (1 << TIMER_SHIFT); + timer_update_outstanding(); +// printf("Recalibrate complete!\n"); + fdc.stat = 0x80 | (1 << fdc.drive); + return; + + case 8: /*Sense interrupt status*/ +// pclog("Sense interrupt status %i\n", fdc_reset_stat); + + fdc.stat = (fdc.stat & 0xf) | 0xd0; + if (fdc_reset_stat) + fdc.res[9] = 0xc0 | (4 - fdc_reset_stat) | (fdc.head ? 4 : 0); + else + fdc.res[9] = fdc.st0; + fdc.res[10] = fdc.track[fdc.drive]; + if (!fdc_reset_stat) + fdc.st0 = 0x80; + else + fdc_reset_stat--; + + paramstogo = 2; + discint = 0; + disctime = 0; + return; + + case 0x0d: /*Format track*/ +// rpclog("Format\n"); + if (fdc.format_state == 1) + { +// ioc_fiq(IOC_FIQ_DISC_DATA); + fdc.format_state = 2; + timer_process(); + disctime = 128 * (1 << TIMER_SHIFT); + timer_update_outstanding(); + } + else if (fdc.format_state == 2) + { + temp = fdc_getdata(fdc.pos == ((fdc.params[2] * 4) - 1)); + if (temp == -1) + { + timer_process(); + disctime = 128 * (1 << TIMER_SHIFT); + timer_update_outstanding(); + return; + } + fdc.format_dat[fdc.pos++] = temp; + if (fdc.pos == (fdc.params[2] * 4)) + fdc.format_state = 3; + timer_process(); + disctime = 128 * (1 << TIMER_SHIFT); + timer_update_outstanding(); + } + else if (fdc.format_state == 3) + { +// pclog("Format next stage track %i head %i\n", fdc.track[fdc.drive], fdc.head); + if (((fdc.drive ^ fdd_swap) == 1) && !fdc.drv2en) + not_found[fdc.drive ^ fdd_swap] = 1000; +#if 0 + disc_notfound = 1000; +#endif + else + disc_format(fdc.drive, disc_realtrack(fdc.drive, fdc.track[fdc.drive]), fdc.head, fdc.rate, fdc.params[4]); + fdc.format_state = 4; + } + else + { + discint=-2; + fdc_int(); + fdc_set_skip_pulses(fdc.drive, 0); + fdc.stat=0xD0; + fdc.res[4] = (fdc.head?4:0)|fdc.drive; + fdc.res[5] = fdc.res[6] = 0; + fdc.res[7] = fdc.track[fdc.drive]; + fdc.res[8] = fdc.head; + fdc.res[9] = fdc.format_dat[fdc.pos - 2] + 1; + fdc.res[10] = fdc.params[4]; + paramstogo=7; + fdc.format_state = 0; + return; + } + return; + + case 15: /*Seek*/ + fdc.track[fdc.drive]=fdc.params[1]; +// if (!driveempty[fdc.dor & 1]) discchanged[fdc.dor & 1] = 0; +// printf("Seeked to track %i %i\n",fdc.track[fdc.drive], fdc.drive); + if (fdc.drive <= 1) + fdc.st0 = 0x20 | (fdc.params[0] & 3) | (fdc.head?4:0); + else + fdc.st0 = 0x68 | (fdc.params[0] & 3) | (fdc.head?4:0); + discint=-3; + timer_process(); + disctime = 2048 * (1 << TIMER_SHIFT); + timer_update_outstanding(); + fdc.stat = 0x80 | (1 << fdc.drive); +// pclog("Stat %02X ST0 %02X\n", fdc.stat, fdc.st0); + return; + case 0x0e: /*Dump registers*/ + fdc.stat = (fdc.stat & 0xf) | 0xd0; + fdc.res[3] = fdc.track[0]; + fdc.res[4] = fdc.track[1]; + fdc.res[5] = 0; + fdc.res[6] = 0; + fdc.res[7] = fdc.specify[0]; + fdc.res[8] = fdc.specify[1]; + fdc.res[9] = fdc.eot[fdc.drive]; + fdc.res[10] = (fdc.perp & 0x7f) | ((fdc.lock) ? 0x80 : 0); + paramstogo=10; + discint=0; + disctime = 0; + return; + + case 0x10: /*Version*/ + fdc.stat = (fdc.stat & 0xf) | 0xd0; + fdc.res[10] = 0x90; + paramstogo=1; + discint=0; + disctime = 0; + return; + + case 0x12: + fdc.perp = fdc.params[0]; + fdc.stat = 0x80; + disctime = 0; +// picint(0x40); + return; + case 0x13: /*Configure*/ + fdc.config = fdc.params[1]; + fdc.pretrk = fdc.params[2]; + fdc.fifo = (fdc.params[1] & 0x20) ? 0 : 1; + fdc.tfifo = (fdc.params[1] & 0xF) + 1; + // pclog("FIFO is now %02X, threshold is %02X\n", fdc.fifo, fdc.tfifo); + fdc.stat = 0x80; + disctime = 0; +// picint(0x40); + return; + case 0x14: /*Unlock*/ + fdc.lock = 0; + fdc.stat = (fdc.stat & 0xf) | 0xd0; + fdc.res[10] = 0; + paramstogo=1; + discint=0; + disctime = 0; + return; + case 0x94: /*Lock*/ + fdc.lock = 1; + fdc.stat = (fdc.stat & 0xf) | 0xd0; + fdc.res[10] = 0x10; + paramstogo=1; + discint=0; + disctime = 0; + return; + + case 0x18: /*NSC*/ + fdc.stat = (fdc.stat & 0xf) | 0xd0; + fdc.res[10] = 0x73; + paramstogo=1; + discint=0; + disctime = 0; + return; + + case 0xfc: /*Invalid*/ + fdc.dat = fdc.st0 = 0x80; +// pclog("Inv!\n"); + //picint(0x40); + fdc.stat = (fdc.stat & 0xf) | 0xd0; +// fdc.stat|=0xC0; + fdc.res[10] = fdc.st0; + paramstogo=1; + discint=0; + disctime = 0; + return; + } +// printf("Bad FDC disc int %i\n",discint); +// dumpregs(); +// exit(-1); +} + +void fdc_overrun() +{ + disc_sector_stop(fdc.drive ^ fdd_swap); + disctime = 0; + + fdc_int(); + fdc.stat=0xD0; + fdc_set_skip_pulses(fdc.drive ^ fdd_swap, 0); + fdc.res[4]=0x40|(fdc.head?4:0)|fdc.drive; + fdc.res[5]=0x10; /*Overrun*/ + fdc.res[6]=0; + fdc.res[7]=0; + fdc.res[8]=0; + fdc.res[9]=0; + fdc.res[10]=0; + paramstogo=7; +} + +int fdc_data(uint8_t data) +{ + if (fdc.tc) + return 0; + + if (fdc.pcjr || !fdc.dma) + { + if (fdc.data_ready) + { + fdc_overrun(); +// pclog("Overrun\n"); + return -1; + } + + if (fdc.pcjr || !fdc.fifo) + { + fdc.dat = data; + fdc.data_ready = 1; + fdc.stat = 0xf0; + } + else + { + // FIFO enabled + fdc_fifo_buf_write(data); + if (fdc.fifobufpos == 0) + { + // We have wrapped around, means FIFO is over + fdc.data_ready = 1; + fdc.stat = 0xf0; + } + } + } + else + { + if (dma_channel_write(2, data) & DMA_OVER) + fdc.tc = 1; + + if (!fdc.fifo) + { + fdc.data_ready = 1; + fdc.stat = 0xd0; + } + else + { + fdc_fifo_buf_dummy(); + if (fdc.fifobufpos == 0) + { + // We have wrapped around, means FIFO is over + fdc.data_ready = 1; + fdc.stat = 0xd0; + } + } + } + + return 0; +} + +void fdc_finishread(int drive) +{ + pclog("Read finished\n"); + fdc_set_skip_pulses(drive, 1); + disctime = 200 * TIMER_USEC; +// rpclog("fdc_finishread\n"); +} + +void fdc_notfound() +{ + disctime = 0; + + fdc_int(); + fdc.stat=0xD0; + fdc_set_skip_pulses(fdc.drive ^ fdd_swap, 0); + fdc.res[4]=0x40|(fdc.head?4:0)|fdc.drive; + fdc.res[5]=5; + fdc.res[6]=0; + fdc.res[7]=0; + fdc.res[8]=0; + fdc.res[9]=0; + fdc.res[10]=0; + paramstogo=7; +// rpclog("c82c711_fdc_notfound\n"); +} + +void fdc_datacrcerror() +{ + disctime = 0; + + fdc_int(); + fdc.stat=0xD0; + fdc_set_skip_pulses(fdc.drive ^ fdd_swap, 0); + fdc.res[4]=0x40|(fdc.head?4:0)|fdc.drive; + fdc.res[5]=0x20; /*Data error*/ + fdc.res[6]=0x20; /*Data error in data field*/ + fdc.res[7]=0; + fdc.res[8]=0; + fdc.res[9]=0; + fdc.res[10]=0; + paramstogo=7; +// rpclog("c82c711_fdc_datacrcerror\n"); +} + +void fdc_headercrcerror() +{ + disctime = 0; + + fdc_int(); + fdc.stat=0xD0; + fdc_set_skip_pulses(fdc.drive ^ fdd_swap, 0); + fdc.res[4]=0x40|(fdc.head?4:0)|fdc.drive; + fdc.res[5]=0x20; /*Data error*/ + fdc.res[6]=0; + fdc.res[7]=0; + fdc.res[8]=0; + fdc.res[9]=0; + fdc.res[10]=0; + paramstogo=7; +// rpclog("c82c711_fdc_headercrcerror\n"); +} + +void fdc_writeprotect() +{ + disctime = 0; + + fdc_int(); + fdc.stat=0xD0; + fdc_set_skip_pulses(fdc.drive ^ fdd_swap, 0); + fdc.res[4]=0x40|(fdc.head?4:0)|fdc.drive; + fdc.res[5]=0x02; /*Not writeable*/ + fdc.res[6]=0; + fdc.res[7]=0; + fdc.res[8]=0; + fdc.res[9]=0; + fdc.res[10]=0; + paramstogo=7; +} + +int fdc_getdata(int last) +{ + int data; + + if (fdc.pcjr || !fdc.dma) + { + if (fdc.written) + { + fdc_overrun(); +// pclog("Overrun\n"); + return -1; + } + if (fdc.pcjr || !fdc.fifo) + { + data = fdc.dat; + + if (!last) + fdc.stat = 0xb0; + } + else + { + data = fdc_fifo_buf_read(); + + if (!last && (fdc.fifobufpos == 0)) + fdc.stat = 0xb0; + } + } + else + { + data = dma_channel_read(2); + + if (!fdc.fifo) + { + if (!last) + fdc.stat = 0x90; + } + else + { + fdc_fifo_buf_dummy(); + + if (!last && (fdc.fifobufpos == 0)) + fdc.stat = 0x90; + } + + if (data & DMA_OVER) + fdc.tc = 1; + } + + fdc.written = 0; + return data & 0xff; +} + +void fdc_sectorid(uint8_t track, uint8_t side, uint8_t sector, uint8_t size, uint8_t crc1, uint8_t crc2) +{ +// pclog("SectorID %i %i %i %i\n", track, side, sector, size); + fdc_int(); + fdc_set_skip_pulses(fdc.drive ^ fdd_swap, 0); + fdc.stat=0xD0; + fdc.res[4]=(fdc.head?4:0)|fdc.drive; + fdc.res[5]=0; + fdc.res[6]=0; + fdc.res[7]=track; + fdc.res[8]=side; + fdc.res[9]=sector; + fdc.res[10]=size; + paramstogo=7; +} + +void fdc_indexpulse() +{ +// ioc_irqa(IOC_IRQA_DISC_INDEX); +// rpclog("c82c711_fdc_indexpulse\n"); +} + +void fdc_init() +{ + timer_add(fdc_callback, &disctime, &disctime, NULL); + fdc.dskchg_activelow = 0; + fdc.enable_3f1 = 1; + + fdc_update_enh_mode(0); + fdc_update_densel_polarity(1); + fdc_update_rwc(0, 0); + fdc_update_rwc(1, 0); + fdc_update_densel_force(0); + fdc_update_drv2en(1); + + fdc_set_skip_pulses(0, 0); + fdc_set_skip_pulses(1, 0); + + fdd_init(); + + swwp = 0; + disable_write = 0; + + fdd_stepping_motor_on[0] = fdd_track_diff[0] = 0; + fdd_stepping_motor_on[1] = fdd_track_diff[1] = 0; + fdc_state = FDC_STATE_NORMAL; + + fdc.fifo = fdc.tfifo = 0; +} + +void fdc_add() +{ + io_sethandler(0x03f0, 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL, NULL); + io_sethandler(0x03f7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, NULL); + fdc.pcjr = 0; + fdc.ps1 = 0; +} + +void fdc_add_for_superio() +{ + io_sethandler(0x03f2, 0x0004, fdc_read, NULL, NULL, fdc_write, NULL, NULL, NULL); + io_sethandler(0x03f7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, NULL); + fdc.pcjr = 0; + fdc.ps1 = 0; +} + +void fdc_add_pcjr() +{ + io_sethandler(0x00f0, 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL, NULL); + timer_add(fdc_watchdog_poll, &fdc.watchdog_timer, &fdc.watchdog_timer, &fdc); + fdc.pcjr = 1; + fdc.ps1 = 0; +} + +void fdc_remove() +{ + io_removehandler(0x03f0, 0x0006, fdc_read, NULL, NULL, fdc_write, NULL, NULL, NULL); + io_removehandler(0x03f7, 0x0001, fdc_read, NULL, NULL, fdc_write, NULL, NULL, NULL); +} + +void fdc_set_ps1() +{ + fdc.ps1 = 1; +} + +void fdc_discchange_clear(int drive) +{ + if (drive < 2) + disc_changed[drive] = 0; +} + +void fdc_set_dskchg_activelow() +{ + fdc.dskchg_activelow = 1; +} + +void fdc_3f1_enable(int enable) +{ + fdc.enable_3f1 = enable; +} diff --git a/src/fdc.h b/src/fdc.h new file mode 100644 index 000000000..7650988c5 --- /dev/null +++ b/src/fdc.h @@ -0,0 +1,27 @@ +void fdc_init(); +void fdc_add(); +void fdc_add_for_superio(); +void fdc_add_pcjr(); +void fdc_add_tandy(); +void fdc_remove(); +void fdc_reset(); +void fdc_poll(); +void fdc_abort(); +void fdc_discchange_clear(int drive); +void fdc_set_dskchg_activelow(); +void fdc_3f1_enable(int enable); +void fdc_set_ps1(); +int fdc_get_bitcell_period(); + +/* A few functions to communicate between Super I/O chips and the FDC. */ +void fdc_update_is_nsc(int is_nsc); +void fdc_update_enh_mode(int enh_mode); +int fdc_get_rwc(int drive); +void fdc_update_rwc(int drive, int rwc); +int fdc_get_boot_drive(); +void fdc_update_boot_drive(int boot_drive); +void fdc_update_densel_polarity(int densel_polarity); +void fdc_update_densel_force(int densel_force); +void fdc_update_drvrate(int drive, int drvrate); +void fdc_update_drv2en(int drv2en); +int fdc_skip_pulses(int drive); diff --git a/src/fdc37c665.c b/src/fdc37c665.c new file mode 100644 index 000000000..8a3f80904 --- /dev/null +++ b/src/fdc37c665.c @@ -0,0 +1,165 @@ +#include "ibm.h" + +#include "fdc.h" +#include "fdd.h" +#include "io.h" +#include "lpt.h" +#include "serial.h" +#include "fdc37c665.h" + +static uint8_t fdc37c665_lock[2]; +static int fdc37c665_curreg; +static uint8_t fdc37c665_regs[16]; + +static void write_lock(uint8_t val) +{ + if (val == 0x55 && fdc37c665_lock[1] == 0x55) + fdc_3f1_enable(0); + if (fdc37c665_lock[0] == 0x55 && fdc37c665_lock[1] == 0x55 && val != 0x55) + fdc_3f1_enable(1); + + fdc37c665_lock[0] = fdc37c665_lock[1]; + fdc37c665_lock[1] = val; +} + +void fdc37c665_write(uint16_t port, uint8_t val, void *priv) +{ +// pclog("Write SuperIO %04x %02x\n", port, val); + if (fdc37c665_lock[0] == 0x55 && fdc37c665_lock[1] == 0x55) + { + if (port == 0x3f0) + { + if (val == 0xaa) + write_lock(val); + else + fdc37c665_curreg = val & 0xf; + } + else + { + uint16_t com3_addr, com4_addr; + fdc37c665_regs[fdc37c665_curreg] = val; +// pclog("Write superIO %02x %02x %04x(%08x):%08x\n", fdc37c665_curreg, val, CS, cs, pc); + + switch (fdc37c665_regs[1] & 0x60) + { + case 0x00: + com3_addr = 0x338; + com4_addr = 0x238; + break; + case 0x20: + com3_addr = 0x3e8; + com4_addr = 0x2e8; + break; + case 0x40: + com3_addr = 0x3e8; + com4_addr = 0x2e0; + break; + case 0x60: + com3_addr = 0x220; + com4_addr = 0x228; + break; + } + + if (!(fdc37c665_regs[2] & 4)) + serial1_remove(); + else switch (fdc37c665_regs[2] & 3) + { + case 0: + serial1_set(0x3f8, 4); + break; + case 1: + serial1_set(0x2f8, 4); + break; + case 2: + serial1_set(com3_addr, 4); + break; + case 3: + serial1_set(com4_addr, 4); + break; + } + + if (!(fdc37c665_regs[2] & 0x40)) + serial2_remove(); + else switch (fdc37c665_regs[2] & 0x30) + { + case 0x00: + serial2_set(0x3f8, 3); + break; + case 0x10: + serial2_set(0x2f8, 3); + break; + case 0x20: + serial2_set(com3_addr, 3); + break; + case 0x30: + serial2_set(com4_addr, 3); + break; + } + + lpt1_remove(); + lpt2_remove(); + switch (fdc37c665_regs[1] & 3) + { + case 1: + lpt1_init(0x3bc); + break; + case 2: + lpt1_init(0x378); + break; + case 3: + lpt1_init(0x278); + break; + } + + fdc_update_enh_mode((fdc37c665_regs[3] & 2) ? 1 : 0); + + fdc_update_densel_force((fdc37c665_regs[5] & 0x18) >> 3); + fdd_swap = ((fdc37c665_regs[5] & 0x20) >> 5); + } + } + else + { + if (port == 0x3f0) + write_lock(val); + } +} + +uint8_t fdc37c665_read(uint16_t port, void *priv) +{ +// pclog("Read SuperIO %04x %02x\n", port, fdc37c665_curreg); + if (fdc37c665_lock[0] == 0x55 && fdc37c665_lock[1] == 0x55) + { + if (port == 0x3f1) + return fdc37c665_regs[fdc37c665_curreg]; + } + return 0xff; +} + +void fdc37c665_init() +{ + io_sethandler(0x03f0, 0x0002, fdc37c665_read, NULL, NULL, fdc37c665_write, NULL, NULL, NULL); + + fdc_update_is_nsc(0); + + fdc37c665_lock[0] = fdc37c665_lock[1] = 0; + fdc37c665_regs[0x0] = 0x3b; + fdc37c665_regs[0x1] = 0x9f; + fdc37c665_regs[0x2] = 0xdc; + fdc37c665_regs[0x3] = 0x78; + fdc37c665_regs[0x4] = 0x00; + fdc37c665_regs[0x5] = 0x00; + fdc37c665_regs[0x6] = 0xff; + fdc37c665_regs[0x7] = 0x00; + fdc37c665_regs[0x8] = 0x00; + fdc37c665_regs[0x9] = 0x00; + fdc37c665_regs[0xa] = 0x00; + fdc37c665_regs[0xb] = 0x00; + fdc37c665_regs[0xc] = 0x00; + fdc37c665_regs[0xd] = 0x65; + fdc37c665_regs[0xe] = 0x01; + fdc37c665_regs[0xf] = 0x00; + + fdc_update_densel_polarity(1); + fdc_update_densel_force(0); + fdd_swap = 0; +} diff --git a/src/fdc37c665.h b/src/fdc37c665.h new file mode 100644 index 000000000..1576c01c1 --- /dev/null +++ b/src/fdc37c665.h @@ -0,0 +1 @@ +extern void fdc37c665_init(); diff --git a/src/fdc37c932fr.c b/src/fdc37c932fr.c new file mode 100644 index 000000000..08b45ab91 --- /dev/null +++ b/src/fdc37c932fr.c @@ -0,0 +1,478 @@ +/* + SMSC SMC fdc37c932fr Super I/O Chip + Used by all some Acer boards, and by the Epox P55-VA +*/ + +#include "ibm.h" + +#include "fdc.h" +#include "fdd.h" +#include "ide.h" +#include "io.h" +#include "lpt.h" +#include "mouse_serial.h" +#include "serial.h" +#include "fdc37c932fr.h" + +static int fdc37c932fr_locked; +static int fdc37c932fr_curreg = 0; +static int fdc37c932fr_gpio_curreg = 0; +static uint8_t fdc37c932fr_regs[48]; +static uint8_t fdc37c932fr_ld_regs[10][256]; +static uint8_t fdc37c932fr_gpio_regs[16] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; + +static uint8_t tries; + +static uint16_t ld0_valid_ports[2] = {0x3F0, 0x370}; +static uint16_t ld1_valid_ports[2] = {0x1F0, 0x170}; +static uint16_t ld1_valid_ports2[2] = {0x3F6, 0x376}; +static uint16_t ld2_valid_ports[2] = {0x170, 0x1F0}; +static uint16_t ld2_valid_ports2[2] = {0x376, 0x3F6}; +static uint16_t ld3_valid_ports[3] = {0x3BC, 0x378, 0x278}; +static uint16_t ld4_valid_ports[9] = {0x3F8, 0x2F8, 0x338, 0x3E8, 0x2E8, 0x220, 0x238, 0x2E0, 0x228}; +static uint16_t ld5_valid_ports[9] = {0x3F8, 0x2F8, 0x338, 0x3E8, 0x2E8, 0x220, 0x238, 0x2E0, 0x228}; +static uint16_t ld5_valid_ports2[9] = {0x3F8, 0x2F8, 0x338, 0x3E8, 0x2E8, 0x220, 0x238, 0x2E0, 0x228}; + +static uint8_t is_in_array(uint16_t *port_array, uint8_t max, uint16_t port) +{ + uint8_t i = 0; + + for (i = 0; i < max; i++) + { + if (port_array[i] == port) return 1; + } + return 0; +} + +static uint16_t make_port(uint8_t ld) +{ + uint16_t r0 = fdc37c932fr_ld_regs[ld][0x60]; + uint16_t r1 = fdc37c932fr_ld_regs[ld][0x61]; + + uint16_t p = (r0 << 8) + r1; + + switch(ld) + { + case 0: + p &= 0xFF8; + if ((p < 0x100) || (p > 0xFF8)) p = 0x3F0; + if (!(is_in_array(ld0_valid_ports, 2, p))) p = 0x3F0; + break; + case 1: + p &= 0xFF8; + if ((p < 0x100) || (p > 0xFF8)) p = 0x1F0; + if (!(is_in_array(ld1_valid_ports, 2, p))) p = 0x1F0; + break; + case 2: + p &= 0xFF8; + if ((p < 0x100) || (p > 0xFF8)) p = 0x170; + if (!(is_in_array(ld2_valid_ports, 2, p))) p = 0x170; + break; + case 3: + p &= 0xFF8; + if ((p < 0x100) || (p > 0xFF8)) p = 0x378; + if (!(is_in_array(ld3_valid_ports, 3, p))) p = 0x378; + break; + case 4: + p &= 0xFF8; + if ((p < 0x100) || (p > 0xFF8)) p = 0x3F8; + if (!(is_in_array(ld4_valid_ports, 9, p))) p = 0x3F8; + break; + case 5: + p &= 0xFF8; + if ((p < 0x100) || (p > 0xFF8)) p = 0x2F8; + if (!(is_in_array(ld5_valid_ports, 9, p))) p = 0x2F8; + break; + } + + fdc37c932fr_ld_regs[ld][0x60] = (p >> 8); + fdc37c932fr_ld_regs[ld][0x61] = (p & 0xFF); + + return p; +} + +uint16_t make_port2(uint8_t ld) +{ + uint16_t r0 = fdc37c932fr_ld_regs[ld][0x62]; + uint16_t r1 = fdc37c932fr_ld_regs[ld][0x63]; + + uint16_t p = (r0 << 8) + r1; + + switch(ld) + { + case 1: + p &= 0xFFF; + if ((p < 0x100) || (p > 0xFF8)) p = 0x3F6; + if (!(is_in_array(ld1_valid_ports2, 2, p))) p = 0x3F6; + break; + case 2: + p &= 0xFFF; + if ((p < 0x100) || (p > 0xFF8)) p = 0x376; + if (!(is_in_array(ld2_valid_ports2, 2, p))) p = 0x376; + break; + case 5: + p &= 0xFF8; + if ((p < 0x100) || (p > 0xFF8)) p = 0x3E8; + if (!(is_in_array(ld5_valid_ports2, 9, p))) p = 0x3E8; + break; + } + + fdc37c932fr_ld_regs[ld][0x62] = (p >> 8); + fdc37c932fr_ld_regs[ld][0x63] = (p & 0xFF); + + return p; +} + +void fdc37c932fr_gpio_write(uint16_t port, uint8_t val, void *priv) +{ + if (port & 1) + { + if (fdc37c932fr_gpio_curreg && (fdc37c932fr_gpio_curreg <= 0xF)) + fdc37c932fr_gpio_regs[fdc37c932fr_gpio_curreg] = val; + } + else + { + fdc37c932fr_gpio_curreg = val; + } +} + +void fdc37c932fr_write(uint16_t port, uint8_t val, void *priv) +{ + uint8_t index = (port & 1) ? 0 : 1; + uint8_t valxor = 0; + uint16_t ld_port = 0; + uint16_t ld_port2 = 0; + int temp; + // pclog("fdc37c932fr_write : port=%04x reg %02X = %02X locked=%i\n", port, fdc37c932fr_curreg, val, fdc37c932fr_locked); + + if (index) + { + if ((val == 0x55) && !fdc37c932fr_locked) + { + if (tries) + { + fdc37c932fr_locked = 1; + fdc_3f1_enable(0); + tries = 0; + } + else + { + tries++; + } + } + else + { + if (fdc37c932fr_locked) + { + if (val == 0xaa) + { + fdc37c932fr_locked = 0; + fdc_3f1_enable(1); + return; + } + fdc37c932fr_curreg = val; + } + else + { + if (tries) + tries = 0; + } + } + } + else + { + if (fdc37c932fr_locked) + { + if (fdc37c932fr_curreg < 48) + { + valxor = val ^ fdc37c932fr_regs[fdc37c932fr_curreg]; + fdc37c932fr_regs[fdc37c932fr_curreg] = val; + } + else + { + valxor = val ^ fdc37c932fr_ld_regs[fdc37c932fr_regs[7]][fdc37c932fr_curreg]; + if ((fdc37c932fr_curreg & 0xF0 == 0x70) && (fdc37c932fr_regs[7] < 4)) return; + /* Block writes to IDE configuration. */ + if (fdc37c932fr_regs[7] == 1) return; + if (fdc37c932fr_regs[7] == 2) return; + if (fdc37c932fr_regs[7] > 5) return; + fdc37c932fr_ld_regs[fdc37c932fr_regs[7]][fdc37c932fr_curreg] = val; + goto process_value; + } + } + } + return; + +process_value: + switch(fdc37c932fr_regs[7]) + { + case 0: + /* FDD */ + switch(fdc37c932fr_curreg) + { + case 0x30: + /* Activate */ + if (valxor) + { + if (!val) + fdc_remove(); + else + { + fdc_add(); + } + } + break; + case 0x60: + case 0x61: + if (valxor && fdc37c932fr_ld_regs[0][0x30]) + { + fdc_remove(); + ld_port = make_port(0); + fdc37c932fr_ld_regs[0][0x60] = make_port(0) >> 8; + fdc37c932fr_ld_regs[0][0x61] = make_port(0) & 0xFF; + fdc_add(); + } + break; + case 0xF0: + if (valxor & 0x01) fdc_update_enh_mode(val & 0x01); + if (valxor & 0x10) fdd_swap = ((val & 0x10) >> 4); + break; + case 0xF1: + if (valxor & 0xC) fdc_update_densel_force((val & 0xC) >> 2); + break; + case 0xF2: + if (valxor & 0x0C) fdc_update_rwc(1, (valxor & 0x0C) >> 2); + if (valxor & 0x03) fdc_update_rwc(0, (valxor & 0x03)); + break; + case 0xF4: + if (valxor & 0x18) fdc_update_drvrate(0, (val & 0x18) >> 3); + break; + case 0xF5: + if (valxor & 0x18) fdc_update_drvrate(1, (val & 0x18) >> 3); + break; + } + break; + case 3: + /* Parallel port */ + switch(fdc37c932fr_curreg) + { + case 0x30: + /* Activate */ + if (valxor) + { + if (!val) + lpt1_remove(); + else + { + ld_port = make_port(3); + lpt1_init(ld_port); + } + } + break; + case 0x60: + case 0x61: + if (valxor && fdc37c932fr_ld_regs[3][0x30]) + { + lpt1_remove(); + ld_port = make_port(3); + lpt1_init(ld_port); + } + break; + } + break; + case 4: + /* Serial port 1 */ + switch(fdc37c932fr_curreg) + { + case 0x30: + /* Activate */ + if (valxor) + { + if (!val) + serial1_remove(); + else + { + ld_port = make_port(4); + serial1_set(ld_port, fdc37c932fr_ld_regs[4][0x70]); + mouse_serial_init(); + } + } + break; + case 0x60: + case 0x61: + case 0x70: + if (valxor && fdc37c932fr_ld_regs[4][0x30]) + { + ld_port = make_port(4); + serial1_set(ld_port, fdc37c932fr_ld_regs[4][0x70]); + mouse_serial_init(); + } + break; + } + break; + case 5: + /* Serial port 2 */ + switch(fdc37c932fr_curreg) + { + case 0x30: + /* Activate */ + if (valxor) + { + if (!val) + serial2_remove(); + else + { + ld_port = make_port(5); + serial2_set(ld_port, fdc37c932fr_ld_regs[5][0x70]); + } + } + break; + case 0x60: + case 0x61: + case 0x70: + if (valxor && fdc37c932fr_ld_regs[5][0x30]) + { + ld_port = make_port(5); + serial2_set(ld_port, fdc37c932fr_ld_regs[5][0x70]); + } + break; + } + break; + } +} + +uint8_t fdc37c932fr_gpio_read(uint16_t port, void *priv) +{ + if (port & 1) + { + if (fdc37c932fr_gpio_curreg && (fdc37c932fr_gpio_curreg <= 0xF)) + return fdc37c932fr_gpio_regs[fdc37c932fr_gpio_curreg]; + else + return 0xff; + } + else + { + return fdc37c932fr_gpio_curreg; + } +} + +uint8_t fdc37c932fr_read(uint16_t port, void *priv) +{ + // pclog("fdc37c932fr_read : port=%04x reg %02X locked=%i\n", port, fdc37c932fr_curreg, fdc37c932fr_locked); + uint8_t index = (port & 1) ? 0 : 1; + + if (!fdc37c932fr_locked) + { + return 0xff; + } + + if (index) + return fdc37c932fr_curreg; + else + { + if (fdc37c932fr_curreg < 0x30) + { + // pclog("0x03F1: %02X\n", fdc37c932fr_regs[fdc37c932fr_curreg]); + return fdc37c932fr_regs[fdc37c932fr_curreg]; + } + else + { + // pclog("0x03F1 (CD=%02X): %02X\n", fdc37c932fr_regs[7], fdc37c932fr_ld_regs[fdc37c932fr_regs[7]][fdc37c932fr_curreg]); + if ((fdc37c932fr_regs[7] == 0) && (fdc37c932fr_curreg == 0xF2)) return (fdc_get_rwc(0) | (fdc_get_rwc(1) << 2)); + return fdc37c932fr_ld_regs[fdc37c932fr_regs[7]][fdc37c932fr_curreg]; + } + } +} + +void fdc37c932fr_init() +{ + int i = 0; + + lpt2_remove(); + + fdc37c932fr_regs[3] = 3; + fdc37c932fr_regs[0x20] = 3; + fdc37c932fr_regs[0x21] = 1; + fdc37c932fr_regs[0x24] = 4; + fdc37c932fr_regs[0x26] = 0xF0; + fdc37c932fr_regs[0x27] = 3; + + for (i = 0; i < 10; i++) + { + memset(fdc37c932fr_ld_regs[i], 0, 256); + } + + /* Logical device 0: FDD */ + fdc37c932fr_ld_regs[0][0x30] = 1; + fdc37c932fr_ld_regs[0][0x60] = 3; + fdc37c932fr_ld_regs[0][0x61] = 0xF0; + fdc37c932fr_ld_regs[0][0x70] = 6; + fdc37c932fr_ld_regs[0][0x74] = 2; + fdc37c932fr_ld_regs[0][0xF0] = 0xE; + fdc37c932fr_ld_regs[0][0xF2] = 0xFF; + + /* Logical device 1: IDE1 */ + fdc37c932fr_ld_regs[1][0x30] = 1; + fdc37c932fr_ld_regs[1][0x60] = 1; + fdc37c932fr_ld_regs[1][0x61] = 0xF0; + fdc37c932fr_ld_regs[1][0x62] = 3; + fdc37c932fr_ld_regs[1][0x63] = 0xF6; + fdc37c932fr_ld_regs[1][0x70] = 0xE; + fdc37c932fr_ld_regs[1][0xF0] = 0xC; + + /* Logical device 2: IDE2 */ + fdc37c932fr_ld_regs[2][0x30] = 1; + fdc37c932fr_ld_regs[2][0x60] = 1; + fdc37c932fr_ld_regs[2][0x61] = 0x70; + fdc37c932fr_ld_regs[2][0x62] = 3; + fdc37c932fr_ld_regs[2][0x63] = 0x76; + fdc37c932fr_ld_regs[2][0x70] = 0xF; + + /* Logical device 3: Parallel Port */ + fdc37c932fr_ld_regs[3][0x30] = 1; + fdc37c932fr_ld_regs[3][0x60] = 3; + fdc37c932fr_ld_regs[3][0x61] = 0x78; + fdc37c932fr_ld_regs[3][0x70] = 7; + fdc37c932fr_ld_regs[3][0x74] = 4; + fdc37c932fr_ld_regs[3][0xF0] = 0x3C; + + /* Logical device 4: Serial Port 1 */ + fdc37c932fr_ld_regs[4][0x30] = 1; + fdc37c932fr_ld_regs[4][0x60] = 3; + fdc37c932fr_ld_regs[4][0x61] = 0xf8; + fdc37c932fr_ld_regs[4][0x70] = 4; + fdc37c932fr_ld_regs[4][0xF0] = 3; + + /* Logical device 5: Serial Port 2 */ + fdc37c932fr_ld_regs[5][0x30] = 1; + fdc37c932fr_ld_regs[5][0x60] = 2; + fdc37c932fr_ld_regs[5][0x61] = 0xf8; + fdc37c932fr_ld_regs[5][0x70] = 3; + fdc37c932fr_ld_regs[5][0x74] = 4; + fdc37c932fr_ld_regs[5][0xF1] = 2; + fdc37c932fr_ld_regs[5][0xF2] = 3; + + /* Logical device 6: RTC */ + fdc37c932fr_ld_regs[6][0x63] = 0x70; + fdc37c932fr_ld_regs[6][0xF4] = 3; + + /* Logical device 7: Keyboard */ + fdc37c932fr_ld_regs[7][0x30] = 1; + fdc37c932fr_ld_regs[7][0x61] = 0x60; + fdc37c932fr_ld_regs[7][0x70] = 1; + + /* Logical device 8: AUX I/O */ + + /* Logical device 9: ACCESS.bus */ + + fdc_update_densel_force(0); + fdd_swap = 0; + fdc_update_rwc(0, 0); + fdc_update_rwc(1, 0); + fdc_update_drvrate(0, 0); + fdc_update_drvrate(1, 0); + io_sethandler(0xe0, 0x0006, fdc37c932fr_gpio_read, NULL, NULL, fdc37c932fr_gpio_write, NULL, NULL, NULL); + io_sethandler(0xea, 0x0002, fdc37c932fr_gpio_read, NULL, NULL, fdc37c932fr_gpio_write, NULL, NULL, NULL); + io_sethandler(0x3f0, 0x0002, fdc37c932fr_read, NULL, NULL, fdc37c932fr_write, NULL, NULL, NULL); + fdc37c932fr_locked = 0; +} diff --git a/src/fdc37c932fr.h b/src/fdc37c932fr.h new file mode 100644 index 000000000..8329d2ddd --- /dev/null +++ b/src/fdc37c932fr.h @@ -0,0 +1 @@ +extern void fdc37c932fr_init(); diff --git a/src/fdd.c b/src/fdd.c new file mode 100644 index 000000000..1237129da --- /dev/null +++ b/src/fdd.c @@ -0,0 +1,325 @@ +#include "ibm.h" +#include "disc.h" +#include "fdc.h" +#include "fdd.h" +#include "timer.h" + +static struct +{ + int type; + + int track; + + int densel; + + int drate; + + int kbps; + int fdc_kbps; + + int head; +} fdd[2]; + +/* Flags: + Bit 0: 300 rpm supported; + Bit 1: 360 rpm supported; + Bit 2: size (0 = 3.5", 1 = 5.25"); + Bit 3: double density supported; + Bit 4: high density supported; + Bit 5: extended density supported; + Bit 6: double step for 40-track media; +*/ +#define FLAG_RPM_300 1 +#define FLAG_RPM_360 2 +#define FLAG_525 4 +#define FLAG_HOLE0 8 +#define FLAG_HOLE1 16 +#define FLAG_HOLE2 32 +#define FLAG_DOUBLE_STEP 64 + +static struct +{ + int max_track; + int flags; +} drive_types[] = +{ + { /*None*/ + .max_track = 0, + .flags = 0 + }, + { /*5.25" DD*/ +#ifdef MAINLINE + .max_track = 41, +#else + .max_track = 43, +#endif + .flags = FLAG_RPM_300 | FLAG_525 | FLAG_HOLE0 + }, + { /*5.25" HD*/ +#ifdef MAINLINE + .max_track = 82, +#else + .max_track = 86, +#endif + .flags = FLAG_RPM_360 | FLAG_525 | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP + }, + { /*5.25" HD Dual RPM*/ +#ifdef MAINLINE + .max_track = 82, +#else + .max_track = 86, +#endif + .flags = FLAG_RPM_300 | FLAG_RPM_360 | FLAG_525 | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP + }, + { /*3.5" DD*/ +#ifdef MAINLINE + .max_track = 82, +#else + .max_track = 86, +#endif + .flags = FLAG_RPM_300 | FLAG_HOLE0 + }, + { /*3.5" HD*/ +#ifdef MAINLINE + .max_track = 82, +#else + .max_track = 86, +#endif + .flags = FLAG_RPM_300 | FLAG_HOLE0 | FLAG_HOLE1 + }, + { /*3.5" HD 3-Mode*/ +#ifdef MAINLINE + .max_track = 82, +#else + .max_track = 86, +#endif + .flags = FLAG_RPM_300 | FLAG_RPM_360 | FLAG_HOLE0 | FLAG_HOLE1 + }, + { /*3.5" ED*/ +#ifdef MAINLINE + .max_track = 82, +#else + .max_track = 86, +#endif + .flags = FLAG_RPM_300 | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_HOLE2 + } +}; + +int fdd_swap = 0; + +int fdd_stepping_motor_on[2] = {0, 0}; +int fdd_track_diff[2] = {0, 0}; +int fdd_track_direction[2] = {0, 0}; +int fdd_old_track[2] = {0, 0}; + +int fdd_poll_time[2] = {0, 0}; + +void fdd_seek_poll(int poll_drive) +{ + if (!fdd_track_diff[poll_drive]) + { + fdd_stepping_motor_on[poll_drive] = 0; + return; + } + + /* 80-track drive takes 6 µs per step, 40-track drive takes 10 µs. */ + // fdd_poll_time[poll_drive] += (drive_types[fdd[poll_drive].type].max_track <= 43) ? (10 * TIMER_USEC) : (6 * TIMER_USEC); + fdd_poll_time[poll_drive] += (drive_types[fdd[poll_drive].type].max_track <= 43) ? (5 * TIMER_USEC) : (3 * TIMER_USEC); + + if (fdd_track_direction[poll_drive]) + { + fdd[poll_drive].track++; + + if (fdd[poll_drive].track > drive_types[fdd[poll_drive].type].max_track) + fdd[poll_drive].track = drive_types[fdd[poll_drive].type].max_track; + } + else + { + fdd[poll_drive].track--; + + if (fdd[poll_drive].track < 0) + fdd[poll_drive].track = 0; + } + + fdd_track_diff[poll_drive]--; + + if (!fdd_track_diff[poll_drive]) + { + fdc_discchange_clear(poll_drive); + + disc_seek(poll_drive, fdd[poll_drive].track); + fdd_stepping_motor_on[poll_drive] = 0; + } +} + +void fdd_seek_poll_0() +{ + fdd_seek_poll(0); +} + +void fdd_seek_poll_1() +{ + fdd_seek_poll(1); +} + +#if 0 +void fdd_seek(int drive, int track_diff) +{ + drive ^= fdd_swap; + + fdd_old_track[drive] = fdd[drive].track; + + if (!track_diff) + { + /* Do not turn on motor if there are no pulses to be sent. */ + fdc_discchange_clear(drive); + return; + } + + fdd_stepping_motor_on[drive] = (track_diff == 0) ? 0 : 1; + if (fdd_stepping_motor_on[drive]) pclog("fdd_seek(): Stepping motor now on\n"); + + if (track_diff < 0) + { + fdd_track_diff[drive] = -track_diff; + fdd_track_direction[drive] = 0; + } + else + { + fdd_track_diff[drive] = track_diff; + fdd_track_direction[drive] = 1; + } + + fdd_old_track[drive] = fdd[drive].track; +} +#endif + +void fdd_seek(int drive, int track_diff) +{ + int old_track; + + drive ^= fdd_swap; + + old_track = fdd[drive].track; + + fdd[drive].track += track_diff; + + if (fdd[drive].track < 0) + fdd[drive].track = 0; + + if (fdd[drive].track > drive_types[fdd[drive].type].max_track) + fdd[drive].track = drive_types[fdd[drive].type].max_track; + + // pclog("fdd_seek: drive=%i track_diff=%i old_track=%i track=%i\n", drive, track_diff, old_track, fdd[drive].track); + // if (fdd[drive].track != old_track) + // fdc_discchange_clear(drive); + fdc_discchange_clear(drive); + disc_seek(drive, fdd[drive].track); + // disctime = 5000; + disctime = 50; +} + +int fdd_track0(int drive) +{ + drive ^= fdd_swap; + + /* If drive is disabled, TRK0 never gets set. */ + if (!drive_types[fdd[drive].type].max_track) return 0; + + return !fdd[drive].track; +} + +void fdd_set_densel(int densel) +{ + fdd[0].densel = densel; + fdd[1].densel = densel; +} + +int fdd_getrpm(int drive) +{ + int hole = disc_hole(drive); + + drive ^= fdd_swap; + + if (!(drive_types[fdd[drive].type].flags & FLAG_RPM_360)) return 300; + if (!(drive_types[fdd[drive].type].flags & FLAG_RPM_300)) return 360; + + if (drive_types[fdd[drive].type].flags & FLAG_525) + { + return fdd[drive].densel ? 360 : 300; + } + else + { + /* disc_hole(drive) returns 0 for double density media, 1 for high density, and 2 for extended density. */ + if (hole == 1) + { + return fdd[drive].densel ? 300 : 360; + } + else + { + return 300; + } + } +} + +void fdd_setswap(int swap) +{ + fdd_swap = swap ? 1 : 0; +} + +int fdd_can_read_medium(int drive) +{ + int hole = disc_hole(drive); + + drive ^= fdd_swap; + + hole = 1 << (hole + 3); + +// pclog("Drive %02X, type %02X, hole flag %02X, flags %02X, result %02X\n", drive, fdd[drive].type, hole, drive_types[fdd[drive].type].flags, drive_types[fdd[drive].type].flags & hole); + return (drive_types[fdd[drive].type].flags & hole) ? 1 : 0; +} + +int fdd_doublestep_40(int drive) +{ + return drive_types[fdd[drive].type].flags & FLAG_DOUBLE_STEP; +} + +void fdd_set_type(int drive, int type) +{ + fdd[drive].type = type; +} + +int fdd_get_type(int drive) +{ + return fdd[drive].type; +} + +int fdd_is_525(int drive) +{ + return drive_types[fdd[drive].type].flags & FLAG_525; +} + +int fdd_is_ed(int drive) +{ + return drive_types[fdd[drive].type].flags & FLAG_HOLE2; +} + +void fdd_set_head(int drive, int head) +{ + drive ^= fdd_swap; + fdd[drive].head = head; +} + +int fdd_get_head(int drive) +{ + return fdd[drive].head; +} + +void fdd_init() +{ + fdd_stepping_motor_on[0] = fdd_stepping_motor_on[1] = 0; + fdd_track_diff[0] = fdd_track_diff[1] = 0; + + timer_add(fdd_seek_poll_0, &(fdd_poll_time[0]), &(fdd_stepping_motor_on[0]), NULL); + timer_add(fdd_seek_poll_1, &(fdd_poll_time[1]), &(fdd_stepping_motor_on[1]), NULL); +} diff --git a/src/fdd.h b/src/fdd.h new file mode 100644 index 000000000..8b183054e --- /dev/null +++ b/src/fdd.h @@ -0,0 +1,20 @@ +#define SEEK_RECALIBRATE -999 +void fdd_seek(int drive, int track_diff); +int fdd_track0(int drive); +int fdd_getrpm(int drive); +void fdd_set_densel(int densel); +int fdd_can_read_medium(int drive); +int fdd_doublestep_40(int drive); +int fdd_is_525(int drive); +int fdd_is_ed(int drive); +void fdd_set_head(int drive, int head); +int fdd_get_head(int drive); + +void fdd_set_type(int drive, int type); +int fdd_get_type(int drive); + +extern int fdd_swap; + +extern int fdd_stepping_motor_on[2]; +extern int fdd_track_diff[2]; +void fdd_init(); diff --git a/src/fdi2raw.c b/src/fdi2raw.c new file mode 100644 index 000000000..abace4f1b --- /dev/null +++ b/src/fdi2raw.c @@ -0,0 +1,2190 @@ +/* + + FDI to raw bit stream converter + Copyright (c) 2001 by Toni Wilen + FDI 2.0 support + Copyright (c) 2003-2004 by Toni Wilen + and Vincent Joguin + + FDI format created by Vincent "ApH" Joguin + + Tiny changes - function type fixes, multiple drives, addition of + get_last_head and C++ callability - by Thomas Harte, 2001, + T.Harte@excite.co.uk + + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2 of the License, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + more details. + + You should have received a copy of the GNU General Public License along + with this program; if not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + +*/ + +#define STATIC_INLINE +#include +#include +#include +#include + +/* IF UAE */ +/*#include "sysconfig.h" +#include "sysdeps.h" +#include "zfile.h"*/ +/* ELSE */ +//#include "types.h" +#define xmalloc malloc +#include "fdi2raw.h" + +#include "ibm.h" + +#undef DEBUG +#define VERBOSE +#undef VERBOSE + +#include + +#ifdef DEBUG +static char *datalog(uae_u8 *src, int len) +{ + static char buf[1000]; + static int offset; + int i = 0, offset2; + + offset2 = offset; + buf[offset++]='\''; + while(len--) { + sprintf (buf + offset, "%02.2X", src[i]); + offset += 2; + i++; + if (i > 10) break; + } + buf[offset++]='\''; + buf[offset++] = 0; + if (offset >= 900) offset = 0; + return buf + offset2; +} +#else +static char *datalog(uae_u8 *src, int len) { return ""; } +#endif + +#define outlog pclog +#define debuglog pclog + +static int fdi_allocated; +#ifdef DEBUG +static void fdi_free (void *p) +{ + int size; + if (!p) + return; + size = ((int*)p)[-1]; + fdi_allocated -= size; + write_log ("%d freed (%d)\n", size, fdi_allocated); + free ((int*)p - 1); +} +static void *fdi_malloc (int size) +{ + void *p = xmalloc (size + sizeof (int)); + ((int*)p)[0] = size; + fdi_allocated += size; + write_log ("%d allocated (%d)\n", size, fdi_allocated); + return (int*)p + 1; +} +#else +#define fdi_free free +#define fdi_malloc xmalloc +#endif + +#define MAX_SRC_BUFFER 4194304 +#define MAX_DST_BUFFER 40000 +#define MAX_MFM_SYNC_BUFFER 60000 +#define MAX_TIMING_BUFFER 400000 +#define MAX_TRACKS 166 + +struct fdi_cache { + uae_u32 *avgp, *minp, *maxp; + uae_u8 *idxp; + int avg_free, idx_free, min_free, max_free; + uae_u32 totalavg, pulses, maxidx, indexoffset; + int weakbits; + int lowlevel; +}; + +struct fdi { + uae_u8 *track_src_buffer; + uae_u8 *track_src; + int track_src_len; + uae_u8 *track_dst_buffer; + uae_u8 *track_dst; + uae_u16 *track_dst_buffer_timing; + uae_u8 track_len; + uae_u8 track_type; + int current_track; + int last_track; + int last_head; + int rotation_speed; + int bit_rate; + int disk_type; + int write_protect; + int err; + uae_u8 header[2048]; + int track_offsets[MAX_TRACKS]; + FILE *file; + int out; + int mfmsync_offset; + int *mfmsync_buffer; + /* sector described only */ + int index_offset; + int encoding_type; + /* bit handling */ + int nextdrop; + struct fdi_cache cache[MAX_TRACKS]; +}; + +#define get_u32(x) ((((x)[0])<<24)|(((x)[1])<<16)|(((x)[2])<<8)|((x)[3])) +#define get_u24(x) ((((x)[0])<<16)|(((x)[1])<<8)|((x)[2])) +STATIC_INLINE void put_u32 (uae_u8 *d, uae_u32 v) +{ + d[0] = v >> 24; + d[1] = v >> 16; + d[2] = v >> 8; + d[3] = v; +} + +struct node { + uae_u16 v; + struct node *left; + struct node *right; +}; +typedef struct node NODE; + +static uae_u8 temp, temp2; + +static uae_u8 *expand_tree (uae_u8 *stream, NODE *node) +{ + if (temp & temp2) { + fdi_free (node->left); + node->left = 0; + fdi_free (node->right); + node->right = 0; + temp2 >>= 1; + if (!temp2) { + temp = *stream++; + temp2 = 0x80; + } + return stream; + } else { + uae_u8 *stream_temp; + temp2 >>= 1; + if (!temp2) { + temp = *stream++; + temp2 = 0x80; + } + node->left = fdi_malloc (sizeof (NODE)); + memset (node->left, 0, sizeof (NODE)); + stream_temp = expand_tree (stream, node->left); + node->right = fdi_malloc (sizeof (NODE)); + memset (node->right, 0, sizeof (NODE)); + return expand_tree (stream_temp, node->right); + } +} + +static uae_u8 *values_tree8 (uae_u8 *stream, NODE *node) +{ + if (node->left == 0) { + node->v = *stream++; + return stream; + } else { + uae_u8 *stream_temp = values_tree8 (stream, node->left); + return values_tree8 (stream_temp, node->right); + } +} + +static uae_u8 *values_tree16 (uae_u8 *stream, NODE *node) +{ + if (node->left == 0) { + uae_u16 high_8_bits = (*stream++) << 8; + node->v = high_8_bits | (*stream++); + return stream; + } else { + uae_u8 *stream_temp = values_tree16 (stream, node->left); + return values_tree16 (stream_temp, node->right); + } +} + +static void free_nodes (NODE *node) +{ + if (node) { + free_nodes (node->left); + free_nodes (node->right); + fdi_free (node); + } +} + +static uae_u32 sign_extend16 (uae_u32 v) +{ + if (v & 0x8000) + v |= 0xffff0000; + return v; +} + +static uae_u32 sign_extend8 (uae_u32 v) +{ + if (v & 0x80) + v |= 0xffffff00; + return v; +} + +static void fdi_decode (uae_u8 *stream, int size, uae_u8 *out) +{ + int i; + uae_u8 sign_extend, sixteen_bit, sub_stream_shift; + NODE root; + NODE *current_node; + + memset (out, 0, size * 4); + sub_stream_shift = 1; + while (sub_stream_shift) { + + //sub-stream header decode + sign_extend = *stream++; + sub_stream_shift = sign_extend & 0x7f; + sign_extend &= 0x80; + sixteen_bit = (*stream++) & 0x80; + + //huffman tree architecture decode + temp = *stream++; + temp2 = 0x80; + stream = expand_tree (stream, &root); + if (temp2 == 0x80) + stream--; + + //huffman output values decode + if (sixteen_bit) + stream = values_tree16 (stream, &root); + else + stream = values_tree8 (stream, &root); + + //sub-stream data decode + temp2 = 0; + for (i = 0; i < size; i++) { + uae_u32 v; + uae_u8 decode = 1; + current_node = &root; + while (decode) { + if (current_node->left == 0) { + decode = 0; + } else { + temp2 >>= 1; + if (!temp2) { + temp2 = 0x80; + temp = *stream++; + } + if (temp & temp2) + current_node = current_node->right; + else + current_node = current_node->left; + } + } + v = ((uae_u32*)out)[i]; + if (sign_extend) { + if (sixteen_bit) + v |= sign_extend16 (current_node->v) << sub_stream_shift; + else + v |= sign_extend8 (current_node->v) << sub_stream_shift; + } else { + v |= current_node->v << sub_stream_shift; + } + ((uae_u32*)out)[i] = v; + } + free_nodes (root.left); + free_nodes (root.right); + } +} + + +static int decode_raw_track (FDI *fdi) +{ + int size = get_u32(fdi->track_src); + memcpy (fdi->track_dst, fdi->track_src, (size + 7) >> 3); + fdi->track_src += (size + 7) >> 3; + return size; +} + +/* unknown track */ +static void zxx (FDI *fdi) +{ + outlog ("track %d: unknown track type 0x%02.2X\n", fdi->current_track, fdi->track_type); +// return -1; +} +/* unsupported track */ +#if 0 +static void zyy (FDI *fdi) +{ + outlog ("track %d: unsupported track type 0x%02.2X\n", fdi->current_track, fdi->track_type); +// return -1; +} +#endif +/* empty track */ +static void track_empty (FDI *fdi) +{ +// return 0; +} + +/* unknown sector described type */ +static void dxx (FDI *fdi) +{ + outlog ("\ntrack %d: unknown sector described type 0x%02.2X\n", fdi->current_track, fdi->track_type); + fdi->err = 1; +} +/* unsupported sector described type */ +#if 0 +static void dyy (FDI *fdi) +{ + outlog ("\ntrack %d: unsupported sector described 0x%02.2X\n", fdi->current_track, fdi->track_type); + fdi->err = 1; +} +#endif +/* add position of mfm sync bit */ +static void add_mfm_sync_bit (FDI *fdi) +{ + if (fdi->nextdrop) { + fdi->nextdrop = 0; + return; + } + fdi->mfmsync_buffer[fdi->mfmsync_offset++] = fdi->out; + if (fdi->out == 0) { + outlog ("illegal position for mfm sync bit, offset=%d\n",fdi->out); + fdi->err = 1; + } + if (fdi->mfmsync_offset >= MAX_MFM_SYNC_BUFFER) { + fdi->mfmsync_offset = 0; + outlog ("mfmsync buffer overflow\n"); + fdi->err = 1; + } + fdi->out++; +} + +#define BIT_BYTEOFFSET ((fdi->out) >> 3) +#define BIT_BITOFFSET (7-((fdi->out)&7)) + +/* add one bit */ +static void bit_add (FDI *fdi, int bit) +{ + if (fdi->nextdrop) { + fdi->nextdrop = 0; + return; + } + fdi->track_dst[BIT_BYTEOFFSET] &= ~(1 << BIT_BITOFFSET); + if (bit) + fdi->track_dst[BIT_BYTEOFFSET] |= (1 << BIT_BITOFFSET); + fdi->out++; + if (fdi->out >= MAX_DST_BUFFER * 8) { + outlog ("destination buffer overflow\n"); + fdi->err = 1; + fdi->out = 1; + } +} +/* add bit and mfm sync bit */ +static void bit_mfm_add (FDI *fdi, int bit) +{ + add_mfm_sync_bit (fdi); + bit_add (fdi, bit); +} +/* remove following bit */ +static void bit_drop_next (FDI *fdi) +{ + if (fdi->nextdrop > 0) { + outlog("multiple bit_drop_next() called"); + } else if (fdi->nextdrop < 0) { + fdi->nextdrop = 0; + debuglog(":DNN:"); + return; + } + debuglog(":DN:"); + fdi->nextdrop = 1; +} + +/* ignore next bit_drop_next() */ +static void bit_dedrop (FDI *fdi) +{ + if (fdi->nextdrop) { + outlog("bit_drop_next called before bit_dedrop"); + } + fdi->nextdrop = -1; + debuglog(":BDD:"); +} + +/* add one byte */ +static void byte_add (FDI *fdi, uae_u8 v) +{ + int i; + for (i = 7; i >= 0; i--) + bit_add (fdi, v & (1 << i)); +} +/* add one word */ +static void word_add (FDI *fdi, uae_u16 v) +{ + byte_add (fdi, (uae_u8)(v >> 8)); + byte_add (fdi, (uae_u8)v); +} +/* add one byte and mfm encode it */ +static void byte_mfm_add (FDI *fdi, uae_u8 v) +{ + int i; + for (i = 7; i >= 0; i--) + bit_mfm_add (fdi, v & (1 << i)); +} +/* add multiple bytes and mfm encode them */ +static void bytes_mfm_add (FDI *fdi, uae_u8 v, int len) +{ + int i; + for (i = 0; i < len; i++) byte_mfm_add (fdi, v); +} +/* add one mfm encoded word and re-mfm encode it */ +static void word_post_mfm_add (FDI *fdi, uae_u16 v) +{ + int i; + for (i = 14; i >= 0; i -= 2) + bit_mfm_add (fdi, v & (1 << i)); +} + +/* bit 0 */ +static void s00(FDI *fdi) { bit_add (fdi, 0); } +/* bit 1*/ +static void s01(FDI *fdi) { bit_add (fdi, 1); } +/* 4489 */ +static void s02(FDI *fdi) { word_add (fdi, 0x4489); } +/* 5224 */ +static void s03(FDI *fdi) { word_add (fdi, 0x5224); } +/* mfm sync bit */ +static void s04(FDI *fdi) { add_mfm_sync_bit (fdi); } +/* RLE MFM-encoded data */ +static void s08(FDI *fdi) +{ + int bytes = *fdi->track_src++; + uae_u8 byte = *fdi->track_src++; + if (bytes == 0) bytes = 256; + debuglog ("s08:len=%d,data=%02.2X",bytes,byte); + while(bytes--) byte_add (fdi, byte); +} +/* RLE MFM-decoded data */ +static void s09(FDI *fdi) +{ + int bytes = *fdi->track_src++; + uae_u8 byte = *fdi->track_src++; + if (bytes == 0) bytes = 256; + bit_drop_next (fdi); + debuglog ("s09:len=%d,data=%02.2X",bytes,byte); + while(bytes--) byte_mfm_add (fdi, byte); +} +/* MFM-encoded data */ +static void s0a(FDI *fdi) +{ + int i, bits = (fdi->track_src[0] << 8) | fdi->track_src[1]; + uae_u8 b; + fdi->track_src += 2; + debuglog ("s0a:bits=%d,data=%s", bits, datalog(fdi->track_src, (bits + 7) / 8)); + while (bits >= 8) { + byte_add (fdi, *fdi->track_src++); + bits -= 8; + } + if (bits > 0) { + i = 7; + b = *fdi->track_src++; + while (bits--) { + bit_add (fdi, b & (1 << i)); + i--; + } + } +} +/* MFM-encoded data */ +static void s0b(FDI *fdi) +{ + int i, bits = ((fdi->track_src[0] << 8) | fdi->track_src[1]) + 65536; + uae_u8 b; + fdi->track_src += 2; + debuglog ("s0b:bits=%d,data=%s", bits, datalog(fdi->track_src, (bits + 7) / 8)); + while (bits >= 8) { + byte_add (fdi, *fdi->track_src++); + bits -= 8; + } + if (bits > 0) { + i = 7; + b = *fdi->track_src++; + while (bits--) { + bit_add (fdi, b & (1 << i)); + i--; + } + } +} +/* MFM-decoded data */ +static void s0c(FDI *fdi) +{ + int i, bits = (fdi->track_src[0] << 8) | fdi->track_src[1]; + uae_u8 b; + fdi->track_src += 2; + bit_drop_next (fdi); + debuglog ("s0c:bits=%d,data=%s", bits, datalog(fdi->track_src, (bits + 7) / 8)); + while (bits >= 8) { + byte_mfm_add (fdi, *fdi->track_src++); + bits -= 8; + } + if (bits > 0) { + i = 7; + b = *fdi->track_src++; + while(bits--) { + bit_mfm_add (fdi, b & (1 << i)); + i--; + } + } +} +/* MFM-decoded data */ +static void s0d(FDI *fdi) +{ + int i, bits = ((fdi->track_src[0] << 8) | fdi->track_src[1]) + 65536; + uae_u8 b; + fdi->track_src += 2; + bit_drop_next (fdi); + debuglog ("s0d:bits=%d,data=%s", bits, datalog(fdi->track_src, (bits + 7) / 8)); + while (bits >= 8) { + byte_mfm_add (fdi, *fdi->track_src++); + bits -= 8; + } + if (bits > 0) { + i = 7; + b = *fdi->track_src++; + while(bits--) { + bit_mfm_add (fdi, b & (1 << i)); + i--; + } + } +} + +/* ***** */ +/* AMIGA */ +/* ***** */ + +/* just for testing integrity of Amiga sectors */ + +/*static void rotateonebit (uae_u8 *start, uae_u8 *end, int shift) +{ + if (shift == 0) + return; + while (start <= end) { + start[0] <<= shift; + start[0] |= start[1] >> (8 - shift); + start++; + } +}*/ + +//static int check_offset; +/*static uae_u16 getmfmword (uae_u8 *mbuf) +{ + uae_u32 v; + + v = (mbuf[0] << 8) | (mbuf[1] << 0); + if (check_offset == 0) + return v; + v <<= 8; + v |= mbuf[2]; + v >>= check_offset; + return v; +}*/ + +#define MFMMASK 0x55555555 +/*static uae_u32 getmfmlong (uae_u8 * mbuf) +{ + return ((getmfmword (mbuf) << 16) | getmfmword (mbuf + 2)) & MFMMASK; +}*/ + +#if 0 +static int amiga_check_track (FDI *fdi) +{ + int i, j, secwritten = 0; + int fwlen = fdi->out / 8; + int length = 2 * fwlen; + int drvsec = 11; + uae_u32 odd, even, chksum, id, dlong; + uae_u8 *secdata; + uae_u8 secbuf[544]; + uae_u8 bigmfmbuf[60000]; + uae_u8 *mbuf, *mbuf2, *mend; + char sectable[22]; + uae_u8 *raw = fdi->track_dst_buffer; + int slabel, off; + int ok = 1; + + memset (bigmfmbuf, 0, sizeof (bigmfmbuf)); + mbuf = bigmfmbuf; + check_offset = 0; + for (i = 0; i < (fdi->out + 7) / 8; i++) + *mbuf++ = raw[i]; + off = fdi->out & 7; +#if 1 + if (off > 0) { + mbuf--; + *mbuf &= ~((1 << (8 - off)) - 1); + } + j = 0; + while (i < (fdi->out + 7) / 8 + 600) { + *mbuf++ |= (raw[j] >> off) | ((raw[j + 1]) << (8 - off)); + j++; + i++; + } +#endif + mbuf = bigmfmbuf; + + memset (sectable, 0, sizeof (sectable)); + //memcpy (mbuf + fwlen, mbuf, fwlen * sizeof (uae_u16)); + mend = bigmfmbuf + length; + mend -= (4 + 16 + 8 + 512); + + while (secwritten < drvsec) { + int trackoffs; + + for (;;) { + rotateonebit (bigmfmbuf, mend, 1); + if (getmfmword (mbuf) == 0) + break; + if (secwritten == 10) { + mbuf[0] = 0x44; + mbuf[1] = 0x89; + } +// check_offset++; + if (check_offset > 7) { + check_offset = 0; + mbuf++; + if (mbuf >= mend || *mbuf == 0) + break; + } + if (getmfmword (mbuf) == 0x4489) + break; + } + if (mbuf >= mend || *mbuf == 0) + break; + + rotateonebit (bigmfmbuf, mend, check_offset); + check_offset = 0; + + while (getmfmword (mbuf) == 0x4489) + mbuf+= 1 * 2; + mbuf2 = mbuf + 8; + + odd = getmfmlong (mbuf); + even = getmfmlong (mbuf + 2 * 2); + mbuf += 4 * 2; + id = (odd << 1) | even; + + trackoffs = (id & 0xff00) >> 8; + if (trackoffs + 1 > drvsec) { + outlog("illegal sector offset %d\n",trackoffs); + ok = 0; + mbuf = mbuf2; + continue; + } + if ((id >> 24) != 0xff) { + outlog ("sector %d format type %02.2X?\n", trackoffs, id >> 24); + ok = 0; + } + chksum = odd ^ even; + slabel = 0; + for (i = 0; i < 4; i++) { + odd = getmfmlong (mbuf); + even = getmfmlong (mbuf + 8 * 2); + mbuf += 2* 2; + + dlong = (odd << 1) | even; + if (dlong) slabel = 1; + chksum ^= odd ^ even; + } + mbuf += 8 * 2; + odd = getmfmlong (mbuf); + even = getmfmlong (mbuf + 2 * 2); + mbuf += 4 * 2; + if (((odd << 1) | even) != chksum) { + outlog("sector %d header crc error\n", trackoffs); + ok = 0; + mbuf = mbuf2; + continue; + } + outlog("sector %d header crc ok\n", trackoffs); + if (((id & 0x00ff0000) >> 16) != (uae_u32)fdi->current_track) { + outlog("illegal track number %d <> %d\n",fdi->current_track,(id & 0x00ff0000) >> 16); + ok++; + mbuf = mbuf2; + continue; + } + odd = getmfmlong (mbuf); + even = getmfmlong (mbuf + 2 * 2); + mbuf += 4 * 2; + chksum = (odd << 1) | even; + secdata = secbuf + 32; + for (i = 0; i < 128; i++) { + odd = getmfmlong (mbuf); + even = getmfmlong (mbuf + 256 * 2); + mbuf += 2 * 2; + dlong = (odd << 1) | even; + *secdata++ = (uae_u8) (dlong >> 24); + *secdata++ = (uae_u8) (dlong >> 16); + *secdata++ = (uae_u8) (dlong >> 8); + *secdata++ = (uae_u8) dlong; + chksum ^= odd ^ even; + } + mbuf += 256 * 2; + if (chksum) { + outlog("sector %d data checksum error\n",trackoffs); + ok = 0; + } else if (sectable[trackoffs]) { + outlog("sector %d already found?\n", trackoffs); + mbuf = mbuf2; + } else { + outlog("sector %d ok\n",trackoffs); + if (slabel) outlog("(non-empty sector header)\n"); + sectable[trackoffs] = 1; + secwritten++; + if (trackoffs == 9) + mbuf += 0x228; + } + } + for (i = 0; i < drvsec; i++) { + if (!sectable[i]) { + outlog ("sector %d missing\n", i); + ok = 0; + } + } + return ok; +} +#endif + +static void amiga_data_raw (FDI *fdi, uae_u8 *secbuf, uae_u8 *crc, int len) +{ + int i; + uae_u8 crcbuf[4]; + + if (!crc) { + memset (crcbuf, 0, 4); + } else { + memcpy (crcbuf, crc ,4); + } + for (i = 0; i < 4; i++) + byte_mfm_add (fdi, crcbuf[i]); + for (i = 0; i < len; i++) + byte_mfm_add (fdi, secbuf[i]); +} + +static void amiga_data (FDI *fdi, uae_u8 *secbuf) +{ + uae_u16 mfmbuf[4 + 512]; + uae_u32 dodd, deven, dck; + int i; + + for (i = 0; i < 512; i += 4) { + deven = ((secbuf[i + 0] << 24) | (secbuf[i + 1] << 16) + | (secbuf[i + 2] << 8) | (secbuf[i + 3])); + dodd = deven >> 1; + deven &= 0x55555555; + dodd &= 0x55555555; + mfmbuf[(i >> 1) + 4] = (uae_u16) (dodd >> 16); + mfmbuf[(i >> 1) + 5] = (uae_u16) dodd; + mfmbuf[(i >> 1) + 256 + 4] = (uae_u16) (deven >> 16); + mfmbuf[(i >> 1) + 256 + 5] = (uae_u16) deven; + } + dck = 0; + for (i = 4; i < 4 + 512; i += 2) + dck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1]; + deven = dodd = dck; + dodd >>= 1; + deven &= 0x55555555; + dodd &= 0x55555555; + mfmbuf[0] = (uae_u16) (dodd >> 16); + mfmbuf[1] = (uae_u16) dodd; + mfmbuf[2] = (uae_u16) (deven >> 16); + mfmbuf[3] = (uae_u16) deven; + + for (i = 0; i < 4 + 512; i ++) + word_post_mfm_add (fdi, mfmbuf[i]); +} + +static void amiga_sector_header (FDI *fdi, uae_u8 *header, uae_u8 *data, int sector, int untilgap) +{ + uae_u8 headerbuf[4], databuf[16]; + uae_u32 deven, dodd, hck; + uae_u16 mfmbuf[24]; + int i; + + byte_mfm_add (fdi, 0); + byte_mfm_add (fdi, 0); + word_add (fdi, 0x4489); + word_add (fdi, 0x4489); + if (header) { + memcpy (headerbuf, header, 4); + } else { + headerbuf[0] = 0xff; + headerbuf[1] = (uae_u8)fdi->current_track; + headerbuf[2] = (uae_u8)sector; + headerbuf[3] = (uae_u8)untilgap; + } + if (data) + memcpy (databuf, data, 16); + else + memset (databuf, 0, 16); + + deven = ((headerbuf[0] << 24) | (headerbuf[1] << 16) + | (headerbuf[2] << 8) | (headerbuf[3])); + dodd = deven >> 1; + deven &= 0x55555555; + dodd &= 0x55555555; + mfmbuf[0] = (uae_u16) (dodd >> 16); + mfmbuf[1] = (uae_u16) dodd; + mfmbuf[2] = (uae_u16) (deven >> 16); + mfmbuf[3] = (uae_u16) deven; + for (i = 0; i < 16; i += 4) { + deven = ((databuf[i] << 24) | (databuf[i + 1] << 16) + | (databuf[i + 2] << 8) | (databuf[i + 3])); + dodd = deven >> 1; + deven &= 0x55555555; + dodd &= 0x55555555; + mfmbuf[(i >> 1) + 0 + 4] = (uae_u16) (dodd >> 16); + mfmbuf[(i >> 1) + 0 + 5] = (uae_u16) dodd; + mfmbuf[(i >> 1) + 8 + 4] = (uae_u16) (deven >> 16); + mfmbuf[(i >> 1) + 8 + 5] = (uae_u16) deven; + } + hck = 0; + for (i = 0; i < 4 + 16; i += 2) + hck ^= (mfmbuf[i] << 16) | mfmbuf[i + 1]; + deven = dodd = hck; + dodd >>= 1; + deven &= 0x55555555; + dodd &= 0x55555555; + mfmbuf[20] = (uae_u16) (dodd >> 16); + mfmbuf[21] = (uae_u16) dodd; + mfmbuf[22] = (uae_u16) (deven >> 16); + mfmbuf[23] = (uae_u16) deven; + + for (i = 0; i < 4 + 16 + 4; i ++) + word_post_mfm_add (fdi, mfmbuf[i]); +} + +/* standard super-extended Amiga sector header */ +static void s20(FDI *fdi) +{ + bit_drop_next (fdi); + debuglog ("s20:header=%s,data=%s", datalog(fdi->track_src, 4), datalog(fdi->track_src + 4, 16)); + amiga_sector_header (fdi, fdi->track_src, fdi->track_src + 4, 0, 0); + fdi->track_src += 4 + 16; +} +/* standard extended Amiga sector header */ +static void s21(FDI *fdi) +{ + bit_drop_next (fdi); + debuglog ("s21:header=%s", datalog(fdi->track_src, 4)); + amiga_sector_header (fdi, fdi->track_src, 0, 0, 0); + fdi->track_src += 4; +} +/* standard Amiga sector header */ +static void s22(FDI *fdi) +{ + bit_drop_next (fdi); + debuglog("s22:sector=%d,untilgap=%d", fdi->track_src[0], fdi->track_src[1]); + amiga_sector_header (fdi, 0, 0, fdi->track_src[0], fdi->track_src[1]); + fdi->track_src += 2; +} +/* standard 512-byte, CRC-correct Amiga data */ +static void s23(FDI *fdi) +{ + debuglog("s23:data=%s", datalog (fdi->track_src, 512)); + amiga_data (fdi, fdi->track_src); + fdi->track_src += 512; +} +/* not-decoded, 128*2^x-byte, CRC-correct Amiga data */ +static void s24(FDI *fdi) +{ + int shift = *fdi->track_src++; + debuglog("s24:shift=%d,data=%s", shift, datalog (fdi->track_src, 128 << shift)); + amiga_data_raw (fdi, fdi->track_src, 0, 128 << shift); + fdi->track_src += 128 << shift; +} +/* not-decoded, 128*2^x-byte, CRC-incorrect Amiga data */ +static void s25(FDI *fdi) +{ + int shift = *fdi->track_src++; + debuglog("s25:shift=%d,crc=%s,data=%s", shift, datalog (fdi->track_src, 4), datalog (fdi->track_src + 4, 128 << shift)); + amiga_data_raw (fdi, fdi->track_src + 4, fdi->track_src, 128 << shift); + fdi->track_src += 4 + (128 << shift); +} +/* standard extended Amiga sector */ +static void s26(FDI *fdi) +{ + s21 (fdi); + debuglog("s26:data=%s", datalog (fdi->track_src, 512)); + amiga_data (fdi, fdi->track_src); + fdi->track_src += 512; +} +/* standard short Amiga sector */ +static void s27(FDI *fdi) +{ + s22 (fdi); + debuglog("s27:data=%s", datalog (fdi->track_src, 512)); + amiga_data (fdi, fdi->track_src); + fdi->track_src += 512; +} + +/* *** */ +/* IBM */ +/* *** */ + +static uae_u16 ibm_crc (uae_u8 byte, int reset) +{ + static uae_u16 crc; + int i; + + if (reset) crc = 0xcdb4; + for (i = 0; i < 8; i++) { + if (crc & 0x8000) { + crc <<= 1; + if (!(byte & 0x80)) crc ^= 0x1021; + } else { + crc <<= 1; + if (byte & 0x80) crc ^= 0x1021; + } + byte <<= 1; + } + return crc; +} + +static void ibm_data (FDI *fdi, uae_u8 *data, uae_u8 *crc, int len) +{ + int i; + uae_u8 crcbuf[2]; + uae_u16 crcv = 0; + + word_add (fdi, 0x4489); + word_add (fdi, 0x4489); + word_add (fdi, 0x4489); + byte_mfm_add (fdi, 0xfb); + ibm_crc (0xfb, 1); + for (i = 0; i < len; i++) { + byte_mfm_add (fdi, data[i]); + crcv = ibm_crc (data[i], 0); + } + if (!crc) { + crc = crcbuf; + crc[0] = (uae_u8)(crcv >> 8); + crc[1] = (uae_u8)crcv; + } + byte_mfm_add (fdi, crc[0]); + byte_mfm_add (fdi, crc[1]); +} + +static void ibm_sector_header (FDI *fdi, uae_u8 *data, uae_u8 *crc, int secnum, int pre) +{ + uae_u8 secbuf[5]; + uae_u8 crcbuf[2]; + uae_u16 crcv; + int i; + + if (pre) + bytes_mfm_add (fdi, 0, 12); + word_add (fdi, 0x4489); + word_add (fdi, 0x4489); + word_add (fdi, 0x4489); + secbuf[0] = 0xfe; + if (secnum >= 0) { + secbuf[1] = (uae_u8)(fdi->current_track/2); + secbuf[2] = (uae_u8)(fdi->current_track%2); + secbuf[3] = (uae_u8)secnum; + secbuf[4] = 2; + } else { + memcpy (secbuf + 1, data, 4); + } + ibm_crc (secbuf[0], 1); + ibm_crc (secbuf[1], 0); + ibm_crc (secbuf[2], 0); + ibm_crc (secbuf[3], 0); + crcv = ibm_crc (secbuf[4], 0); + if (crc) { + memcpy (crcbuf, crc, 2); + } else { + crcbuf[0] = (uae_u8)(crcv >> 8); + crcbuf[1] = (uae_u8)crcv; + } + /* data */ + for (i = 0;i < 5; i++) + byte_mfm_add (fdi, secbuf[i]); + /* crc */ + byte_mfm_add (fdi, crcbuf[0]); + byte_mfm_add (fdi, crcbuf[1]); +} + +/* standard IBM index address mark */ +static void s10(FDI *fdi) +{ + bit_drop_next (fdi); + bytes_mfm_add (fdi, 0, 12); + word_add (fdi, 0x5224); + word_add (fdi, 0x5224); + word_add (fdi, 0x5224); + byte_mfm_add (fdi, 0xfc); +} +/* standard IBM pre-gap */ +static void s11(FDI *fdi) +{ + bit_drop_next (fdi); + bytes_mfm_add (fdi, 0x4e, 78); + bit_dedrop (fdi); + s10 (fdi); + bytes_mfm_add (fdi, 0x4e, 50); +} +/* standard ST pre-gap */ +static void s12(FDI *fdi) +{ + bit_drop_next (fdi); + bytes_mfm_add (fdi, 0x4e, 78); +} +/* standard extended IBM sector header */ +static void s13(FDI *fdi) +{ + bit_drop_next (fdi); + debuglog ("s13:header=%s", datalog (fdi->track_src, 4)); + ibm_sector_header (fdi, fdi->track_src, 0, -1, 1); + fdi->track_src += 4; +} +/* standard mini-extended IBM sector header */ +static void s14(FDI *fdi) +{ + debuglog ("s14:header=%s", datalog (fdi->track_src, 4)); + ibm_sector_header (fdi, fdi->track_src, 0, -1, 0); + fdi->track_src += 4; +} +/* standard short IBM sector header */ +static void s15(FDI *fdi) +{ + bit_drop_next (fdi); + debuglog ("s15:sector=%d", *fdi->track_src); + ibm_sector_header (fdi, 0, 0, *fdi->track_src++, 1); +} +/* standard mini-short IBM sector header */ +static void s16(FDI *fdi) +{ + debuglog ("s16:track=%d", *fdi->track_src); + ibm_sector_header (fdi, 0, 0, *fdi->track_src++, 0); +} +/* standard CRC-incorrect mini-extended IBM sector header */ +static void s17(FDI *fdi) +{ + debuglog ("s17:header=%s,crc=%s", datalog (fdi->track_src, 4), datalog (fdi->track_src + 4, 2)); + ibm_sector_header (fdi, fdi->track_src, fdi->track_src + 4, -1, 0); + fdi->track_src += 4 + 2; +} +/* standard CRC-incorrect mini-short IBM sector header */ +static void s18(FDI *fdi) +{ + debuglog ("s18:sector=%d,header=%s", *fdi->track_src, datalog (fdi->track_src + 1, 4)); + ibm_sector_header (fdi, 0, fdi->track_src + 1, *fdi->track_src, 0); + fdi->track_src += 1 + 4; +} +/* standard 512-byte CRC-correct IBM data */ +static void s19(FDI *fdi) +{ + debuglog ("s19:data=%s", datalog (fdi->track_src , 512)); + ibm_data (fdi, fdi->track_src, 0, 512); + fdi->track_src += 512; +} +/* standard 128*2^x-byte-byte CRC-correct IBM data */ +static void s1a(FDI *fdi) +{ + int shift = *fdi->track_src++; + debuglog ("s1a:shift=%d,data=%s", shift, datalog (fdi->track_src , 128 << shift)); + ibm_data (fdi, fdi->track_src, 0, 128 << shift); + fdi->track_src += 128 << shift; +} +/* standard 128*2^x-byte-byte CRC-incorrect IBM data */ +static void s1b(FDI *fdi) +{ + int shift = *fdi->track_src++; + debuglog ("s1b:shift=%d,crc=%s,data=%s", shift, datalog (fdi->track_src + (128 << shift), 2), datalog (fdi->track_src , 128 << shift)); + ibm_data (fdi, fdi->track_src, fdi->track_src + (128 << shift), 128 << shift); + fdi->track_src += (128 << shift) + 2; +} +/* standard extended IBM sector */ +static void s1c(FDI *fdi) +{ + int shift = fdi->track_src[3]; + s13 (fdi); + bytes_mfm_add (fdi, 0x4e, 22); + bytes_mfm_add (fdi, 0x00, 12); + ibm_data (fdi, fdi->track_src, 0, 128 << shift); + fdi->track_src += 128 << shift; +} +/* standard short IBM sector */ +static void s1d(FDI *fdi) +{ + s15 (fdi); + bytes_mfm_add (fdi, 0x4e, 22); + bytes_mfm_add (fdi, 0x00, 12); + s19 (fdi); +} + +/* end marker */ +static void sff(FDI *fdi) +{ +} + +typedef void (*decode_described_track_func)(FDI*); + +static decode_described_track_func decode_sectors_described_track[] = +{ + s00,s01,s02,s03,s04,dxx,dxx,dxx,s08,s09,s0a,s0b,s0c,s0d,dxx,dxx, /* 00-0F */ + s10,s11,s12,s13,s14,s15,s16,s17,s18,s19,s1a,s1b,s1c,s1d,dxx,dxx, /* 10-1F */ + s20,s21,s22,s23,s24,s25,s26,s27,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 20-2F */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 30-3F */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 40-4F */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 50-5F */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 60-6F */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 70-7F */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 80-8F */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* 90-9F */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* A0-AF */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* B0-BF */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* C0-CF */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* D0-DF */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx, /* E0-EF */ + dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,dxx,sff /* F0-FF */ +}; + +static void track_amiga (struct fdi *fdi, int first_sector, int max_sector) +{ + int i; + + bit_add (fdi, 0); + bit_drop_next (fdi); + for (i = 0; i < max_sector; i++) { + amiga_sector_header (fdi, 0, 0, first_sector, max_sector - i); + amiga_data (fdi, fdi->track_src + first_sector * 512); + first_sector++; + if (first_sector >= max_sector) first_sector = 0; + } + bytes_mfm_add (fdi, 0, 260); /* gap */ +} +static void track_atari_st (struct fdi *fdi, int max_sector) +{ + int i, gap3 = 0; + uae_u8 *p = fdi->track_src; + + switch (max_sector) + { + case 9: + gap3 = 40; + break; + case 10: + gap3 = 24; + break; + } + s15 (fdi); + for (i = 0; i < max_sector; i++) { + byte_mfm_add (fdi, 0x4e); + byte_mfm_add (fdi, 0x4e); + ibm_sector_header (fdi, 0, 0, fdi->current_track, 1); + ibm_data (fdi, p + i * 512, 0, 512); + bytes_mfm_add (fdi, 0x4e, gap3); + } + bytes_mfm_add (fdi, 0x4e, 660 - gap3); + fdi->track_src += fdi->track_len * 256; +} +static void track_pc (struct fdi *fdi, int max_sector) +{ + int i, gap3; + uae_u8 *p = fdi->track_src; + + switch (max_sector) + { + case 8: + gap3 = 116; + break; + case 9: + gap3 = 54; + break; + default: + gap3 = 100; /* fixme */ + break; + } + s11 (fdi); + for (i = 0; i < max_sector; i++) { + byte_mfm_add (fdi, 0x4e); + byte_mfm_add (fdi, 0x4e); + ibm_sector_header (fdi, 0, 0, fdi->current_track, 1); + ibm_data (fdi, p + i * 512, 0, 512); + bytes_mfm_add (fdi, 0x4e, gap3); + } + bytes_mfm_add (fdi, 0x4e, 600 - gap3); + fdi->track_src += fdi->track_len * 256; +} + +/* amiga dd */ +static void track_amiga_dd (struct fdi *fdi) +{ + uae_u8 *p = fdi->track_src; + track_amiga (fdi, fdi->track_len >> 4, 11); + fdi->track_src = p + (fdi->track_len & 15) * 512; +} +/* amiga hd */ +static void track_amiga_hd (struct fdi *fdi) +{ + uae_u8 *p = fdi->track_src; + track_amiga (fdi, 0, 22); + fdi->track_src = p + fdi->track_len * 256; +} +/* atari st 9 sector */ +static void track_atari_st_9 (struct fdi *fdi) +{ + track_atari_st (fdi, 9); +} +/* atari st 10 sector */ +static void track_atari_st_10 (struct fdi *fdi) +{ + track_atari_st (fdi, 10); +} +/* pc 8 sector */ +static void track_pc_8 (struct fdi *fdi) +{ + track_pc (fdi, 8); +} +/* pc 9 sector */ +static void track_pc_9 (struct fdi *fdi) +{ + track_pc (fdi, 9); +} +/* pc 15 sector */ +static void track_pc_15 (struct fdi *fdi) +{ + track_pc (fdi, 15); +} +/* pc 18 sector */ +static void track_pc_18 (struct fdi *fdi) +{ + track_pc (fdi, 18); +} +/* pc 36 sector */ +static void track_pc_36 (struct fdi *fdi) +{ + track_pc (fdi, 36); +} + +typedef void (*decode_normal_track_func)(FDI*); + +static decode_normal_track_func decode_normal_track[] = +{ + track_empty, /* 0 */ + track_amiga_dd, track_amiga_hd, /* 1-2 */ + track_atari_st_9, track_atari_st_10, /* 3-4 */ + track_pc_8, track_pc_9, track_pc_15, track_pc_18, track_pc_36, /* 5-9 */ + zxx,zxx,zxx,zxx,zxx /* A-F */ +}; + +static void fix_mfm_sync (FDI *fdi) +{ + int i, pos, off1, off2, off3, mask1, mask2, mask3; + + for (i = 0; i < fdi->mfmsync_offset; i++) { + pos = fdi->mfmsync_buffer[i]; + off1 = (pos - 1) >> 3; + off2 = (pos + 1) >> 3; + off3 = pos >> 3; + mask1 = 1 << (7 - ((pos - 1) & 7)); + mask2 = 1 << (7 - ((pos + 1) & 7)); + mask3 = 1 << (7 - (pos & 7)); + if (!(fdi->track_dst[off1] & mask1) && !(fdi->track_dst[off2] & mask2)) + fdi->track_dst[off3] |= mask3; + else + fdi->track_dst[off3] &= ~mask3; + } +} + +static int handle_sectors_described_track (FDI *fdi) +{ + int oldout; + uae_u8 *start_src = fdi->track_src ; + fdi->encoding_type = *fdi->track_src++; + fdi->index_offset = get_u32(fdi->track_src); + fdi->index_offset >>= 8; + fdi->track_src += 3; + outlog ("sectors_described, index offset: %d\n",fdi->index_offset); + + do { + fdi->track_type = *fdi->track_src++; + outlog ("%06.6X %06.6X %02.2X:",fdi->track_src - start_src + 0x200, fdi->out/8, fdi->track_type); + oldout = fdi->out; + decode_sectors_described_track[fdi->track_type](fdi); + outlog(" %d\n", fdi->out - oldout); + oldout = fdi->out; + if (fdi->out < 0 || fdi->err) { + outlog ("\nin %d bytes, out %d bits\n", fdi->track_src - fdi->track_src_buffer, fdi->out); + return -1; + } + if (fdi->track_src - fdi->track_src_buffer >= fdi->track_src_len) { + outlog ("source buffer overrun, previous type: %02.2X\n", fdi->track_type); + return -1; + } + } while (fdi->track_type != 0xff); + outlog("\n"); + fix_mfm_sync (fdi); + return fdi->out; +} + +static uae_u8 *fdi_decompress (int pulses, uae_u8 *sizep, uae_u8 *src, int *dofree) +{ + uae_u32 size = get_u24 (sizep); + uae_u32 *dst2; + int len = size & 0x3fffff; + uae_u8 *dst; + int mode = size >> 22, i; + + *dofree = 0; + if (mode == 0 && pulses * 2 > len) + mode = 1; + if (mode == 0) { + dst2 = (uae_u32*)src; + dst = src; + for (i = 0; i < pulses; i++) { + *dst2++ = get_u32 (src); + src += 4; + } + } else if (mode == 1) { + dst = fdi_malloc (pulses *4); + *dofree = 1; + fdi_decode (src, pulses, dst); + } else { + dst = 0; + } + return dst; +} + +static void dumpstream(int track, uae_u8 *stream, int len) +{ +#if 0 + char name[100]; + FILE *f; + + sprintf (name, "track_%d.raw", track); + f = fopen(name, "wb"); + fwrite (stream, 1, len * 4, f); + fclose (f); +#endif +} + +static int bitoffset; + +STATIC_INLINE void addbit (uae_u8 *p, int bit) +{ + int off1 = bitoffset / 8; + int off2 = bitoffset % 8; + p[off1] |= bit << (7 - off2); + bitoffset++; +} + + +struct pulse_sample { + uint32_t size; + int number_of_bits; +}; + + +#define FDI_MAX_ARRAY 10 /* change this value as you want */ +static int pulse_limitval = 15; /* tolerance of 15% */ +static struct pulse_sample psarray[FDI_MAX_ARRAY]; +static int array_index; +static unsigned long total; +static int totaldiv; + +static void init_array(uint32_t standard_MFM_2_bit_cell_size, int nb_of_bits) +{ + int i; + + for (i = 0; i < FDI_MAX_ARRAY; i++) { + psarray[i].size = standard_MFM_2_bit_cell_size; // That is (total track length / 50000) for Amiga double density + total += psarray[i].size; + psarray[i].number_of_bits = nb_of_bits; + totaldiv += psarray[i].number_of_bits; + } + array_index = 0; +} + +#if 0 + +static void fdi2_decode (FDI *fdi, uint32_t totalavg, uae_u32 *avgp, uae_u32 *minp, uae_u32 *maxp, uae_u8 *idx, int maxidx, int *indexoffsetp, int pulses, int mfm) +{ + uint32_t adjust; + uint32_t adjusted_pulse; + uint32_t standard_MFM_2_bit_cell_size = totalavg / 50000; + uint32_t standard_MFM_8_bit_cell_size = totalavg / 12500; + int real_size, i, j, eodat, outstep; + int indexoffset = *indexoffsetp; + uae_u8 *d = fdi->track_dst_buffer; + uae_u16 *pt = fdi->track_dst_buffer_timing; + uae_u32 ref_pulse, pulse; + + /* detects a long-enough stable pulse coming just after another stable pulse */ + i = 1; + while ( (i < pulses) && ( (idx[i] < maxidx) + || (idx[i - 1] < maxidx) + || (avgp[i] < (standard_MFM_2_bit_cell_size - (standard_MFM_2_bit_cell_size / 4))) ) ) + i++; + if (i == pulses) { + outlog ("No stable and long-enough pulse in track.\n"); + return; + } + i--; + eodat = i; + adjust = 0; + total = 0; + totaldiv = 0; + init_array(standard_MFM_2_bit_cell_size, 2); + bitoffset = 0; + ref_pulse = 0; + outstep = 0; + while (outstep < 2) { + + /* calculates the current average bitrate from previous decoded data */ + uae_u32 avg_size = (total << 3) / totaldiv; /* this is the new average size for one MFM bit */ + /* uae_u32 avg_size = (uae_u32)((((float)total)*8.0) / ((float)totaldiv)); */ + /* you can try tighter ranges than 25%, or wider ranges. I would probably go for tighter... */ + if ((avg_size < (standard_MFM_8_bit_cell_size - (pulse_limitval * standard_MFM_8_bit_cell_size / 100))) || + (avg_size > (standard_MFM_8_bit_cell_size + (pulse_limitval * standard_MFM_8_bit_cell_size / 100)))) { + //init_array(standard_MFM_2_bit_cell_size, 2); + avg_size = standard_MFM_8_bit_cell_size; + } + /* this is to prevent the average value from going too far + * from the theoretical value, otherwise it could progressively go to (2 * + * real value), or (real value / 2), etc. */ + + /* gets the next long-enough pulse (this may require more than one pulse) */ + pulse = 0; + while (pulse < ((avg_size / 4) - (avg_size / 16))) { + int indx; + i++; + if (i >= pulses) + i = 0; + indx = idx[i]; + if (rand() <= (indx * RAND_MAX) / maxidx) { + pulse += avgp[i] - ref_pulse; + if (indx >= maxidx) + ref_pulse = 0; + else + ref_pulse = avgp[i]; + } + if (i == eodat) + outstep++; + if (outstep == 1 && indexoffset == i) + *indexoffsetp = bitoffset; + } + + /* gets the size in bits from the pulse width, considering the current average bitrate */ + adjusted_pulse = pulse; + real_size = 0; + while (adjusted_pulse >= avg_size) { + real_size += 4; + adjusted_pulse -= avg_size / 2; + } + adjusted_pulse <<= 3; + while (adjusted_pulse >= ((avg_size * 4) + (avg_size / 4))) { + real_size += 2; + adjusted_pulse -= avg_size * 2; + } + if (adjusted_pulse >= ((avg_size * 3) + (avg_size / 4))) { + if (adjusted_pulse <= ((avg_size * 4) - (avg_size / 4))) { + if ((2 * ((adjusted_pulse >> 2) - adjust)) <= ((2 * avg_size) - (avg_size / 4))) + real_size += 3; + else + real_size += 4; + } else + real_size += 4; + } else { + if (adjusted_pulse > ((avg_size * 3) - (avg_size / 4))) { + real_size += 3; + } else { + if (adjusted_pulse >= ((avg_size * 2) + (avg_size / 4))) { + if ((2 * ((adjusted_pulse >> 2) - adjust)) < (avg_size + (avg_size / 4))) + real_size += 2; + else + real_size += 3; + } else + real_size += 2; + } + } + + if (outstep == 1) { + for (j = real_size; j > 1; j--) + addbit (d, 0); + addbit (d, 1); + for (j = 0; j < real_size; j++) + *pt++ = (uae_u16)(pulse / real_size); + } + + /* prepares for the next pulse */ + adjust = ((real_size * avg_size)/8) - pulse; + total -= psarray[array_index].size; + totaldiv -= psarray[array_index].number_of_bits; + psarray[array_index].size = pulse; + psarray[array_index].number_of_bits = real_size; + total += pulse; + totaldiv += real_size; + array_index++; + if (array_index >= FDI_MAX_ARRAY) + array_index = 0; + } + + fdi->out = bitoffset; +} + +#else + +static void fdi2_decode (FDI *fdi, uint32_t totalavg, uae_u32 *avgp, uae_u32 *minp, uae_u32 *maxp, uae_u8 *idx, int maxidx, int *indexoffsetp, int pulses, int mfm) +{ + uint32_t adjust; + uint32_t adjusted_pulse; + uint32_t standard_MFM_2_bit_cell_size = totalavg / 50000; + uint32_t standard_MFM_8_bit_cell_size = totalavg / 12500; + int real_size, i, j, nexti, eodat, outstep, randval; + int indexoffset = *indexoffsetp; + uae_u8 *d = fdi->track_dst_buffer; + uae_u16 *pt = fdi->track_dst_buffer_timing; + uae_u32 ref_pulse, pulse; + long jitter; + + /* detects a long-enough stable pulse coming just after another stable pulse */ + i = 1; + while ( (i < pulses) && ( (idx[i] < maxidx) + || (idx[i - 1] < maxidx) + || (minp[i] < (standard_MFM_2_bit_cell_size - (standard_MFM_2_bit_cell_size / 4))) ) ) + i++; + if (i == pulses) { + outlog ("FDI: No stable and long-enough pulse in track.\n"); + return; + } + nexti = i; + eodat = i; + i--; + adjust = 0; + total = 0; + totaldiv = 0; + init_array(standard_MFM_2_bit_cell_size, 1 + mfm); + bitoffset = 0; + ref_pulse = 0; + jitter = 0; + outstep = -1; + while (outstep < 2) { + + /* calculates the current average bitrate from previous decoded data */ + uae_u32 avg_size = (total << (2 + mfm)) / totaldiv; /* this is the new average size for one MFM bit */ + /* uae_u32 avg_size = (uae_u32)((((float)total)*((float)(mfm+1))*4.0) / ((float)totaldiv)); */ + /* you can try tighter ranges than 25%, or wider ranges. I would probably go for tighter... */ + if ((avg_size < (standard_MFM_8_bit_cell_size - (pulse_limitval * standard_MFM_8_bit_cell_size / 100))) || + (avg_size > (standard_MFM_8_bit_cell_size + (pulse_limitval * standard_MFM_8_bit_cell_size / 100)))) { + //init_array(standard_MFM_2_bit_cell_size, mfm + 1); + avg_size = standard_MFM_8_bit_cell_size; + } + /* this is to prevent the average value from going too far + * from the theoretical value, otherwise it could progressively go to (2 * + * real value), or (real value / 2), etc. */ + + /* gets the next long-enough pulse (this may require more than one pulse) */ + pulse = 0; + while (pulse < ((avg_size / 4) - (avg_size / 16))) { + uae_u32 avg_pulse, min_pulse, max_pulse; + i++; + if (i >= pulses) + i = 0; + if (i == nexti) { + do { + nexti++; + if (nexti >= pulses) + nexti = 0; + } while (idx[nexti] < maxidx); + } + if (idx[i] >= maxidx) { /* stable pulse */ + avg_pulse = avgp[i] - jitter; + min_pulse = minp[i]; + max_pulse = maxp[i]; + if (jitter >= 0) + max_pulse -= jitter; + else + min_pulse -= jitter; + if ((maxp[nexti] - avgp[nexti]) < (avg_pulse - min_pulse)) + min_pulse = avg_pulse - (maxp[nexti] - avgp[nexti]); + if ((avgp[nexti] - minp[nexti]) < (max_pulse - avg_pulse)) + max_pulse = avg_pulse + (avgp[nexti] - minp[nexti]); + if (min_pulse < ref_pulse) + min_pulse = ref_pulse; + randval = rand(); + if (randval < (RAND_MAX / 2)) { + if (randval > (RAND_MAX / 4)) { + if (randval <= (3 * RAND_MAX / 8)) + randval = (2 * randval) - (RAND_MAX /4); + else + randval = (4 * randval) - RAND_MAX; + } + jitter = 0 - (randval * (avg_pulse - min_pulse)) / RAND_MAX; + } else { + randval -= RAND_MAX / 2; + if (randval > (RAND_MAX / 4)) { + if (randval <= (3 * RAND_MAX / 8)) + randval = (2 * randval) - (RAND_MAX /4); + else + randval = (4 * randval) - RAND_MAX; + } + jitter = (randval * (max_pulse - avg_pulse)) / RAND_MAX; + } + avg_pulse += jitter; + if ((avg_pulse < min_pulse) || (avg_pulse > max_pulse)) { + outlog ("FDI: avg_pulse outside bounds! avg=%u min=%u max=%u\n", avg_pulse, min_pulse, max_pulse); + outlog ("FDI: avgp=%u (%u) minp=%u (%u) maxp=%u (%u) jitter=%d i=%d ni=%d\n", + avgp[i], avgp[nexti], minp[i], minp[nexti], maxp[i], maxp[nexti], jitter, i, nexti); + } + if (avg_pulse < ref_pulse) + outlog ("FDI: avg_pulse < ref_pulse! (%u < %u)\n", avg_pulse, ref_pulse); + pulse += avg_pulse - ref_pulse; + ref_pulse = 0; + if (i == eodat) + outstep++; + } else if (rand() <= ((idx[i] * RAND_MAX) / maxidx)) { + avg_pulse = avgp[i]; + min_pulse = minp[i]; + max_pulse = maxp[i]; + randval = rand(); + if (randval < (RAND_MAX / 2)) { + if (randval > (RAND_MAX / 4)) { + if (randval <= (3 * RAND_MAX / 8)) + randval = (2 * randval) - (RAND_MAX /4); + else + randval = (4 * randval) - RAND_MAX; + } + avg_pulse -= (randval * (avg_pulse - min_pulse)) / RAND_MAX; + } else { + randval -= RAND_MAX / 2; + if (randval > (RAND_MAX / 4)) { + if (randval <= (3 * RAND_MAX / 8)) + randval = (2 * randval) - (RAND_MAX /4); + else + randval = (4 * randval) - RAND_MAX; + } + avg_pulse += (randval * (max_pulse - avg_pulse)) / RAND_MAX; + } + if ((avg_pulse > ref_pulse) && (avg_pulse < (avgp[nexti] - jitter))) { + pulse += avg_pulse - ref_pulse; + ref_pulse = avg_pulse; + } + } + if (outstep == 1 && indexoffset == i) + *indexoffsetp = bitoffset; + } + + /* gets the size in bits from the pulse width, considering the current average bitrate */ + adjusted_pulse = pulse; + real_size = 0; + if (mfm) { + while (adjusted_pulse >= avg_size) { + real_size += 4; + adjusted_pulse -= avg_size / 2; + } + adjusted_pulse <<= 3; + while (adjusted_pulse >= ((avg_size * 4) + (avg_size / 4))) { + real_size += 2; + adjusted_pulse -= avg_size * 2; + } + if (adjusted_pulse >= ((avg_size * 3) + (avg_size / 4))) { + if (adjusted_pulse <= ((avg_size * 4) - (avg_size / 4))) { + if ((2 * ((adjusted_pulse >> 2) - adjust)) <= ((2 * avg_size) - (avg_size / 4))) + real_size += 3; + else + real_size += 4; + } else + real_size += 4; + } else { + if (adjusted_pulse > ((avg_size * 3) - (avg_size / 4))) { + real_size += 3; + } else { + if (adjusted_pulse >= ((avg_size * 2) + (avg_size / 4))) { + if ((2 * ((adjusted_pulse >> 2) - adjust)) < (avg_size + (avg_size / 4))) + real_size += 2; + else + real_size += 3; + } else + real_size += 2; + } + } + } else { + while (adjusted_pulse >= (2*avg_size)) + { + real_size+=4; + adjusted_pulse-=avg_size; + } + adjusted_pulse<<=2; + while (adjusted_pulse >= ((avg_size*3)+(avg_size/4))) + { + real_size+=2; + adjusted_pulse-=avg_size*2; + } + if (adjusted_pulse >= ((avg_size*2)+(avg_size/4))) + { + if (adjusted_pulse <= ((avg_size*3)-(avg_size/4))) + { + if (((adjusted_pulse>>1)-adjust) < (avg_size+(avg_size/4))) + real_size+=2; + else + real_size+=3; + } + else + real_size+=3; + } + else + { + if (adjusted_pulse > ((avg_size*2)-(avg_size/4))) + real_size+=2; + else + { + if (adjusted_pulse >= (avg_size+(avg_size/4))) + { + if (((adjusted_pulse>>1)-adjust) <= (avg_size-(avg_size/4))) + real_size++; + else + real_size+=2; + } + else + real_size++; + } + } + } + + /* after one pass to correctly initialize the average bitrate, outputs the bits */ + if (outstep == 1) { + for (j = real_size; j > 1; j--) + addbit (d, 0); + addbit (d, 1); + for (j = 0; j < real_size; j++) + *pt++ = (uae_u16)(pulse / real_size); + } + + /* prepares for the next pulse */ + adjust = ((real_size * avg_size) / (4 << mfm)) - pulse; + total -= psarray[array_index].size; + totaldiv -= psarray[array_index].number_of_bits; + psarray[array_index].size = pulse; + psarray[array_index].number_of_bits = real_size; + total += pulse; + totaldiv += real_size; + array_index++; + if (array_index >= FDI_MAX_ARRAY) + array_index = 0; + } + + fdi->out = bitoffset; +} + +#endif + +static void fdi2_celltiming (FDI *fdi, uint32_t totalavg, int bitoffset, uae_u16 *out) +{ + uae_u16 *pt2, *pt; + double avg_bit_len; + int i; + + avg_bit_len = (double)totalavg / (double)bitoffset; + pt2 = fdi->track_dst_buffer_timing; + pt = out; + for (i = 0; i < bitoffset / 8; i++) { + double v = (pt2[0] + pt2[1] + pt2[2] + pt2[3] + pt2[4] + pt2[5] + pt2[6] + pt2[7]) / 8.0; + v = 1000.0 * v / avg_bit_len; + *pt++ = (uae_u16)v; + pt2 += 8; + } + *pt++ = out[0]; + *pt = out[0]; +} + +static int decode_lowlevel_track (FDI *fdi, int track, struct fdi_cache *cache) +{ + uae_u8 *p1, *d; + uae_u32 *p2; + uae_u32 *avgp, *minp = 0, *maxp = 0; + uae_u8 *idxp = 0; + uae_u32 maxidx, totalavg, weakbits; + int i, j, len, pulses, indexoffset; + int avg_free, min_free = 0, max_free = 0, idx_free; + int idx_off1, idx_off2, idx_off3; + + d = fdi->track_dst; + p1 = fdi->track_src; + pulses = get_u32 (p1); + if (!pulses) + return -1; + p1 += 4; + len = 12; + avgp = (uae_u32*)fdi_decompress (pulses, p1 + 0, p1 + len, &avg_free); + dumpstream(track, (uae_u8*)avgp, pulses); + len += get_u24 (p1 + 0) & 0x3fffff; + if (!avgp) + return -1; + if (get_u24 (p1 + 3) && get_u24 (p1 + 6)) { + minp = (uae_u32*)fdi_decompress (pulses, p1 + 3, p1 + len, &min_free); + len += get_u24 (p1 + 3) & 0x3fffff; + maxp = (uae_u32*)fdi_decompress (pulses, p1 + 6, p1 + len, &max_free); + len += get_u24 (p1 + 6) & 0x3fffff; + /* Computes the real min and max values */ + for (i = 0; i < pulses; i++) { + maxp[i] = avgp[i] + minp[i] - maxp[i]; + minp[i] = avgp[i] - minp[i]; + } + } else { + minp = avgp; + maxp = avgp; + } + if (get_u24 (p1 + 9)) { + idx_off1 = 0; + idx_off2 = 1; + idx_off3 = 2; + idxp = fdi_decompress (pulses, p1 + 9, p1 + len, &idx_free); + if (idx_free) { + if (idxp[0] == 0 && idxp[1] == 0) { + idx_off1 = 2; + idx_off2 = 3; + } else { + idx_off1 = 1; + idx_off2 = 0; + } + idx_off3 = 4; + } + } else { + idxp = fdi_malloc (pulses * 2); + idx_free = 1; + for (i = 0; i < pulses; i++) { + idxp[i * 2 + 0] = 2; + idxp[i * 2 + 1] = 0; + } + idxp[0] = 1; + idxp[1] = 1; + } + + maxidx = 0; + indexoffset = 0; + p1 = idxp; + for (i = 0; i < pulses; i++) { + if (p1[idx_off1] + p1[idx_off2] > maxidx) + maxidx = p1[idx_off1] + p1[idx_off2]; + p1 += idx_off3; + } + p1 = idxp; + for (i = 0; (i < pulses) && (p1[idx_off2] != 0); i++) /* falling edge, replace with idx_off1 for rising edge */ + p1 += idx_off3; + if (i < pulses) { + j = i; + do { + i++; + p1 += idx_off3; + if (i >= pulses) { + i = 0; + p1 = idxp; + } + } while ((i != j) && (p1[idx_off2] == 0)); /* falling edge, replace with idx_off1 for rising edge */ + if (i != j) /* index pulse detected */ + { + while ((i != j) && (p1[idx_off1] > p1[idx_off2])) { /* falling edge, replace with "<" for rising edge */ + i++; + p1 += idx_off3; + if (i >= pulses) { + i = 0; + p1 = idxp; + } + } + if (i != j) + indexoffset = i; /* index position detected */ + } + } + p1 = idxp; + p2 = avgp; + totalavg = 0; + weakbits = 0; + for (i = 0; i < pulses; i++) { + int sum = p1[idx_off1] + p1[idx_off2]; + if (sum >= maxidx) { + totalavg += *p2; + } else { + weakbits++; + } + p2++; + p1 += idx_off3; + idxp[i] = sum; + } + len = totalavg / 100000; + outlog("totalavg=%u index=%d (%d) maxidx=%d weakbits=%d len=%d\n", + totalavg, indexoffset, maxidx, weakbits, len); + cache->avgp = avgp; + cache->idxp = idxp; + cache->minp = minp; + cache->maxp = maxp; + cache->avg_free = avg_free; + cache->idx_free = idx_free; + cache->min_free = min_free; + cache->max_free = max_free; + cache->totalavg = totalavg; + cache->pulses = pulses; + cache->maxidx = maxidx; + cache->indexoffset = indexoffset; + cache->weakbits = weakbits; + cache->lowlevel = 1; + + return 1; +} + +static unsigned char fdiid[]={"Formatted Disk Image file"}; +static int bit_rate_table[16] = { 125,150,250,300,500,1000 }; + +void fdi2raw_header_free (FDI *fdi) +{ + int i; + + fdi_free (fdi->mfmsync_buffer); + fdi_free (fdi->track_src_buffer); + fdi_free (fdi->track_dst_buffer); + fdi_free (fdi->track_dst_buffer_timing); + for (i = 0; i < MAX_TRACKS; i++) { + struct fdi_cache *c = &fdi->cache[i]; + if (c->idx_free) + fdi_free (c->idxp); + if (c->avg_free) + fdi_free (c->avgp); + if (c->min_free) + fdi_free (c->minp); + if (c->max_free) + fdi_free (c->maxp); + } + fdi_free (fdi); + debuglog ("FREE: memory allocated %d\n", fdi_allocated); +} + +int fdi2raw_get_last_track (FDI *fdi) +{ + return fdi->last_track; +} + +int fdi2raw_get_num_sector (FDI *fdi) +{ + if (fdi->header[152] == 0x02) + return 22; + return 11; +} + +int fdi2raw_get_last_head (FDI *fdi) +{ + return fdi->last_head; +} + +int fdi2raw_get_rotation (FDI *fdi) +{ + return fdi->rotation_speed; +} + +int fdi2raw_get_bit_rate (FDI *fdi) +{ + return fdi->bit_rate; +} + +int fdi2raw_get_type (FDI *fdi) +{ + return fdi->disk_type; +} + +int fdi2raw_get_write_protect (FDI *fdi) +{ + return fdi->write_protect; +} + +FDI *fdi2raw_header(FILE *f) +{ + int i, offset, oldseek; + uae_u8 type, size; + FDI *fdi; + + debuglog ("ALLOC: memory allocated %d\n", fdi_allocated); + fdi = fdi_malloc(sizeof(FDI)); + memset (fdi, 0, sizeof (FDI)); + fdi->file = f; + oldseek = ftell (fdi->file); + fseek (fdi->file, 0, SEEK_SET); + fread (fdi->header, 2048, 1, fdi->file); + fseek (fdi->file, oldseek, SEEK_SET); + if (memcmp (fdiid, fdi->header, strlen ((char *)fdiid)) ) { + fdi_free(fdi); + return NULL; + } + if ((fdi->header[140] != 1 && fdi->header[140] != 2) || (fdi->header[141] != 0 && !(fdi->header[140]==2 && fdi->header[141]==1))) { + fdi_free(fdi); + return NULL; + } + + fdi->mfmsync_buffer = fdi_malloc (MAX_MFM_SYNC_BUFFER * sizeof(int)); + fdi->track_src_buffer = fdi_malloc (MAX_SRC_BUFFER); + fdi->track_dst_buffer = fdi_malloc (MAX_DST_BUFFER); + fdi->track_dst_buffer_timing = fdi_malloc (MAX_TIMING_BUFFER); + + fdi->last_track = ((fdi->header[142] << 8) + fdi->header[143]) + 1; + fdi->last_track *= fdi->header[144] + 1; + if (fdi->last_track > MAX_TRACKS) + fdi->last_track = MAX_TRACKS; + fdi->last_head = fdi->header[144]; + fdi->disk_type = fdi->header[145]; + fdi->rotation_speed = fdi->header[146] + 128; + fdi->write_protect = fdi->header[147] & 1; + outlog ("FDI version %d.%d\n", fdi->header[140], fdi->header[141]); + outlog ("last_track=%d rotation_speed=%d\n",fdi->last_track,fdi->rotation_speed); + + offset = 512; + i = fdi->last_track; + if (i > 180) { + offset += 512; + i -= 180; + while (i > 256) { + offset += 512; + i -= 256; + } + } + for (i = 0; i < fdi->last_track; i++) { + fdi->track_offsets[i] = offset; + type = fdi->header[152 + i * 2]; + size = fdi->header[152 + i * 2 + 1]; + if (type == 1) + offset += (size & 15) * 512; + else if ((type & 0xc0) == 0x80) + offset += (((type & 0x3f) << 8) | size) * 256; + else + offset += size * 256; + } + fdi->track_offsets[i] = offset; + + return fdi; +} + + +int fdi2raw_loadrevolution_2 (FDI *fdi, uae_u16 *mfmbuf, uae_u16 *tracktiming, int track, int *tracklength, int *indexoffsetp, int *multirev, int mfm) +{ + struct fdi_cache *cache = &fdi->cache[track]; + int len, i, idx; + + memset (fdi->track_dst_buffer, 0, MAX_DST_BUFFER); + idx = cache->indexoffset; + fdi2_decode (fdi, cache->totalavg, + cache->avgp, cache->minp, cache->maxp, cache->idxp, + cache->maxidx, &idx, cache->pulses, mfm); + //fdi2_gcr_decode (fdi, totalavg, avgp, minp, maxp, idxp, idx_off1, idx_off2, idx_off3, maxidx, pulses); + outlog("track %d: nbits=%d avg len=%.2f weakbits=%d idx=%d\n", + track, bitoffset, (double)cache->totalavg / bitoffset, cache->weakbits, cache->indexoffset); + len = fdi->out; + if (cache->weakbits >= 10 && multirev) + *multirev = 1; + *tracklength = len; + + for (i = 0; i < (len + 15) / (2 * 8); i++) { + uae_u8 *data = fdi->track_dst_buffer + i * 2; + *mfmbuf++ = 256 * *data + *(data + 1); + } + fdi2_celltiming (fdi, cache->totalavg, len, tracktiming); + if (indexoffsetp) + *indexoffsetp = idx; + return 1; +} + +int fdi2raw_loadrevolution (FDI *fdi, uae_u16 *mfmbuf, uae_u16 *tracktiming, int track, int *tracklength, int mfm) +{ + return fdi2raw_loadrevolution_2 (fdi, mfmbuf, tracktiming, track, tracklength, 0, 0, mfm); +} + +int fdi2raw_loadtrack (FDI *fdi, uae_u16 *mfmbuf, uae_u16 *tracktiming, int track, int *tracklength, int *indexoffsetp, int *multirev, int mfm) +{ + uae_u8 *p; + int outlen, i; + struct fdi_cache *cache = &fdi->cache[track]; + + if (cache->lowlevel) + return fdi2raw_loadrevolution_2 (fdi, mfmbuf, tracktiming, track, tracklength, indexoffsetp, multirev, mfm); + + fdi->err = 0; + fdi->track_src_len = fdi->track_offsets[track + 1] - fdi->track_offsets[track]; + fseek (fdi->file, fdi->track_offsets[track], SEEK_SET); + fread (fdi->track_src_buffer, fdi->track_src_len, 1, fdi->file); + memset (fdi->track_dst_buffer, 0, MAX_DST_BUFFER); + fdi->track_dst_buffer_timing[0] = 0; + + fdi->current_track = track; + fdi->track_src = fdi->track_src_buffer; + fdi->track_dst = fdi->track_dst_buffer; + p = fdi->header + 152 + fdi->current_track * 2; + fdi->track_type = *p++; + fdi->track_len = *p++; + fdi->bit_rate = 0; + fdi->out = 0; + fdi->mfmsync_offset = 0; + + if ((fdi->track_type & 0xf0) == 0xf0 || (fdi->track_type & 0xf0) == 0xe0) + fdi->bit_rate = bit_rate_table[fdi->track_type & 0x0f]; + else + fdi->bit_rate = 250; + + outlog ("track %d: srclen: %d track_type: %02.2X, bitrate: %d\n", + fdi->current_track, fdi->track_src_len, fdi->track_type, fdi->bit_rate); + + if ((fdi->track_type & 0xc0) == 0x80) { + + outlen = decode_lowlevel_track (fdi, track, cache); + + } else if ((fdi->track_type & 0xf0) == 0xf0) { + + outlen = decode_raw_track (fdi); + + } else if ((fdi->track_type & 0xf0) == 0xe0) { + + outlen = handle_sectors_described_track (fdi); + + } else if ((fdi->track_type & 0xf0)) { + + zxx (fdi); + outlen = -1; + + } else if (fdi->track_type < 0x10) { + + decode_normal_track[fdi->track_type](fdi); + fix_mfm_sync (fdi); + outlen = fdi->out; + + } else { + + zxx (fdi); + outlen = -1; + + } + +// amiga_check_track (fdi); + + if (fdi->err) + return 0; + + if (outlen > 0) { + if (cache->lowlevel) + return fdi2raw_loadrevolution_2 (fdi, mfmbuf, tracktiming, track, tracklength, indexoffsetp, multirev, mfm); + *tracklength = fdi->out; + for (i = 0; i < ((*tracklength) + 15) / (2 * 8); i++) { + uae_u8 *data = fdi->track_dst_buffer + i * 2; + *mfmbuf++ = 256 * *data + *(data + 1); + } + } + return outlen; +} + diff --git a/src/fdi2raw.h b/src/fdi2raw.h new file mode 100644 index 000000000..92e6ab1a3 --- /dev/null +++ b/src/fdi2raw.h @@ -0,0 +1,34 @@ +#ifndef __FDI2RAW_H +#define __FDI2RAW_H + +#define uae_u8 uint8_t +#define uae_u16 uint16_t +#define uae_u32 uint32_t + +//#include "types.h" +#include +typedef struct fdi FDI; + +#ifdef __cplusplus +extern "C" { +#endif + +extern int fdi2raw_loadtrack (FDI*, uae_u16 *mfmbuf, uae_u16 *tracktiming, int track, int *tracklength, int *indexoffset, int *multirev, int mfm); + +extern int fdi2raw_loadrevolution (FDI*, uae_u16 *mfmbuf, uae_u16 *tracktiming, int track, int *tracklength, int mfm); + +extern FDI *fdi2raw_header(FILE *f); +extern void fdi2raw_header_free (FDI *); +extern int fdi2raw_get_last_track(FDI *); +extern int fdi2raw_get_num_sector (FDI *); +extern int fdi2raw_get_last_head(FDI *); +extern int fdi2raw_get_type (FDI *); +extern int fdi2raw_get_bit_rate (FDI *); +extern int fdi2raw_get_rotation (FDI *); +extern int fdi2raw_get_write_protect (FDI *); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/filters.h b/src/filters.h new file mode 100644 index 000000000..8119101e1 --- /dev/null +++ b/src/filters.h @@ -0,0 +1,281 @@ +#define NCoef 2 + +//fc=350Hz +static inline float low_iir(int i, float NewSample) { + float ACoef[NCoef+1] = { + 0.00049713569693400649, + 0.00099427139386801299, + 0.00049713569693400649 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.93522955470669530000, + 0.93726236021404663000 + }; + + static float y[2][NCoef+1]; //output samples + static float x[2][NCoef+1]; //input samples + int n; + + //shift the old samples + for(n=NCoef; n>0; n--) { + x[i][n] = x[i][n-1]; + y[i][n] = y[i][n-1]; + } + + //Calculate the new output + x[i][0] = NewSample; + y[i][0] = ACoef[0] * x[i][0]; + for(n=1; n<=NCoef; n++) + y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; + + return y[i][0]; +} + +//fc=350Hz +static inline float low_cut_iir(int i, float NewSample) { + float ACoef[NCoef+1] = { + 0.96839970114733542000, + -1.93679940229467080000, + 0.96839970114733542000 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.93522955471202770000, + 0.93726236021916731000 + }; + + static float y[2][NCoef+1]; //output samples + static float x[2][NCoef+1]; //input samples + int n; + + //shift the old samples + for(n=NCoef; n>0; n--) { + x[i][n] = x[i][n-1]; + y[i][n] = y[i][n-1]; + } + + //Calculate the new output + x[i][0] = NewSample; + y[i][0] = ACoef[0] * x[i][0]; + for(n=1; n<=NCoef; n++) + y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; + + return y[i][0]; +} + +//fc=3.5kHz +static inline float high_iir(int i, float NewSample) { + float ACoef[NCoef+1] = { + 0.72248704753064896000, + -1.44497409506129790000, + 0.72248704753064896000 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.36640781670578510000, + 0.52352474706139873000 + }; + static float y[2][NCoef+1]; //output samples + static float x[2][NCoef+1]; //input samples + int n; + + //shift the old samples + for(n=NCoef; n>0; n--) { + x[i][n] = x[i][n-1]; + y[i][n] = y[i][n-1]; + } + + //Calculate the new output + x[i][0] = NewSample; + y[i][0] = ACoef[0] * x[i][0]; + for(n=1; n<=NCoef; n++) + y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; + + return y[i][0]; +} + +//fc=3.5kHz +static inline float high_cut_iir(int i, float NewSample) { + float ACoef[NCoef+1] = { + 0.03927726802250377400, + 0.07855453604500754700, + 0.03927726802250377400 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.36640781666419950000, + 0.52352474703279628000 + }; + static float y[2][NCoef+1]; //output samples + static float x[2][NCoef+1]; //input samples + int n; + + //shift the old samples + for(n=NCoef; n>0; n--) { + x[i][n] = x[i][n-1]; + y[i][n] = y[i][n-1]; + } + + //Calculate the new output + x[i][0] = NewSample; + y[i][0] = ACoef[0] * x[i][0]; + for(n=1; n<=NCoef; n++) + y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; + + return y[i][0]; +} + + +#undef NCoef +#define NCoef 1 + +//fc=3.2kHz +static inline float sb_iir(int i, float NewSample) { +/* float ACoef[NCoef+1] = { + 0.03356837051492005100, + 0.06713674102984010200, + 0.03356837051492005100 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.41898265221812010000, + 0.55326988968868285000 + };*/ + + float ACoef[NCoef+1] = { + 0.17529642630084405000, + 0.17529642630084405000 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -0.64940759319751051000 + }; + static float y[2][NCoef+1]; //output samples + static float x[2][NCoef+1]; //input samples + int n; + + //shift the old samples + for(n=NCoef; n>0; n--) { + x[i][n] = x[i][n-1]; + y[i][n] = y[i][n-1]; + } + + //Calculate the new output + x[i][0] = NewSample; + y[i][0] = ACoef[0] * x[i][0]; + for(n=1; n<=NCoef; n++) + y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; + + return y[i][0]; +} + + + +#undef NCoef +#define NCoef 2 + +//fc=150Hz +static inline float adgold_highpass_iir(int i, float NewSample) { + float ACoef[NCoef+1] = { + 0.98657437157334349000, + -1.97314874314668700000, + 0.98657437157334349000 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.97223372919758360000, + 0.97261396931534050000 + }; + + static float y[2][NCoef+1]; //output samples + static float x[2][NCoef+1]; //input samples + int n; + + //shift the old samples + for(n=NCoef; n>0; n--) { + x[i][n] = x[i][n-1]; + y[i][n] = y[i][n-1]; + } + + //Calculate the new output + x[i][0] = NewSample; + y[i][0] = ACoef[0] * x[i][0]; + for(n=1; n<=NCoef; n++) + y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; + + return y[i][0]; +} + +//fc=150Hz +static inline float adgold_lowpass_iir(int i, float NewSample) { + float ACoef[NCoef+1] = { + 0.00009159473951071446, + 0.00018318947902142891, + 0.00009159473951071446 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.97223372919526560000, + 0.97261396931306277000 + }; + + static float y[2][NCoef+1]; //output samples + static float x[2][NCoef+1]; //input samples + int n; + + //shift the old samples + for(n=NCoef; n>0; n--) { + x[i][n] = x[i][n-1]; + y[i][n] = y[i][n-1]; + } + + //Calculate the new output + x[i][0] = NewSample; + y[i][0] = ACoef[0] * x[i][0]; + for(n=1; n<=NCoef; n++) + y[i][0] += ACoef[n] * x[i][n] - BCoef[n] * y[i][n]; + + return y[i][0]; +} + +//fc=56Hz +static inline float adgold_pseudo_stereo_iir(float NewSample) { + float ACoef[NCoef+1] = { + 0.00001409030866231767, + 0.00002818061732463533, + 0.00001409030866231767 + }; + + float BCoef[NCoef+1] = { + 1.00000000000000000000, + -1.98733021473466760000, + 0.98738361004063568000 + }; + + static float y[NCoef+1]; //output samples + static float x[NCoef+1]; //input samples + int n; + + //shift the old samples + for(n=NCoef; n>0; n--) { + x[n] = x[n-1]; + y[n] = y[n-1]; + } + + //Calculate the new output + x[0] = NewSample; + y[0] = ACoef[0] * x[0]; + for(n=1; n<=NCoef; n++) + y[0] += ACoef[n] * x[n] - BCoef[n] * y[n]; + + return y[0]; +} diff --git a/src/gameport.c b/src/gameport.c new file mode 100644 index 000000000..3724d8e91 --- /dev/null +++ b/src/gameport.c @@ -0,0 +1,223 @@ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "plat-joystick.h" +#include "timer.h" + +#include "gameport.h" +#include "joystick_standard.h" +#include "joystick_sw_pad.h" + +int joystick_type; + +static joystick_if_t *joystick_list[] = +{ + &joystick_standard, + &joystick_standard_4button, + &joystick_standard_6button, + &joystick_standard_8button, + &joystick_sw_pad, + NULL +}; + +char *joystick_get_name(int joystick) +{ + if (!joystick_list[joystick]) + return NULL; + return joystick_list[joystick]->name; +} + +int joystick_get_max_joysticks(int joystick) +{ + return joystick_list[joystick]->max_joysticks; +} + +int joystick_get_axis_count(int joystick) +{ + return joystick_list[joystick]->axis_count; +} + +int joystick_get_button_count(int joystick) +{ + return joystick_list[joystick]->button_count; +} + +char *joystick_get_axis_name(int joystick, int id) +{ + return joystick_list[joystick]->axis_names[id]; +} + +char *joystick_get_button_name(int joystick, int id) +{ + return joystick_list[joystick]->button_names[id]; +} + +typedef struct gameport_axis_t +{ + int count; + int axis_nr; + struct gameport_t *gameport; +} gameport_axis_t; + +typedef struct gameport_t +{ + uint8_t state; + + gameport_axis_t axis[4]; + + joystick_if_t *joystick; + void *joystick_dat; +} gameport_t; + +static gameport_t *gameport_global = NULL; + +static int gameport_time(int axis) +{ + if (axis == AXIS_NOT_PRESENT) + return 0; + + axis += 32768; + axis = (axis * 100) / 65; /*Axis now in ohms*/ + axis = (axis * 11) / 1000; + return TIMER_USEC * (axis + 24); /*max = 11.115 ms*/ +} + +void gameport_write(uint16_t addr, uint8_t val, void *p) +{ + gameport_t *gameport = (gameport_t *)p; + + timer_clock(); + gameport->state |= 0x0f; +// pclog("gameport_write : joysticks_present=%i\n", joysticks_present); + + gameport->axis[0].count = gameport_time(gameport->joystick->read_axis(gameport->joystick_dat, 0)); + gameport->axis[1].count = gameport_time(gameport->joystick->read_axis(gameport->joystick_dat, 1)); + gameport->axis[2].count = gameport_time(gameport->joystick->read_axis(gameport->joystick_dat, 2)); + gameport->axis[3].count = gameport_time(gameport->joystick->read_axis(gameport->joystick_dat, 3)); + + gameport->joystick->write(gameport->joystick_dat); + + cycles -= ISA_CYCLES(8); +} + +uint8_t gameport_read(uint16_t addr, void *p) +{ + gameport_t *gameport = (gameport_t *)p; + uint8_t ret; + + timer_clock(); +// if (joysticks_present) + ret = gameport->state | gameport->joystick->read(gameport->joystick_dat);//0xf0; +// else +// ret = 0xff; + +// pclog("gameport_read: ret=%02x %08x:%08x isa_cycles=%i %i\n", ret, cs, cpu_state.pc, isa_cycles, gameport->axis[0].count); + + cycles -= ISA_CYCLES(8); + + return ret; +} + +void gameport_timer_over(void *p) +{ + gameport_axis_t *axis = (gameport_axis_t *)p; + gameport_t *gameport = axis->gameport; + + gameport->state &= ~(1 << axis->axis_nr); + axis->count = 0; + + if (axis == &gameport->axis[0]) + gameport->joystick->a0_over(gameport->joystick_dat); +} + +void *gameport_init_common() +{ + gameport_t *gameport = malloc(sizeof(gameport_t)); + + memset(gameport, 0, sizeof(gameport_t)); + + gameport->axis[0].gameport = gameport; + gameport->axis[1].gameport = gameport; + gameport->axis[2].gameport = gameport; + gameport->axis[3].gameport = gameport; + + gameport->axis[0].axis_nr = 0; + gameport->axis[1].axis_nr = 1; + gameport->axis[2].axis_nr = 2; + gameport->axis[3].axis_nr = 3; + + timer_add(gameport_timer_over, &gameport->axis[0].count, &gameport->axis[0].count, &gameport->axis[0]); + timer_add(gameport_timer_over, &gameport->axis[1].count, &gameport->axis[1].count, &gameport->axis[1]); + timer_add(gameport_timer_over, &gameport->axis[2].count, &gameport->axis[2].count, &gameport->axis[2]); + timer_add(gameport_timer_over, &gameport->axis[3].count, &gameport->axis[3].count, &gameport->axis[3]); + + gameport->joystick = joystick_list[joystick_type]; + gameport->joystick_dat = gameport->joystick->init(); + + gameport_global = gameport; + + return gameport; +} + +void gameport_update_joystick_type() +{ + gameport_t *gameport = gameport_global; + + gameport->joystick->close(gameport->joystick_dat); + gameport->joystick = joystick_list[joystick_type]; + gameport->joystick_dat = gameport->joystick->init(); +} + +void *gameport_init() +{ + gameport_t *gameport = gameport_init_common(); + + io_sethandler(0x0200, 0x0008, gameport_read, NULL, NULL, gameport_write, NULL, NULL, gameport); + + return gameport; +} + +void *gameport_201_init() +{ + gameport_t *gameport = gameport_init_common(); + + io_sethandler(0x0201, 0x0001, gameport_read, NULL, NULL, gameport_write, NULL, NULL, gameport); + + return gameport; +} + +void gameport_close(void *p) +{ + gameport_t *gameport = (gameport_t *)p; + + gameport->joystick->close(gameport->joystick_dat); + + gameport_global = NULL; + + free(gameport); +} + +device_t gameport_device = +{ + "Game port", + 0, + gameport_init, + gameport_close, + NULL, + NULL, + NULL, + NULL +}; + +device_t gameport_201_device = +{ + "Game port (port 201h only)", + 0, + gameport_201_init, + gameport_close, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/gameport.h b/src/gameport.h new file mode 100644 index 000000000..cca311e25 --- /dev/null +++ b/src/gameport.h @@ -0,0 +1,29 @@ +extern device_t gameport_device; +extern device_t gameport_201_device; + +typedef struct +{ + char name[80]; + void *(*init)(); + void (*close)(void *p); + uint8_t (*read)(void *p); + void (*write)(void *p); + int (*read_axis)(void *p, int axis); + void (*a0_over)(void *p); + int axis_count, button_count; + int max_joysticks; + char axis_names[8][32]; + char button_names[32][32]; +} joystick_if_t; + +extern int joystick_type; +char *joystick_get_name(int joystick); +int joystick_get_max_joysticks(int joystick); +int joystick_get_axis_count(int joystick); +int joystick_get_button_count(int joystick); +char *joystick_get_axis_name(int joystick, int id); +char *joystick_get_button_name(int joystick, int id); + +void gameport_update_joystick_type(); + +#define AXIS_NOT_PRESENT -99999 diff --git a/src/headland.c b/src/headland.c new file mode 100644 index 000000000..834c6947d --- /dev/null +++ b/src/headland.c @@ -0,0 +1,46 @@ +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "cpu.h" + +#include "headland.h" + +static int headland_index; +static uint8_t headland_regs[256]; + +void headland_write(uint16_t addr, uint8_t val, void *priv) +{ + if (addr & 1) + { + if (headland_index == 0xc1 && !is486) val = 0; + headland_regs[headland_index] = val; + pclog("Headland write %02X %02X\n",headland_index,val); + if (headland_index == 0x82) + { + shadowbios = val & 0x10; + shadowbios_write = !(val & 0x10); + if (shadowbios) + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_INTERNAL | MEM_WRITE_DISABLED); + else + mem_set_mem_state(0xf0000, 0x10000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + } + } + else + headland_index = val; +} + +uint8_t headland_read(uint16_t addr, void *priv) +{ + if (addr & 1) + { + if ((headland_index >= 0xc0 || headland_index == 0x20) && cpu_iscyrix) + return 0xff; /*Don't conflict with Cyrix config registers*/ + return headland_regs[headland_index]; + } + return headland_index; +} + +void headland_init() +{ + io_sethandler(0x0022, 0x0002, headland_read, NULL, NULL, headland_write, NULL, NULL, NULL); +} diff --git a/src/headland.h b/src/headland.h new file mode 100644 index 000000000..f9334fd6f --- /dev/null +++ b/src/headland.h @@ -0,0 +1 @@ +void headland_init(); diff --git a/src/i430fx.c b/src/i430fx.c new file mode 100644 index 000000000..524b3a0db --- /dev/null +++ b/src/i430fx.c @@ -0,0 +1,161 @@ +#include + +#include "ibm.h" +#include "mem.h" +#include "pci.h" + +#include "i430fx.h" + +static uint8_t card_i430fx[256]; + +static void i430fx_map(uint32_t addr, uint32_t size, int state) +{ + switch (state & 3) + { + case 0: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 1: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 2: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + flushmmucache_nopc(); +} + +void i430fx_write(int func, int addr, uint8_t val, void *priv) +{ + if (func) + return; + + switch (addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0e: + return; + + case 0x59: /*PAM0*/ + if ((card_i430fx[0x59] ^ val) & 0xf0) + { + i430fx_map(0xf0000, 0x10000, val >> 4); + shadowbios = (val & 0x10); + } + pclog("i430fx_write : PAM0 write %02X\n", val); + break; + case 0x5a: /*PAM1*/ + if ((card_i430fx[0x5a] ^ val) & 0x0f) + i430fx_map(0xc0000, 0x04000, val & 0xf); + if ((card_i430fx[0x5a] ^ val) & 0xf0) + i430fx_map(0xc4000, 0x04000, val >> 4); + break; + case 0x5b: /*PAM2*/ + if ((card_i430fx[0x5b] ^ val) & 0x0f) + i430fx_map(0xc8000, 0x04000, val & 0xf); + if ((card_i430fx[0x5b] ^ val) & 0xf0) + i430fx_map(0xcc000, 0x04000, val >> 4); + break; + case 0x5c: /*PAM3*/ + if ((card_i430fx[0x5c] ^ val) & 0x0f) + i430fx_map(0xd0000, 0x04000, val & 0xf); + if ((card_i430fx[0x5c] ^ val) & 0xf0) + i430fx_map(0xd4000, 0x04000, val >> 4); + break; + case 0x5d: /*PAM4*/ + if ((card_i430fx[0x5d] ^ val) & 0x0f) + i430fx_map(0xd8000, 0x04000, val & 0xf); + if ((card_i430fx[0x5d] ^ val) & 0xf0) + i430fx_map(0xdc000, 0x04000, val >> 4); + break; + case 0x5e: /*PAM5*/ + if ((card_i430fx[0x5e] ^ val) & 0x0f) + i430fx_map(0xe0000, 0x04000, val & 0xf); + if ((card_i430fx[0x5e] ^ val) & 0xf0) + i430fx_map(0xe4000, 0x04000, val >> 4); + pclog("i430fx_write : PAM5 write %02X\n", val); + break; + case 0x5f: /*PAM6*/ + if ((card_i430fx[0x5f] ^ val) & 0x0f) + i430fx_map(0xe8000, 0x04000, val & 0xf); + if ((card_i430fx[0x5f] ^ val) & 0xf0) + i430fx_map(0xec000, 0x04000, val >> 4); + pclog("i430fx_write : PAM6 write %02X\n", val); + break; + } + + card_i430fx[addr] = val; +} + +uint8_t i430fx_read(int func, int addr, void *priv) +{ + if (func) + return 0xff; + + return card_i430fx[addr]; +} + +/*The Turbo-Reset Control Register isn't listed in the i430FX datasheet, however + the Advanced/EV BIOS seems to assume it exists. It aliases with one of the PCI + registers.*/ +static uint8_t trc = 0; + +void i430fx_trc_write(uint16_t port, uint8_t val, void *p) +{ + if ((val & 4) && !(trc & 4)) + { + if (val & 2) /*Hard reset*/ + i430fx_write(0, 0x59, 0xf, NULL); /*Should reset all PCI devices, but just set PAM0 to point to ROM for now*/ + resetx86(); + } + + trc = val; +} + +void i430fx_init() +{ + pci_add_specific(0, i430fx_read, i430fx_write, NULL); + + memset(card_i430fx, 0, 256); + card_i430fx[0x00] = 0x86; card_i430fx[0x01] = 0x80; /*Intel*/ + card_i430fx[0x02] = 0x22; card_i430fx[0x03] = 0x01; /*SB82437FX-66*/ + card_i430fx[0x04] = 0x06; card_i430fx[0x05] = 0x00; + card_i430fx[0x06] = 0x00; card_i430fx[0x07] = 0x82; + if (romset == ROM_MB500N) card_i430fx[0x07] = 0x02; + card_i430fx[0x08] = 0x00; /*A0 stepping*/ + card_i430fx[0x09] = 0x00; card_i430fx[0x0a] = 0x00; card_i430fx[0x0b] = 0x06; + card_i430fx[0x52] = 0x40; /*256kb PLB cache*/ + if (romset == ROM_MB500N) + { + card_i430fx[0x52] = 0x42; + card_i430fx[0x53] = 0x14; + card_i430fx[0x56] = 0x52; /*DRAM control*/ + } +// card_i430fx[0x53] = 0x14; +// card_i430fx[0x56] = 0x52; /*DRAM control*/ + card_i430fx[0x57] = 0x01; + card_i430fx[0x60] = card_i430fx[0x61] = card_i430fx[0x62] = card_i430fx[0x63] = card_i430fx[0x64] = 0x02; + if (romset == ROM_MB500N) + { + card_i430fx[0x67] = 0x11; + card_i430fx[0x69] = 0x03; + card_i430fx[0x70] = 0x20; + } +// card_i430fx[0x67] = 0x11; +// card_i430fx[0x69] = 0x03; +// card_i430fx[0x70] = 0x20; + card_i430fx[0x72] = 0x02; +// card_i430fx[0x74] = 0x0e; +// card_i430fx[0x78] = 0x23; + if (romset == ROM_MB500N) + { + card_i430fx[0x74] = 0x0e; + card_i430fx[0x78] = 0x23; + } + + if (romset != ROM_MB500N) io_sethandler(0x0cf9, 0x0001, NULL, NULL, NULL, i430fx_trc_write, NULL, NULL, NULL); +} diff --git a/src/i430fx.h b/src/i430fx.h new file mode 100644 index 000000000..98b901ab9 --- /dev/null +++ b/src/i430fx.h @@ -0,0 +1 @@ +void i430fx_init(); diff --git a/src/i430hx.c b/src/i430hx.c new file mode 100644 index 000000000..71ec621e1 --- /dev/null +++ b/src/i430hx.c @@ -0,0 +1,128 @@ +#include + +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "pci.h" + +#include "i430hx.h" + +static uint8_t card_i430hx[256]; + +static void i430hx_map(uint32_t addr, uint32_t size, int state) +{ + switch (state & 3) + { + case 0: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 1: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 2: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + flushmmucache_nopc(); +} + +void i430hx_write(int func, int addr, uint8_t val, void *priv) +{ + if (func) + return; + + switch (addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0e: + return; + + case 0x59: /*PAM0*/ + if ((card_i430hx[0x59] ^ val) & 0xf0) + { + i430hx_map(0xf0000, 0x10000, val >> 4); + shadowbios = (val & 0x10); + } + // pclog("i430hx_write : PAM0 write %02X\n", val); + break; + case 0x5a: /*PAM1*/ + if ((card_i430hx[0x5a] ^ val) & 0x0f) + i430hx_map(0xc0000, 0x04000, val & 0xf); + if ((card_i430hx[0x5a] ^ val) & 0xf0) + i430hx_map(0xc4000, 0x04000, val >> 4); + break; + case 0x5b: /*PAM2*/ + if ((card_i430hx[0x5b] ^ val) & 0x0f) + i430hx_map(0xc8000, 0x04000, val & 0xf); + if ((card_i430hx[0x5b] ^ val) & 0xf0) + i430hx_map(0xcc000, 0x04000, val >> 4); + break; + case 0x5c: /*PAM3*/ + if ((card_i430hx[0x5c] ^ val) & 0x0f) + i430hx_map(0xd0000, 0x04000, val & 0xf); + if ((card_i430hx[0x5c] ^ val) & 0xf0) + i430hx_map(0xd4000, 0x04000, val >> 4); + break; + case 0x5d: /*PAM4*/ + if ((card_i430hx[0x5d] ^ val) & 0x0f) + i430hx_map(0xd8000, 0x04000, val & 0xf); + if ((card_i430hx[0x5d] ^ val) & 0xf0) + i430hx_map(0xdc000, 0x04000, val >> 4); + break; + case 0x5e: /*PAM5*/ + if ((card_i430hx[0x5e] ^ val) & 0x0f) + i430hx_map(0xe0000, 0x04000, val & 0xf); + if ((card_i430hx[0x5e] ^ val) & 0xf0) + i430hx_map(0xe4000, 0x04000, val >> 4); + // pclog("i430hx_write : PAM5 write %02X\n", val); + break; + case 0x5f: /*PAM6*/ + if ((card_i430hx[0x5f] ^ val) & 0x0f) + i430hx_map(0xe8000, 0x04000, val & 0xf); + if ((card_i430hx[0x5f] ^ val) & 0xf0) + i430hx_map(0xec000, 0x04000, val >> 4); + // pclog("i430hx_write : PAM6 write %02X\n", val); + break; + } + + card_i430hx[addr] = val; +} + +uint8_t i430hx_read(int func, int addr, void *priv) +{ + if (func) + return 0xff; + + return card_i430hx[addr]; +} + + +void i430hx_init() +{ + pci_add_specific(0, i430hx_read, i430hx_write, NULL); + + memset(card_i430hx, 0, 256); + card_i430hx[0x00] = 0x86; card_i430hx[0x01] = 0x80; /*Intel*/ + card_i430hx[0x02] = 0x50; card_i430hx[0x03] = 0x12; /*82439HX*/ + card_i430hx[0x04] = 0x06; card_i430hx[0x05] = 0x00; + card_i430hx[0x06] = 0x00; card_i430hx[0x07] = 0x02; + card_i430hx[0x08] = 0x00; /*A0 stepping*/ + card_i430hx[0x09] = 0x00; card_i430hx[0x0a] = 0x00; card_i430hx[0x0b] = 0x06; + // card_i430hx[0x52] = 0x42; /*256kb PLB cache*/ + card_i430hx[0x51] = 0x20; + // card_i430hx[0x52] = 0xB2; /*512kb cache*/ + card_i430hx[0x52] = 0xB5; /*512kb cache*/ + + card_i430hx[0x59] = 0x40; + card_i430hx[0x5A] = card_i430hx[0x5B] = card_i430hx[0x5C] = card_i430hx[0x5D] = card_i430hx[0x5E] = card_i430hx[0x5F] = 0x44; + + card_i430hx[0x56] = 0x52; /*DRAM control*/ + card_i430hx[0x57] = 0x01; + card_i430hx[0x60] = card_i430hx[0x61] = card_i430hx[0x62] = card_i430hx[0x63] = card_i430hx[0x64] = card_i430hx[0x65] = card_i430hx[0x66] = card_i430hx[0x67] = 0x02; + card_i430hx[0x68] = 0x11; + card_i430hx[0x72] = 0x02; +} diff --git a/src/i430hx.h b/src/i430hx.h new file mode 100644 index 000000000..b9a6b22e6 --- /dev/null +++ b/src/i430hx.h @@ -0,0 +1 @@ +void i430hx_init(); diff --git a/src/i430lx.c b/src/i430lx.c new file mode 100644 index 000000000..8738b7bd0 --- /dev/null +++ b/src/i430lx.c @@ -0,0 +1,149 @@ +#include + +#include "ibm.h" +#include "mem.h" +#include "pci.h" + +#include "i430lx.h" + +static uint8_t card_i430lx[256]; + +static void i430lx_map(uint32_t addr, uint32_t size, int state) +{ + switch (state & 3) + { + case 0: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 1: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 2: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + flushmmucache_nopc(); +} + +void i430lx_write(int func, int addr, uint8_t val, void *priv) +{ + if (func) + return; + + switch (addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0e: + return; + + case 0x59: /*PAM0*/ + if ((card_i430lx[0x59] ^ val) & 0xf0) + { + i430lx_map(0xf0000, 0x10000, val >> 4); + shadowbios = (val & 0x10); + } + pclog("i430lx_write : PAM0 write %02X\n", val); + break; + case 0x5a: /*PAM1*/ + if ((card_i430lx[0x5a] ^ val) & 0x0f) + i430lx_map(0xc0000, 0x04000, val & 0xf); + if ((card_i430lx[0x5a] ^ val) & 0xf0) + i430lx_map(0xc4000, 0x04000, val >> 4); + break; + case 0x5b: /*PAM2*/ + if (romset == ROM_REVENGE) + { + if ((card_i430lx[0x5b] ^ val) & 0x0f) + i430lx_map(0xc8000, 0x04000, val & 0xf); + if ((card_i430lx[0x5b] ^ val) & 0xf0) + i430lx_map(0xcc000, 0x04000, val >> 4); + } + break; + case 0x5c: /*PAM3*/ + if ((card_i430lx[0x5c] ^ val) & 0x0f) + i430lx_map(0xd0000, 0x04000, val & 0xf); + if ((card_i430lx[0x5c] ^ val) & 0xf0) + i430lx_map(0xd4000, 0x04000, val >> 4); + break; + case 0x5d: /*PAM4*/ + if ((card_i430lx[0x5d] ^ val) & 0x0f) + i430lx_map(0xd8000, 0x04000, val & 0xf); + if ((card_i430lx[0x5d] ^ val) & 0xf0) + i430lx_map(0xdc000, 0x04000, val >> 4); + break; + case 0x5e: /*PAM5*/ + if ((card_i430lx[0x5e] ^ val) & 0x0f) + i430lx_map(0xe0000, 0x04000, val & 0xf); + if ((card_i430lx[0x5e] ^ val) & 0xf0) + i430lx_map(0xe4000, 0x04000, val >> 4); + pclog("i430lx_write : PAM5 write %02X\n", val); + break; + case 0x5f: /*PAM6*/ + if ((card_i430lx[0x5f] ^ val) & 0x0f) + i430lx_map(0xe8000, 0x04000, val & 0xf); + if ((card_i430lx[0x5f] ^ val) & 0xf0) + i430lx_map(0xec000, 0x04000, val >> 4); + pclog("i430lx_write : PAM6 write %02X\n", val); + break; + } + + card_i430lx[addr] = val; +} + +uint8_t i430lx_read(int func, int addr, void *priv) +{ + if (func) + return 0xff; + + return card_i430lx[addr]; +} + +static uint8_t trc = 0; + +uint8_t i430lx_trc_read(uint16_t port, void *p) +{ + return trc; +} + +void i430lx_trc_write(uint16_t port, uint8_t val, void *p) +{ + if ((val & 4) && !(trc & 4)) + { + if (val & 2) /*Hard reset*/ + i430lx_write(0, 0x59, 0xf, NULL); /*Should reset all PCI devices, but just set PAM0 to point to ROM for now*/ + resetx86(); + } + + trc = val; +} + +void i430lx_init() +{ + pci_add_specific(0, i430lx_read, i430lx_write, NULL); + + memset(card_i430lx, 0, 256); + card_i430lx[0x00] = 0x86; card_i430lx[0x01] = 0x80; /*Intel*/ + card_i430lx[0x02] = 0xa3; card_i430lx[0x03] = 0x04; /*82434LX*/ + card_i430lx[0x04] = 0x06; card_i430lx[0x05] = 0x00; + card_i430lx[0x06] = 0x00; card_i430lx[0x07] = 0x02; + card_i430lx[0x08] = 0x03; /*A3 stepping*/ + card_i430lx[0x09] = 0x00; card_i430lx[0x0a] = 0x00; card_i430lx[0x0b] = 0x06; + card_i430lx[0x50] = 0x80; + card_i430lx[0x52] = 0x40; /*256kb PLB cache*/ +// card_i430lx[0x53] = 0x14; +// card_i430lx[0x56] = 0x52; /*DRAM control*/ + card_i430lx[0x57] = 0x31; + card_i430lx[0x60] = card_i430lx[0x61] = card_i430lx[0x62] = card_i430lx[0x63] = card_i430lx[0x64] = 0x02; +// card_i430lx[0x67] = 0x11; +// card_i430lx[0x69] = 0x03; +// card_i430lx[0x70] = 0x20; +// card_i430lx[0x72] = 0x02; +// card_i430lx[0x74] = 0x0e; +// card_i430lx[0x78] = 0x23; + + io_sethandler(0x0cf9, 0x0001, i430lx_trc_read, NULL, NULL, i430lx_trc_write, NULL, NULL, NULL); +} diff --git a/src/i430lx.h b/src/i430lx.h new file mode 100644 index 000000000..84d1e0ebf --- /dev/null +++ b/src/i430lx.h @@ -0,0 +1 @@ +void i430lx_init(); diff --git a/src/i430nx.c b/src/i430nx.c new file mode 100644 index 000000000..60eb79b62 --- /dev/null +++ b/src/i430nx.c @@ -0,0 +1,147 @@ +#include + +#include "ibm.h" +#include "mem.h" +#include "pci.h" + +#include "i430nx.h" + +static uint8_t card_i430nx[256]; + +static void i430nx_map(uint32_t addr, uint32_t size, int state) +{ + switch (state & 3) + { + case 0: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 1: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 2: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + flushmmucache_nopc(); +} + +void i430nx_write(int func, int addr, uint8_t val, void *priv) +{ + if (func) + return; + + switch (addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0e: + return; + + case 0x59: /*PAM0*/ + if ((card_i430nx[0x59] ^ val) & 0xf0) + { + i430nx_map(0xf0000, 0x10000, val >> 4); + shadowbios = (val & 0x10); + } + pclog("i430nx_write : PAM0 write %02X\n", val); + break; + case 0x5a: /*PAM1*/ + if ((card_i430nx[0x5a] ^ val) & 0x0f) + i430nx_map(0xc0000, 0x04000, val & 0xf); + if ((card_i430nx[0x5a] ^ val) & 0xf0) + i430nx_map(0xc4000, 0x04000, val >> 4); + break; + case 0x5b: /*PAM2*/ + if ((card_i430nx[0x5b] ^ val) & 0x0f) + i430nx_map(0xc8000, 0x04000, val & 0xf); + if ((card_i430nx[0x5b] ^ val) & 0xf0) + i430nx_map(0xcc000, 0x04000, val >> 4); + break; + case 0x5c: /*PAM3*/ + if ((card_i430nx[0x5c] ^ val) & 0x0f) + i430nx_map(0xd0000, 0x04000, val & 0xf); + if ((card_i430nx[0x5c] ^ val) & 0xf0) + i430nx_map(0xd4000, 0x04000, val >> 4); + break; + case 0x5d: /*PAM4*/ + if ((card_i430nx[0x5d] ^ val) & 0x0f) + i430nx_map(0xd8000, 0x04000, val & 0xf); + if ((card_i430nx[0x5d] ^ val) & 0xf0) + i430nx_map(0xdc000, 0x04000, val >> 4); + break; + case 0x5e: /*PAM5*/ + if ((card_i430nx[0x5e] ^ val) & 0x0f) + i430nx_map(0xe0000, 0x04000, val & 0xf); + if ((card_i430nx[0x5e] ^ val) & 0xf0) + i430nx_map(0xe4000, 0x04000, val >> 4); + pclog("i430nx_write : PAM5 write %02X\n", val); + break; + case 0x5f: /*PAM6*/ + if ((card_i430nx[0x5f] ^ val) & 0x0f) + i430nx_map(0xe8000, 0x04000, val & 0xf); + if ((card_i430nx[0x5f] ^ val) & 0xf0) + i430nx_map(0xec000, 0x04000, val >> 4); + pclog("i430nx_write : PAM6 write %02X\n", val); + break; + } + + card_i430nx[addr] = val; +} + +uint8_t i430nx_read(int func, int addr, void *priv) +{ + if (func) + return 0xff; + + return card_i430nx[addr]; +} + +static uint8_t trc = 0; + +uint8_t i430nx_trc_read(uint16_t port, void *p) +{ + return trc; +} + +void i430nx_trc_write(uint16_t port, uint8_t val, void *p) +{ + if ((val & 4) && !(trc & 4)) + { + if (val & 2) /*Hard reset*/ + i430nx_write(0, 0x59, 0xf, NULL); /*Should reset all PCI devices, but just set PAM0 to point to ROM for now*/ + resetx86(); + } + + trc = val; +} + +void i430nx_init() +{ + pci_add_specific(0, i430nx_read, i430nx_write, NULL); + + memset(card_i430nx, 0, 256); + card_i430nx[0x00] = 0x86; card_i430nx[0x01] = 0x80; /*Intel*/ + card_i430nx[0x02] = 0xa3; card_i430nx[0x03] = 0x04; /*82434NX*/ + card_i430nx[0x04] = 0x06; card_i430nx[0x05] = 0x00; + card_i430nx[0x06] = 0x00; card_i430nx[0x07] = 0x02; + card_i430nx[0x08] = 0x10; /*A0 stepping*/ + card_i430nx[0x09] = 0x00; card_i430nx[0x0a] = 0x00; card_i430nx[0x0b] = 0x06; + card_i430nx[0x50] = 0xA0; + card_i430nx[0x52] = 0x44; /*256kb PLB cache*/ +// card_i430nx[0x53] = 0x14; +// card_i430nx[0x56] = 0x52; /*DRAM control*/ + card_i430nx[0x57] = 0x31; + card_i430nx[0x60] = card_i430nx[0x61] = card_i430nx[0x62] = card_i430nx[0x63] = card_i430nx[0x64] = 0x02; + card_i430nx[0x66] = card_i430nx[0x67] = 0x02; +// card_i430nx[0x67] = 0x11; +// card_i430nx[0x69] = 0x03; +// card_i430nx[0x70] = 0x20; +// card_i430nx[0x72] = 0x02; +// card_i430nx[0x74] = 0x0e; +// card_i430nx[0x78] = 0x23; + + io_sethandler(0x0cf9, 0x0001, i430nx_trc_read, NULL, NULL, i430nx_trc_write, NULL, NULL, NULL); +} diff --git a/src/i430nx.h b/src/i430nx.h new file mode 100644 index 000000000..dfc5bd495 --- /dev/null +++ b/src/i430nx.h @@ -0,0 +1 @@ +void i430nx_init(); diff --git a/src/i430vx.c b/src/i430vx.c new file mode 100644 index 000000000..f324687c5 --- /dev/null +++ b/src/i430vx.c @@ -0,0 +1,126 @@ +#include + +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "pci.h" + +#include "i430vx.h" + +static uint8_t card_i430vx[256]; + +static void i430vx_map(uint32_t addr, uint32_t size, int state) +{ + switch (state & 3) + { + case 0: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 1: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 2: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + flushmmucache_nopc(); +} + +void i430vx_write(int func, int addr, uint8_t val, void *priv) +{ + if (func) + return; + + switch (addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0e: + return; + + case 0x59: /*PAM0*/ + if ((card_i430vx[0x59] ^ val) & 0xf0) + { + i430vx_map(0xf0000, 0x10000, val >> 4); + shadowbios = (val & 0x10); + } + pclog("i430vx_write : PAM0 write %02X\n", val); + break; + case 0x5a: /*PAM1*/ + if ((card_i430vx[0x5a] ^ val) & 0x0f) + i430vx_map(0xc0000, 0x04000, val & 0xf); + if ((card_i430vx[0x5a] ^ val) & 0xf0) + i430vx_map(0xc4000, 0x04000, val >> 4); + break; + case 0x5b: /*PAM2*/ + if ((card_i430vx[0x5b] ^ val) & 0x0f) + i430vx_map(0xc8000, 0x04000, val & 0xf); + if ((card_i430vx[0x5b] ^ val) & 0xf0) + i430vx_map(0xcc000, 0x04000, val >> 4); + break; + case 0x5c: /*PAM3*/ + if ((card_i430vx[0x5c] ^ val) & 0x0f) + i430vx_map(0xd0000, 0x04000, val & 0xf); + if ((card_i430vx[0x5c] ^ val) & 0xf0) + i430vx_map(0xd4000, 0x04000, val >> 4); + break; + case 0x5d: /*PAM4*/ + if ((card_i430vx[0x5d] ^ val) & 0x0f) + i430vx_map(0xd8000, 0x04000, val & 0xf); + if ((card_i430vx[0x5d] ^ val) & 0xf0) + i430vx_map(0xdc000, 0x04000, val >> 4); + break; + case 0x5e: /*PAM5*/ + if ((card_i430vx[0x5e] ^ val) & 0x0f) + i430vx_map(0xe0000, 0x04000, val & 0xf); + if ((card_i430vx[0x5e] ^ val) & 0xf0) + i430vx_map(0xe4000, 0x04000, val >> 4); + pclog("i430vx_write : PAM5 write %02X\n", val); + break; + case 0x5f: /*PAM6*/ + if ((card_i430vx[0x5f] ^ val) & 0x0f) + i430vx_map(0xe8000, 0x04000, val & 0xf); + if ((card_i430vx[0x5f] ^ val) & 0xf0) + i430vx_map(0xec000, 0x04000, val >> 4); + pclog("i430vx_write : PAM6 write %02X\n", val); + break; + } + + card_i430vx[addr] = val; +} + +uint8_t i430vx_read(int func, int addr, void *priv) +{ + if (func) + return 0xff; + + return card_i430vx[addr]; +} + + +void i430vx_init() +{ + pci_add_specific(0, i430vx_read, i430vx_write, NULL); + + memset(card_i430vx, 0, 256); + card_i430vx[0x00] = 0x86; card_i430vx[0x01] = 0x80; /*Intel*/ + card_i430vx[0x02] = 0x30; card_i430vx[0x03] = 0x70; /*82437VX*/ + card_i430vx[0x04] = 0x06; card_i430vx[0x05] = 0x00; + card_i430vx[0x06] = 0x00; card_i430vx[0x07] = 0x02; + card_i430vx[0x08] = 0x00; /*A0 stepping*/ + card_i430vx[0x09] = 0x00; card_i430vx[0x0a] = 0x00; card_i430vx[0x0b] = 0x06; + card_i430vx[0x52] = 0x42; /*256kb PLB cache*/ + card_i430vx[0x53] = 0x14; + card_i430vx[0x56] = 0x52; /*DRAM control*/ + card_i430vx[0x57] = 0x01; + card_i430vx[0x60] = card_i430vx[0x61] = card_i430vx[0x62] = card_i430vx[0x63] = card_i430vx[0x64] = 0x02; + card_i430vx[0x67] = 0x11; + card_i430vx[0x69] = 0x03; + card_i430vx[0x70] = 0x20; + card_i430vx[0x72] = 0x02; + card_i430vx[0x74] = 0x0e; + card_i430vx[0x78] = 0x23; +} diff --git a/src/i430vx.h b/src/i430vx.h new file mode 100644 index 000000000..af115bea6 --- /dev/null +++ b/src/i430vx.h @@ -0,0 +1 @@ +void i430vx_init(); diff --git a/src/i440fx.c b/src/i440fx.c new file mode 100644 index 000000000..932b1cd4a --- /dev/null +++ b/src/i440fx.c @@ -0,0 +1,130 @@ +#include + +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "pci.h" + +#include "i440fx.h" + +static uint8_t card_i440fx[256]; + +static void i440fx_map(uint32_t addr, uint32_t size, int state) +{ + switch (state & 3) + { + case 0: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 1: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + case 2: + mem_set_mem_state(addr, size, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(addr, size, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + } + flushmmucache_nopc(); +} + +void i440fx_write(int func, int addr, uint8_t val, void *priv) +{ + if (func) + return; + + switch (addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0e: + return; + + case 0x59: /*PAM0*/ + if ((card_i440fx[0x59] ^ val) & 0xf0) + { + i440fx_map(0xf0000, 0x10000, val >> 4); + shadowbios = (val & 0x10); + } + // pclog("i440fx_write : PAM0 write %02X\n", val); + break; + case 0x5a: /*PAM1*/ + if ((card_i440fx[0x5a] ^ val) & 0x0f) + i440fx_map(0xc0000, 0x04000, val & 0xf); + if ((card_i440fx[0x5a] ^ val) & 0xf0) + i440fx_map(0xc4000, 0x04000, val >> 4); + break; + case 0x5b: /*PAM2*/ + if ((card_i440fx[0x5b] ^ val) & 0x0f) + i440fx_map(0xc8000, 0x04000, val & 0xf); + if ((card_i440fx[0x5b] ^ val) & 0xf0) + i440fx_map(0xcc000, 0x04000, val >> 4); + break; + case 0x5c: /*PAM3*/ + if ((card_i440fx[0x5c] ^ val) & 0x0f) + i440fx_map(0xd0000, 0x04000, val & 0xf); + if ((card_i440fx[0x5c] ^ val) & 0xf0) + i440fx_map(0xd4000, 0x04000, val >> 4); + break; + case 0x5d: /*PAM4*/ + if ((card_i440fx[0x5d] ^ val) & 0x0f) + i440fx_map(0xd8000, 0x04000, val & 0xf); + if ((card_i440fx[0x5d] ^ val) & 0xf0) + i440fx_map(0xdc000, 0x04000, val >> 4); + break; + case 0x5e: /*PAM5*/ + if ((card_i440fx[0x5e] ^ val) & 0x0f) + i440fx_map(0xe0000, 0x04000, val & 0xf); + if ((card_i440fx[0x5e] ^ val) & 0xf0) + i440fx_map(0xe4000, 0x04000, val >> 4); + // pclog("i440fx_write : PAM5 write %02X\n", val); + break; + case 0x5f: /*PAM6*/ + if ((card_i440fx[0x5f] ^ val) & 0x0f) + i440fx_map(0xe8000, 0x04000, val & 0xf); + if ((card_i440fx[0x5f] ^ val) & 0xf0) + i440fx_map(0xec000, 0x04000, val >> 4); + // pclog("i440fx_write : PAM6 write %02X\n", val); + break; + } + + card_i440fx[addr] = val; +} + +uint8_t i440fx_read(int func, int addr, void *priv) +{ + if (func) + return 0xff; + + return card_i440fx[addr]; +} + + +void i440fx_init() +{ + pci_add_specific(0, i440fx_read, i440fx_write, NULL); + + memset(card_i440fx, 0, 256); + card_i440fx[0x00] = 0x86; card_i440fx[0x01] = 0x80; /*Intel*/ + card_i440fx[0x02] = 0x37; card_i440fx[0x03] = 0x12; /*82441FX*/ + card_i440fx[0x04] = 0x03; card_i440fx[0x05] = 0x01; + card_i440fx[0x06] = 0x00; card_i440fx[0x07] = 0x00; + card_i440fx[0x08] = 0x02; /*A0 stepping*/ + card_i440fx[0x09] = 0x00; card_i440fx[0x0a] = 0x00; card_i440fx[0x0b] = 0x06; + card_i440fx[0x2c] = 0xf4; + card_i440fx[0x2d] = 0x1a; + card_i440fx[0x2e] = 0x00; + card_i440fx[0x2f] = 0x11; + // card_i440fx[0x53] = 0x80; + // card_i440fx[0x55] = 0x11; + card_i440fx[0x57] = 0x10; + card_i440fx[0x58] = 0x00; + card_i440fx[0x59] = 0x10; + card_i440fx[0x5a] = card_i440fx[0x5b] = card_i440fx[0x5c] = card_i440fx[0x5d] = card_i440fx[0x5e] = 0x11; + card_i440fx[0x5f] = 0x31; + // card_i440fx[0x60] = card_i440fx[0x61] = card_i440fx[0x62] = card_i440fx[0x63] = card_i440fx[0x64] = card_i440fx[0x65] = card_i440fx[0x66] = card_i440fx[0x67] = 0x02; + // card_i440fx[0x70] = 0x20; + // card_i440fx[0x71] = 0x10; + card_i440fx[0x72] = 0x0A; +} diff --git a/src/i440fx.h b/src/i440fx.h new file mode 100644 index 000000000..052a938e6 --- /dev/null +++ b/src/i440fx.h @@ -0,0 +1 @@ +void i440fx_init(); diff --git a/src/ibm.h b/src/ibm.h new file mode 100644 index 000000000..3693f139c --- /dev/null +++ b/src/ibm.h @@ -0,0 +1,551 @@ +#include +#include +#include +#define printf pclog + +/*Memory*/ +uint8_t *ram,*vram; + +uint32_t rammask; + +int readlookup[256],readlookupp[256]; +uintptr_t *readlookup2; +int readlnext; +int writelookup[256],writelookupp[256]; +uintptr_t *writelookup2; +int writelnext; + +extern int mmu_perm; + +#define readmemb(a) ((readlookup2[(a)>>12]==-1)?readmembl(a):*(uint8_t *)(readlookup2[(a) >> 12] + (a))) +#define readmemw(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a))&0xFFF)>0xFFE)?readmemwl(s,a):*(uint16_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) +#define readmeml(s,a) ((readlookup2[(uint32_t)((s)+(a))>>12]==-1 || (s)==0xFFFFFFFF || (((s)+(a))&0xFFF)>0xFFC)?readmemll(s,a):*(uint32_t *)(readlookup2[(uint32_t)((s)+(a))>>12]+(uint32_t)((s)+(a)))) + +//#define writememb(a,v) if (writelookup2[(a)>>12]==0xFFFFFFFF) writemembl(a,v); else ram[writelookup2[(a)>>12]+((a)&0xFFF)]=v +//#define writememw(s,a,v) if (writelookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF) writememwl(s,a,v); else *((uint16_t *)(&ram[writelookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]))=v +//#define writememl(s,a,v) if (writelookup2[((s)+(a))>>12]==0xFFFFFFFF || (s)==0xFFFFFFFF) writememll(s,a,v); else *((uint32_t *)(&ram[writelookup2[((s)+(a))>>12]+(((s)+(a))&0xFFF)]))=v +//#define readmemb(a) ((isram[((a)>>16)&255] && !(cr0>>31))?ram[a&0xFFFFFF]:readmembl(a)) +//#define writememb(a,v) if (isram[((a)>>16)&255] && !(cr0>>31)) ram[a&0xFFFFFF]=v; else writemembl(a,v) + +//void writememb(uint32_t addr, uint8_t val); +uint8_t readmembl(uint32_t addr); +void writemembl(uint32_t addr, uint8_t val); +uint8_t readmemb386l(uint32_t seg, uint32_t addr); +void writememb386l(uint32_t seg, uint32_t addr, uint8_t val); +uint16_t readmemwl(uint32_t seg, uint32_t addr); +void writememwl(uint32_t seg, uint32_t addr, uint16_t val); +uint32_t readmemll(uint32_t seg, uint32_t addr); +void writememll(uint32_t seg, uint32_t addr, uint32_t val); +uint64_t readmemql(uint32_t seg, uint32_t addr); +void writememql(uint32_t seg, uint32_t addr, uint64_t val); + +uint8_t *getpccache(uint32_t a); + +uint32_t mmutranslatereal(uint32_t addr, int rw); + +void addreadlookup(uint32_t virt, uint32_t phys); +void addwritelookup(uint32_t virt, uint32_t phys); + + +/*IO*/ +uint8_t inb(uint16_t port); +void outb(uint16_t port, uint8_t val); +uint16_t inw(uint16_t port); +void outw(uint16_t port, uint16_t val); +uint32_t inl(uint16_t port); +void outl(uint16_t port, uint32_t val); + +FILE *romfopen(char *fn, char *mode); +extern int shadowbios,shadowbios_write; +extern int cache; +extern int mem_size; +extern int readlnum,writelnum; +extern int memwaitstate; + + +/*Processor*/ +#define EAX cpu_state.regs[0].l +#define ECX cpu_state.regs[1].l +#define EDX cpu_state.regs[2].l +#define EBX cpu_state.regs[3].l +#define ESP cpu_state.regs[4].l +#define EBP cpu_state.regs[5].l +#define ESI cpu_state.regs[6].l +#define EDI cpu_state.regs[7].l +#define AX cpu_state.regs[0].w +#define CX cpu_state.regs[1].w +#define DX cpu_state.regs[2].w +#define BX cpu_state.regs[3].w +#define SP cpu_state.regs[4].w +#define BP cpu_state.regs[5].w +#define SI cpu_state.regs[6].w +#define DI cpu_state.regs[7].w +#define AL cpu_state.regs[0].b.l +#define AH cpu_state.regs[0].b.h +#define CL cpu_state.regs[1].b.l +#define CH cpu_state.regs[1].b.h +#define DL cpu_state.regs[2].b.l +#define DH cpu_state.regs[2].b.h +#define BL cpu_state.regs[3].b.l +#define BH cpu_state.regs[3].b.h + +typedef union +{ + uint32_t l; + uint16_t w; + struct + { + uint8_t l,h; + } b; +} x86reg; + +struct +{ + x86reg regs[8]; + + int flags_op; + uint32_t flags_res; + uint32_t flags_op1, flags_op2; + + uint32_t pc; +} cpu_state; + +/*x86reg regs[8];*/ + +uint16_t flags,eflags; +uint32_t /*cs,ds,es,ss,*/oldds,oldss,olddslimit,oldsslimit,olddslimitw,oldsslimitw; +//uint16_t msw; + +extern int ins,output; +extern int cycdiff; + +typedef struct +{ + uint32_t base; + uint32_t limit; + uint8_t access; + uint16_t seg; + uint32_t limit_low, limit_high; + int checked; /*Non-zero if selector is known to be valid*/ +} x86seg; + +x86seg gdt,ldt,idt,tr; +x86seg _cs,_ds,_es,_ss,_fs,_gs; +x86seg _oldds; + +extern x86seg *ea_seg; + +uint32_t pccache; +uint8_t *pccache2; +/*Segments - + _cs,_ds,_es,_ss are the segment structures + CS,DS,ES,SS is the 16-bit data + cs,ds,es,ss are defines to the bases*/ +//uint16_t CS,DS,ES,SS; +#define CS _cs.seg +#define DS _ds.seg +#define ES _es.seg +#define SS _ss.seg +#define FS _fs.seg +#define GS _gs.seg +#define cs _cs.base +#define ds _ds.base +#define es _es.base +#define ss _ss.base +#define seg_fs _fs.base +#define gs _gs.base + +#define CPL ((_cs.access>>5)&3) + +void loadseg(uint16_t seg, x86seg *s); +void loadcs(uint16_t seg); + +union +{ + uint32_t l; + uint16_t w; +} CR0; + +#define cr0 CR0.l +#define msw CR0.w + +uint32_t cr2, cr3, cr4; +uint32_t dr[8]; + +#define C_FLAG 0x0001 +#define P_FLAG 0x0004 +#define A_FLAG 0x0010 +#define Z_FLAG 0x0040 +#define N_FLAG 0x0080 +#define T_FLAG 0x0100 +#define I_FLAG 0x0200 +#define D_FLAG 0x0400 +#define V_FLAG 0x0800 +#define NT_FLAG 0x4000 +#define VM_FLAG 0x0002 /*In EFLAGS*/ + +#define WP_FLAG 0x10000 /*In CR0*/ + +#define IOPL ((flags>>12)&3) + +#define IOPLp ((!(msw&1)) || (CPL<=IOPL)) +//#define IOPLp 1 + +//#define IOPLV86 ((!(msw&1)) || (CPL<=IOPL)) +extern int cycles; +extern int cycles_lost; +extern int is486; +extern uint8_t opcode; +extern int insc; +extern int fpucount; +extern float mips,flops; +extern int clockrate; +extern int cgate16; +extern int CPUID; + +extern int cpl_override; + +/*Timer*/ +typedef struct PIT +{ + uint32_t l[3]; + int c[3]; + uint8_t m[3]; + uint8_t ctrl,ctrls[3]; + int wp,rm[3],wm[3]; + uint16_t rl[3]; + int thit[3]; + int delay[3]; + int rereadlatch[3]; + int gate[3]; + int out[3]; + int running[3]; + int enabled[3]; + int newcount[3]; + int count[3]; + int using_timer[3]; + int initial[3]; + int latched[3]; + int disabled[3]; + + uint8_t read_status[3]; + int do_read_status[3]; +} PIT; + +PIT pit; +void setpitclock(float clock); +int pitcount; + +float pit_timer0_freq(); + + + +/*DMA*/ +typedef struct DMA +{ + uint16_t ab[4],ac[4]; + uint16_t cb[4]; + int cc[4]; + int wp; + uint8_t m,mode[4]; + uint8_t page[4]; + uint8_t stat; + uint8_t command; +} DMA; + +DMA dma,dma16; + + +/*PPI*/ +typedef struct PPI +{ + int s2; + uint8_t pa,pb; +} PPI; + +PPI ppi; +extern int key_inhibit; + + +/*PIC*/ +typedef struct PIC +{ + uint8_t icw1,icw4,mask,ins,pend,mask2; + int icw; + uint8_t vector; + int read; +} PIC; + +PIC pic,pic2; +extern int pic_intpending; +int intcount; + + +int disctime; +char discfns[2][256]; +int driveempty[2]; + +#define MDA ((gfxcard==GFX_MDA || gfxcard==GFX_HERCULES || gfxcard==GFX_INCOLOR) && (romset=ROM_IBMAT)) +#define VGA ((gfxcard>=GFX_TVGA || romset==ROM_ACER386) && gfxcard!=GFX_INCOLOR && gfxcard!=GFX_NEW_CGA && gfxcard!=GFX_COMPAQ_EGA && gfxcard!=GFX_SUPER_EGA && romset!=ROM_PC1640 && romset!=ROM_PC1512 && romset!=ROM_TANDY && romset!=ROM_PC200) +#define PCJR (romset == ROM_IBMPCJR) +#define AMIBIOS (romset==ROM_AMI386 || romset==ROM_AMI486 || romset == ROM_WIN486) + +int GAMEBLASTER, GUS, SSI2001, voodoo_enabled; +extern int AMSTRAD, AT, is286, is386, PCI, TANDY; + +enum +{ + ROM_IBMPC = 0, /*301 keyboard error, 131 cassette (!!!) error*/ + ROM_IBMXT, /*301 keyboard error*/ + ROM_IBMPCJR, + ROM_GENXT, /*'Generic XT BIOS'*/ + ROM_DTKXT, + ROM_EUROPC, + ROM_OLIM24, + ROM_TANDY, + ROM_PC1512, + ROM_PC200, + ROM_PC1640, + ROM_PC2086, + ROM_PC3086, + ROM_AMIXT, /*XT Clone with AMI BIOS*/ + ROM_LTXT, + ROM_LXT3, + ROM_PX386, + ROM_DTK386, + ROM_PXXT, + ROM_JUKOPC, + ROM_TANDY1000HX, + ROM_TANDY1000SL2, + ROM_IBMAT, + ROM_CMDPC30, + ROM_AMI286, + ROM_AWARD286, + ROM_DELL200, + ROM_MISC286, + ROM_IBMAT386, + ROM_ACER386, + ROM_MEGAPC, + ROM_AMI386, + ROM_AMI486, + ROM_WIN486, + ROM_PCI486, + ROM_SIS496, + ROM_430VX, + ROM_ENDEAVOR, + ROM_REVENGE, + ROM_IBMPS1_2011, + ROM_DESKPRO_386, + ROM_IBMPS1_2121, + + ROM_DTK486, /*DTK PKM-0038S E-2 / SiS 471 / Award BIOS / SiS 85C471*/ + ROM_VLI486SV2G, /*ASUS VL/I-486SV2G / SiS 471 / Award BIOS / SiS 85C471*/ + ROM_R418, /*Rise Computer R418 / SiS 496/497 / Award BIOS / SMC FDC37C665*/ + ROM_586MC1, /*Micro Star 586MC1 MS-5103 / 430LX / Award BIOS*/ + ROM_PLATO, /*Intel Premiere/PCI II / 430NX / AMI BIOS / SMC FDC37C665*/ + ROM_MB500N, /*PC Partner MB500N / 430FX / Award BIOS / SMC FDC37C665*/ + ROM_P54TP4XE, /*ASUS P/I-P55TP4XE / 430FX / Award BIOS / SMC FDC37C665*/ + ROM_ACERM3A, /*Acer M3A / 430HX / Acer BIOS / SMC FDC37C932FR*/ + ROM_ACERV35N, /*Acer V35N / 430HX / Acer BIOS / SMC FDC37C932FR*/ + ROM_P55T2P4, /*ASUS P/I-P55T2P4 / 430HX / Award BIOS / Winbond W8387F*/ + ROM_P55TVP4, /*ASUS P/I-P55TVP4 / 430HX / Award BIOS / Winbond W8387F*/ + ROM_P55VA, /*Epox P55-VA / 430VX / Award BIOS / SMC FDC37C932FR*/ + + ROM_440FX, /*Unknown / 440FX / Award BIOS / SMC FDC37C665*/ + ROM_KN97, /*ASUS KN-97 / 440FX / Award BIOS / Winbond W8387F*/ + + ROM_MAX +}; + +extern int romspresent[ROM_MAX]; + +int hasfpu; +int romset; + +enum +{ + GFX_CGA = 0, + GFX_MDA, + GFX_HERCULES, + GFX_EGA, /*Using IBM EGA BIOS*/ + GFX_TVGA, /*Using Trident TVGA8900D BIOS*/ + GFX_ET4000, /*Tseng ET4000*/ + GFX_ET4000W32, /*Tseng ET4000/W32p (Diamond Stealth 32)*/ + GFX_BAHAMAS64, /*S3 Vision864 (Paradise Bahamas 64)*/ + GFX_N9_9FX, /*S3 764/Trio64 (Number Nine 9FX)*/ + GFX_VIRGE, /*S3 Virge*/ + GFX_TGUI9440, /*Trident TGUI9440*/ + GFX_VGA, /*IBM VGA*/ + GFX_VGAEDGE16, /*ATI VGA Edge-16 (18800-1)*/ + GFX_VGACHARGER, /*ATI VGA Charger (28800-5)*/ + GFX_OTI067, /*Oak OTI-067*/ + GFX_MACH64GX, /*ATI Graphics Pro Turbo (Mach64)*/ + GFX_CL_GD5429, /*Cirrus Logic CL-GD5429*/ + GFX_VIRGEDX, /*S3 Virge/DX*/ + GFX_PHOENIX_TRIO32, /*S3 732/Trio32 (Phoenix)*/ + GFX_PHOENIX_TRIO64, /*S3 764/Trio64 (Phoenix)*/ + GFX_INCOLOR, /* Hercules InColor */ + GFX_NEW_CGA, + GFX_ET4000W32C, /*Tseng ET4000/W32p (Cardex) */ + GFX_COMPAQ_EGA, /*Compaq EGA*/ + GFX_SUPER_EGA, /*Using Chips & Technologies SuperEGA BIOS*/ + GFX_COMPAQ_VGA, /*Compaq/Paradise VGA*/ + GFX_MIRO_VISION964, /*S3 Vision964 (Miro Crystal)*/ + GFX_CL_GD5446, /*Cirrus Logic CL-GD5446*/ + GFX_VGAWONDERXL, /*Compaq ATI VGA Wonder XL (28800-5)*/ + GFX_WD90C11, /*Paradise WD90C11*/ + GFX_OTI077, /*Oak OTI-077*/ + GFX_MAX +}; + +extern int gfx_present[GFX_MAX]; + +int gfxcard; + +int cpuspeed; + + +/*Video*/ +void (*pollvideo)(); +void pollega(); +int readflash; +uint8_t hercctrl; +int slowega,egacycles,egacycles2; +extern uint8_t gdcreg[16]; +extern int egareads,egawrites; +extern int cga_comp; +extern int vid_resize; +extern int vid_api; +extern int winsizex,winsizey; +extern int chain4; + +uint8_t readvram(uint16_t addr); +void writevram(uint16_t addr, uint8_t val); +void writevramgen(uint16_t addr, uint8_t val); + +uint8_t readtandyvram(uint16_t addr); +void writetandy(uint16_t addr, uint8_t val); +void writetandyvram(uint16_t addr, uint8_t val); + +extern int et4k_b8000; +extern int changeframecount; +extern uint8_t changedvram[(8192*1024)/1024]; + +void writeega_chain4(uint32_t addr, uint8_t val); +extern uint32_t svgarbank,svgawbank; + +/*Serial*/ +extern int mousedelay; + + +/*Sound*/ +uint8_t spkstat; + +float spktime; +int rtctime; +int soundtime,gustime,gustime2,vidtime; +int ppispeakon; +float CGACONST; +float MDACONST; +float VGACONST1,VGACONST2; +float RTCCONST; +int gated,speakval,speakon; + +#define SOUNDBUFLEN (48000/10) + + +/*Sound Blaster*/ +/*int sbenable,sblatchi,sblatcho,sbcount,sb_enable_i,sb_count_i; +int16_t sbdat;*/ +void setsbclock(float clock); + +#define SADLIB 1 /*No DSP*/ +#define SB1 2 /*DSP v1.05*/ +#define SB15 3 /*DSP v2.00*/ +#define SB2 4 /*DSP v2.01 - needed for high-speed DMA*/ +#define SBPRO 5 /*DSP v3.00*/ +#define SBPRO2 6 /*DSP v3.02 + OPL3*/ +#define SB16 7 /*DSP v4.05 + OPL3*/ +#define SADGOLD 8 /*AdLib Gold*/ +#define SND_WSS 9 /*Windows Sound System*/ +#define SND_PAS16 10 /*Pro Audio Spectrum 16*/ + +int sbtype; + +int clocks[3][12][4]; +int at70hz; + +char pcempath[512]; + + +/*Hard disc*/ + +typedef struct +{ + FILE *f; + int spt,hpc; /*Sectors per track, heads per cylinder*/ + int tracks; +} PcemHDC; + +PcemHDC hdc[4]; + +/*Keyboard*/ +int keybsenddelay; + + +/*CD-ROM*/ +extern int cdrom_drive; +extern int old_cdrom_drive; +extern int idecallback[3]; +extern int cdrom_enabled; + +#define CD_STATUS_EMPTY 0 +#define CD_STATUS_DATA_ONLY 1 +#define CD_STATUS_PLAYING 2 +#define CD_STATUS_PAUSED 3 +#define CD_STATUS_STOPPED 4 + +extern uint32_t atapi_get_cd_channel(int channel); +extern uint32_t atapi_get_cd_volume(int channel); + +void pclog(const char *format, ...); +extern int nmi; + +extern int times; + + +extern float isa_timing, bus_timing; + +extern int frame; + + +uint8_t *vramp; + +uint64_t timer_read(); +extern uint64_t timer_freq; + + +void loadconfig(char *fn); + +extern int infocus; + +void onesec(); + +void resetpc_cad(); + +extern int start_in_fullscreen; +extern int window_w, window_h, window_x, window_y, window_remember; +extern int mouse_always_serial; + +extern uint64_t pmc[2]; + +extern uint16_t temp_seg_data[4]; + +extern uint16_t cs_msr; +extern uint32_t esp_msr; +extern uint32_t eip_msr; + +/* For the AMD K6. */ +extern uint64_t star; + +#define FPU_CW_Reserved_Bits (0xe0c0) diff --git a/src/ide.c b/src/ide.c new file mode 100644 index 000000000..bb7fc709f --- /dev/null +++ b/src/ide.c @@ -0,0 +1,3206 @@ +/*RPCemu v0.6 by Tom Walker + IDE emulation*/ +//#define RPCEMU_IDE + +#define CDROM_ISO 200 +#define IDE_TIME (5 * 100 * (1 << TIMER_SHIFT)) + +#define _LARGEFILE_SOURCE +#define _LARGEFILE64_SOURCE +#define _GNU_SOURCE +#include +#include +#include +#include + +#include + +#ifdef RPCEMU_IDE + #include "rpcemu.h" + #include "iomd.h" + #include "arm.h" +#else + #include "ibm.h" + #include "io.h" + #include "pic.h" + #include "timer.h" +#endif +#include "ide.h" + +/* Bits of 'atastat' */ +#define ERR_STAT 0x01 +#define DRQ_STAT 0x08 /* Data request */ +#define DSC_STAT 0x10 +#define SERVICE_STAT 0x10 +#define READY_STAT 0x40 +#define BUSY_STAT 0x80 + +/* Bits of 'error' */ +#define ABRT_ERR 0x04 /* Command aborted */ +#define MCR_ERR 0x08 /* Media change request */ + +/* ATA Commands */ +#define WIN_SRST 0x08 /* ATAPI Device Reset */ +#define WIN_RECAL 0x10 +#define WIN_RESTORE WIN_RECAL +#define WIN_READ 0x20 /* 28-Bit Read */ +#define WIN_READ_NORETRY 0x21 /* 28-Bit Read - no retry*/ +#define WIN_WRITE 0x30 /* 28-Bit Write */ +#define WIN_WRITE_NORETRY 0x31 /* 28-Bit Write */ +#define WIN_VERIFY 0x40 /* 28-Bit Verify */ +#define WIN_VERIFY_ONCE 0x41 /* Added by OBattler - deprected older ATA command, according to the specification I found, it is identical to 0x40 */ +#define WIN_FORMAT 0x50 +#define WIN_SEEK 0x70 +#define WIN_DRIVE_DIAGNOSTICS 0x90 /* Execute Drive Diagnostics */ +#define WIN_SPECIFY 0x91 /* Initialize Drive Parameters */ +#define WIN_PACKETCMD 0xA0 /* Send a packet command. */ +#define WIN_PIDENTIFY 0xA1 /* Identify ATAPI device */ +#define WIN_READ_MULTIPLE 0xC4 +#define WIN_WRITE_MULTIPLE 0xC5 +#define WIN_SET_MULTIPLE_MODE 0xC6 +#define WIN_READ_DMA 0xC8 +#define WIN_WRITE_DMA 0xCA +#define WIN_SETIDLE1 0xE3 +#define WIN_IDENTIFY 0xEC /* Ask drive to identify itself */ + +/* ATAPI Commands */ +#define GPCMD_TEST_UNIT_READY 0x00 +#define GPCMD_REQUEST_SENSE 0x03 +#define GPCMD_READ_6 0x08 +#define GPCMD_INQUIRY 0x12 +#define GPCMD_MODE_SELECT_6 0x15 +#define GPCMD_MODE_SENSE_6 0x1a +#define GPCMD_START_STOP_UNIT 0x1b +#define GPCMD_PREVENT_REMOVAL 0x1e +#define GPCMD_READ_CDROM_CAPACITY 0x25 +#define GPCMD_READ_10 0x28 +#define GPCMD_SEEK 0x2b +#define GPCMD_READ_SUBCHANNEL 0x42 +#define GPCMD_READ_TOC_PMA_ATIP 0x43 +#define GPCMD_READ_HEADER 0x44 +#define GPCMD_PLAY_AUDIO_10 0x45 +#define GPCMD_GET_CONFIGURATION 0x46 +#define GPCMD_PLAY_AUDIO_MSF 0x47 +#define GPCMD_GET_EVENT_STATUS_NOTIFICATION 0x4a +#define GPCMD_PAUSE_RESUME 0x4b +#define GPCMD_STOP_PLAY_SCAN 0x4e +#define GPCMD_READ_DISC_INFORMATION 0x51 +#define GPCMD_MODE_SELECT_10 0x55 +#define GPCMD_MODE_SENSE_10 0x5a +#define GPCMD_PLAY_AUDIO_12 0xa5 +#define GPCMD_READ_12 0xa8 +#define GPCMD_READ_DVD_STRUCTURE 0xad /* For reading. */ +#define GPCMD_SET_SPEED 0xbb +#define GPCMD_MECHANISM_STATUS 0xbd +#define GPCMD_READ_CD 0xbe +#define GPCMD_SEND_DVD_STRUCTURE 0xbf /* This is for writing only, irrelevant to PCem. */ + +/* Mode page codes for mode sense/set */ +#define GPMODE_R_W_ERROR_PAGE 0x01 +#define GPMODE_CDROM_PAGE 0x0d +#define GPMODE_CDROM_AUDIO_PAGE 0x0e +#define GPMODE_CAPABILITIES_PAGE 0x2a +#define GPMODE_ALL_PAGES 0x3f + +/* ATAPI Sense Keys */ +#define SENSE_NONE 0 +#define SENSE_NOT_READY 2 +#define SENSE_ILLEGAL_REQUEST 5 +#define SENSE_UNIT_ATTENTION 6 + +/* ATAPI Additional Sense Codes */ +#define ASC_AUDIO_PLAY_OPERATION 0x00 +#define ASC_ILLEGAL_OPCODE 0x20 +#define ASC_INV_FIELD_IN_CMD_PACKET 0x24 +#define ASC_MEDIUM_MAY_HAVE_CHANGED 0x28 +#define ASC_INCOMPATIBLE_FORMAT 0x30 +#define ASC_MEDIUM_NOT_PRESENT 0x3a +#define ASC_DATA_PHASE_ERROR 0x4b +#define ASC_ILLEGAL_MODE_FOR_THIS_TRACK 0x64 + +#define ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS 0x11 +#define ASCQ_AUDIO_PLAY_OPERATION_PAUSED 0x12 +#define ASCQ_AUDIO_PLAY_OPERATION_COMPLETED 0x13 + +/* Tell RISC OS that we have a 4x CD-ROM drive (600kb/sec data, 706kb/sec raw). + Not that it means anything */ +#define CDROM_SPEED 706 + +/** Evaluate to non-zero if the currently selected drive is an ATAPI device */ +#define IDE_DRIVE_IS_CDROM(ide) (ide->type == IDE_CDROM) +/* +\ + (!ide.drive)*/ + +/* Some generally useful CD-ROM information */ +#define CD_MINS 75 /* max. minutes per CD */ +#define CD_SECS 60 /* seconds per minute */ +#define CD_FRAMES 75 /* frames per second */ +#define CD_FRAMESIZE 2048 /* bytes per frame, "cooked" mode */ +#define CD_MAX_BYTES (CD_MINS * CD_SECS * CD_FRAMES * CD_FRAMESIZE) +#define CD_MAX_SECTORS (CD_MAX_BYTES / 512) + +/* Event notification classes for GET EVENT STATUS NOTIFICATION */ +#define GESN_NO_EVENTS 0 +#define GESN_OPERATIONAL_CHANGE 1 +#define GESN_POWER_MANAGEMENT 2 +#define GESN_EXTERNAL_REQUEST 3 +#define GESN_MEDIA 4 +#define GESN_MULTIPLE_HOSTS 5 +#define GESN_DEVICE_BUSY 6 + +/* Event codes for MEDIA event status notification */ +#define MEC_NO_CHANGE 0 +#define MEC_EJECT_REQUESTED 1 +#define MEC_NEW_MEDIA 2 +#define MEC_MEDIA_REMOVAL 3 /* only for media changers */ +#define MEC_MEDIA_CHANGED 4 /* only for media changers */ +#define MEC_BG_FORMAT_COMPLETED 5 /* MRW or DVD+RW b/g format completed */ +#define MEC_BG_FORMAT_RESTARTED 6 /* MRW or DVD+RW b/g format restarted */ +#define MS_TRAY_OPEN 1 +#define MS_MEDIA_PRESENT 2 + +/* + * The MMC values are not IDE specific and might need to be moved + * to a common header if they are also needed for the SCSI emulation + */ + +/* Profile list from MMC-6 revision 1 table 91 */ +#define MMC_PROFILE_NONE 0x0000 +#define MMC_PROFILE_CD_ROM 0x0008 +#define MMC_PROFILE_CD_R 0x0009 +#define MMC_PROFILE_CD_RW 0x000A +#define MMC_PROFILE_DVD_ROM 0x0010 +#define MMC_PROFILE_DVD_R_SR 0x0011 +#define MMC_PROFILE_DVD_RAM 0x0012 +#define MMC_PROFILE_DVD_RW_RO 0x0013 +#define MMC_PROFILE_DVD_RW_SR 0x0014 +#define MMC_PROFILE_DVD_R_DL_SR 0x0015 +#define MMC_PROFILE_DVD_R_DL_JR 0x0016 +#define MMC_PROFILE_DVD_RW_DL 0x0017 +#define MMC_PROFILE_DVD_DDR 0x0018 +#define MMC_PROFILE_DVD_PLUS_RW 0x001A +#define MMC_PROFILE_DVD_PLUS_R 0x001B +#define MMC_PROFILE_DVD_PLUS_RW_DL 0x002A +#define MMC_PROFILE_DVD_PLUS_R_DL 0x002B +#define MMC_PROFILE_BD_ROM 0x0040 +#define MMC_PROFILE_BD_R_SRM 0x0041 +#define MMC_PROFILE_BD_R_RRM 0x0042 +#define MMC_PROFILE_BD_RE 0x0043 +#define MMC_PROFILE_HDDVD_ROM 0x0050 +#define MMC_PROFILE_HDDVD_R 0x0051 +#define MMC_PROFILE_HDDVD_RAM 0x0052 +#define MMC_PROFILE_HDDVD_RW 0x0053 +#define MMC_PROFILE_HDDVD_R_DL 0x0058 +#define MMC_PROFILE_HDDVD_RW_DL 0x005A +#define MMC_PROFILE_INVALID 0xFFFF + +#define NONDATA 4 +#define CHECK_READY 2 +#define ALLOW_UA 1 + +/* Table of all ATAPI commands and their flags, needed for the new disc change / not ready handler. */ +uint8_t atapi_cmd_table[0x100] = +{ + [GPCMD_TEST_UNIT_READY] = CHECK_READY | NONDATA, + [GPCMD_REQUEST_SENSE] = ALLOW_UA, + [GPCMD_READ_6] = CHECK_READY, + [GPCMD_INQUIRY] = ALLOW_UA, + [GPCMD_MODE_SELECT_6] = 0, + [GPCMD_MODE_SENSE_6] = 0, + [GPCMD_START_STOP_UNIT] = 0, + [GPCMD_PREVENT_REMOVAL] = CHECK_READY, + [GPCMD_READ_CDROM_CAPACITY] = CHECK_READY, + [GPCMD_READ_10] = CHECK_READY, + [GPCMD_SEEK] = CHECK_READY | NONDATA, + [GPCMD_READ_SUBCHANNEL] = CHECK_READY, + [GPCMD_READ_TOC_PMA_ATIP] = CHECK_READY | ALLOW_UA, /* Read TOC - can get through UNIT_ATTENTION, per VIDE-CDD.SYS */ + [GPCMD_READ_HEADER] = CHECK_READY, + [GPCMD_PLAY_AUDIO_10] = CHECK_READY, +#if 0 + [GPCMD_GET_CONFIGURATION] = ALLOW_UA, +#endif + [GPCMD_PLAY_AUDIO_MSF] = CHECK_READY, + [GPCMD_GET_EVENT_STATUS_NOTIFICATION] = ALLOW_UA, + [GPCMD_PAUSE_RESUME] = CHECK_READY, + [GPCMD_STOP_PLAY_SCAN] = CHECK_READY, + [GPCMD_READ_DISC_INFORMATION] = CHECK_READY, + [GPCMD_MODE_SELECT_10] = 0, + [GPCMD_MODE_SENSE_10] = 0, + [GPCMD_PLAY_AUDIO_12] = CHECK_READY, + [GPCMD_READ_12] = CHECK_READY, + [GPCMD_SEND_DVD_STRUCTURE] = CHECK_READY, /* Read DVD structure (NOT IMPLEMENTED YET) */ + [GPCMD_SET_SPEED] = 0, + [GPCMD_MECHANISM_STATUS] = 0, + [GPCMD_READ_CD] = CHECK_READY, + [0xBF] = CHECK_READY /* Send DVD structure (NOT IMPLEMENTED YET) */ +}; + +#define IMPLEMENTED 1 + +uint8_t mode_sense_pages[0x40] = +{ + [GPMODE_R_W_ERROR_PAGE] = IMPLEMENTED, + [GPMODE_CDROM_PAGE] = IMPLEMENTED, + [GPMODE_CDROM_AUDIO_PAGE] = IMPLEMENTED, + [GPMODE_CAPABILITIES_PAGE] = IMPLEMENTED, + [GPMODE_ALL_PAGES] = IMPLEMENTED +}; + +ATAPI *atapi; + +int atapi_command = 0; +int readcdmode = 0; + +int cdrom_channel = 2; + +/* Mode sense/select stuff. */ +uint8_t mode_pages_in[256][256]; +#define PAGE_CHANGEABLE 1 +#define PAGE_CHANGED 2 +uint8_t page_flags[256] = +{ + [GPMODE_R_W_ERROR_PAGE] = 0, + [GPMODE_CDROM_PAGE] = 0, + [GPMODE_CDROM_AUDIO_PAGE] = PAGE_CHANGEABLE, + [GPMODE_CAPABILITIES_PAGE] = 0, +}; +uint8_t prefix_len; +uint8_t page_current; + +#define ATAPI_STATUS_IDLE 0 +#define ATAPI_STATUS_COMMAND 1 +#define ATAPI_STATUS_COMPLETE 2 +#define ATAPI_STATUS_DATA 3 +#define ATAPI_STATUS_PACKET_REQ 4 +#define ATAPI_STATUS_PACKET_RECEIVED 5 +#define ATAPI_STATUS_READCD 6 +#define ATAPI_STATUS_REQ_SENSE 7 +#define ATAPI_STATUS_ERROR 0x80 +#define ATAPI_STATUS_ERROR_2 0x81 + +enum +{ + IDE_NONE = 0, + IDE_HDD, + IDE_CDROM +}; + +typedef struct IDE +{ + int type; + int board; + uint8_t atastat; + uint8_t error; + int secount,sector,cylinder,head,drive,cylprecomp; + uint8_t command; + uint8_t fdisk; + int pos; + int packlen; + int spt,hpc; + int tracks; + int packetstatus; + int cdpos,cdlen; + uint8_t asc; + int reset; + FILE *hdfile; + uint16_t buffer[65536]; + int irqstat; + int service; + int lba; + uint32_t lba_addr; + int skip512; + int blocksize, blockcount; +} IDE; + +IDE ide_drives[6]; + +IDE *ext_ide; + +char ide_fn[4][512]; + +int (*ide_bus_master_read_sector)(int channel, uint8_t *data); +int (*ide_bus_master_write_sector)(int channel, uint8_t *data); +void (*ide_bus_master_set_irq)(int channel); + +static void callnonreadcd(IDE *ide); +static void callreadcd(IDE *ide); +static void atapicommand(int ide_board); + +int idecallback[3] = {0, 0, 0}; + +int cur_ide[3]; + +uint8_t getstat(IDE *ide) { return ide->atastat; } + +static inline void ide_irq_raise(IDE *ide) +{ +// pclog("IDE_IRQ_RAISE\n"); + if (!(ide->fdisk&2)) { +#ifdef RPCEMU_IDE + iomd.irqb.status |= IOMD_IRQB_IDE; + updateirqs(); +#else +// if (ide->board && !ide->irqstat) pclog("IDE_IRQ_RAISE\n"); +#ifdef MAINLINE + picint((ide->board)?(1<<15):(1<<14)); +#else + switch(ide->board) + { + case 0: + picint(1 << 14); + break; + case 1: + picint(1 << 15); + break; + case 2: + picint(1 << 10); + break; + } +#endif + if (ide->board < 2) + { + if (ide_bus_master_set_irq) + ide_bus_master_set_irq(ide->board); + } +#endif + } + ide->irqstat=1; + ide->service=1; + // pclog("raising interrupt %i\n", 14 + ide->board); +} + +static inline void ide_irq_lower(IDE *ide) +{ +// pclog("IDE_IRQ_LOWER\n"); +// if (ide.board == 0) { +#ifdef RPCEMU_IDE + iomd.irqb.status &= ~IOMD_IRQB_IDE; + updateirqs(); +#else +#ifdef MAINLINE + picintc((ide->board)?(1<<15):(1<<14)); +#else + switch(ide->board) + { + case 0: + picintc(1 << 14); + break; + case 1: + picintc(1 << 15); + break; + case 2: + picintc(1 << 10); + break; + } +#endif +#endif +// } + ide->irqstat=0; +} + +int get_irq(uint8_t board) +{ + if (board == 0) return 1 << 14; + else if (board == 1) return 1 << 15; + else if (board == 2) return 1 << 10; +} + +void ide_irq_update(IDE *ide) +{ +#ifdef RPCEMU_IDE + if (ide->irqstat && !(iomd.irqb.status & IOMD_IRQB_IDE) && !(ide->fdisk & 2)) { + iomd.irqb.status |= IOMD_IRQB_IDE; + updateirqs(); + } + else if (iomd.irqb.status & IOMD_IRQB_IDE) + { + iomd.irqb.status &= ~IOMD_IRQB_IDE; + updateirqs(); + } +#else +#ifdef MAINLINE + if (ide->irqstat && !((pic2.pend|pic2.ins)&0x40) && !(ide->fdisk & 2)) + picint((ide->board)?(1<<15):(1<<14)); + else if ((pic2.pend|pic2.ins)&0x40) + picintc((ide->board)?(1<<15):(1<<14)); +#else + if (ide->irqstat && !((pic2.pend|pic2.ins)&0x40) && !(ide->fdisk & 2)) + picint(get_irq(ide->board)); + else if ((pic2.pend|pic2.ins)&0x40) + picintc(get_irq(ide->board)); +#endif +#endif +} +/** + * Copy a string into a buffer, padding with spaces, and placing characters as + * if they were packed into 16-bit values, stored little-endian. + * + * @param str Destination buffer + * @param src Source string + * @param len Length of destination buffer to fill in. Strings shorter than + * this length will be padded with spaces. + */ +static void +ide_padstr(char *str, const char *src, int len) +{ + int i, v; + + for (i = 0; i < len; i++) { + if (*src != '\0') { + v = *src++; + } else { + v = ' '; + } + str[i ^ 1] = v; + } +} + +/** + * Copy a string into a buffer, padding with spaces. Does not add string + * terminator. + * + * @param buf Destination buffer + * @param buf_size Size of destination buffer to fill in. Strings shorter than + * this length will be padded with spaces. + * @param src Source string + */ +static void +ide_padstr8(uint8_t *buf, int buf_size, const char *src) +{ + int i; + + for (i = 0; i < buf_size; i++) { + if (*src != '\0') { + buf[i] = *src++; + } else { + buf[i] = ' '; + } + } +} + +/** + * Fill in ide->buffer with the output of the "IDENTIFY DEVICE" command + */ +static void ide_identify(IDE *ide) +{ + memset(ide->buffer, 0, 512); + + //ide->buffer[1] = 101; /* Cylinders */ + +#ifdef RPCEMU_IDE + ide->buffer[1] = 65535; /* Cylinders */ + ide->buffer[3] = 16; /* Heads */ + ide->buffer[6] = 63; /* Sectors */ +#else + ide->buffer[1] = hdc[cur_ide[ide->board]].tracks; /* Cylinders */ + ide->buffer[3] = hdc[cur_ide[ide->board]].hpc; /* Heads */ + ide->buffer[6] = hdc[cur_ide[ide->board]].spt; /* Sectors */ +#endif + ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ + ide_padstr((char *) (ide->buffer + 23), "v1.0", 8); /* Firmware */ +#ifdef RPCEMU_IDE + ide_padstr((char *) (ide->buffer + 27), "RPCemuHD", 40); /* Model */ +#else + ide_padstr((char *) (ide->buffer + 27), "PCemHD", 40); /* Model */ +#endif + ide->buffer[20] = 3; /*Buffer type*/ + ide->buffer[21] = 512; /*Buffer size*/ + ide->buffer[47] = 16; /*Max sectors on multiple transfer command*/ + ide->buffer[48] = 1; /*Dword transfers supported*/ + ide->buffer[49] = (1 << 9) | (1 << 8); /* LBA and DMA supported */ + ide->buffer[50] = 0x4000; /* Capabilities */ + ide->buffer[51] = 2 << 8; /*PIO timing mode*/ + ide->buffer[52] = 2 << 8; /*DMA timing mode*/ + ide->buffer[59] = ide->blocksize ? (ide->blocksize | 0x100) : 0; +#ifdef RPCEMU_IDE + ide->buffer[60] = (65535 * 16 * 63) & 0xFFFF; /* Total addressable sectors (LBA) */ + ide->buffer[61] = (65535 * 16 * 63) >> 16; +#else + ide->buffer[60] = (hdc[cur_ide[ide->board]].tracks * hdc[cur_ide[ide->board]].hpc * hdc[cur_ide[ide->board]].spt) & 0xFFFF; /* Total addressable sectors (LBA) */ + ide->buffer[61] = (hdc[cur_ide[ide->board]].tracks * hdc[cur_ide[ide->board]].hpc * hdc[cur_ide[ide->board]].spt) >> 16; +#endif + ide->buffer[63] = 7; /*Multiword DMA*/ + ide->buffer[80] = 0xe; /*ATA-1 to ATA-3 supported*/ +} + +/** + * Fill in ide->buffer with the output of the "IDENTIFY PACKET DEVICE" command + */ +static void ide_atapi_identify(IDE *ide) +{ + memset(ide->buffer, 0, 512); + + ide->buffer[0] = 0x8000 | (5<<8) | 0x80 | (2<<5); /* ATAPI device, CD-ROM drive, removable media, accelerated DRQ */ + ide_padstr((char *) (ide->buffer + 10), "", 20); /* Serial Number */ + ide_padstr((char *) (ide->buffer + 23), "v1.0", 8); /* Firmware */ +#ifdef RPCEMU_IDE + ide_padstr((char *) (ide->buffer + 27), "RPCemuCD", 40); /* Model */ +#else + ide_padstr((char *) (ide->buffer + 27), "PCemCD", 40); /* Model */ +#endif + ide->buffer[49] = 0x200; /* LBA supported */ +} + +/** + * Fill in ide->buffer with the output of the ATAPI "MODE SENSE" command + * + * @param pos Offset within the buffer to start filling in data + * + * @return Offset within the buffer after the end of the data + */ +static uint32_t ide_atapi_mode_sense(IDE *ide, uint32_t pos, uint8_t type) +{ + uint8_t *buf = (uint8_t *) ide->buffer; +// pclog("ide_atapi_mode_sense %02X\n",type); + if (type==GPMODE_ALL_PAGES || type==GPMODE_R_W_ERROR_PAGE) + { + /* &01 - Read error recovery */ + buf[pos++] = GPMODE_R_W_ERROR_PAGE; + buf[pos++] = 6; /* Page length */ + buf[pos++] = 0; /* Error recovery parameters */ + buf[pos++] = 5; /* Read retry count */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; /* Reserved */ + } + + if (type==GPMODE_ALL_PAGES || type==GPMODE_CDROM_PAGE) + { + /* &0D - CD-ROM Parameters */ + buf[pos++] = GPMODE_CDROM_PAGE; + buf[pos++] = 6; /* Page length */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 1; /* Inactivity time multiplier *NEEDED BY RISCOS* value is a guess */ + buf[pos++] = 0; buf[pos++] = 60; /* MSF settings */ + buf[pos++] = 0; buf[pos++] = 75; /* MSF settings */ + } + + if (type==GPMODE_ALL_PAGES || type==GPMODE_CDROM_AUDIO_PAGE) + { + /* &0e - CD-ROM Audio Control Parameters */ + buf[pos++] = GPMODE_CDROM_AUDIO_PAGE; + buf[pos++] = 0xE; /* Page length */ + if (page_flags[GPMODE_CDROM_AUDIO_PAGE] & PAGE_CHANGED) + { + int i; + + for (i = 0; i < 14; i++) + { + buf[pos++] = mode_pages_in[GPMODE_CDROM_AUDIO_PAGE][i]; + } + } + else + { + buf[pos++] = 4; /* Reserved */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; buf[pos++] = 75; /* Logical audio block per second */ + buf[pos++] = 1; /* CDDA Output Port 0 Channel Selection */ + buf[pos++] = 0xFF; /* CDDA Output Port 0 Volume */ + buf[pos++] = 2; /* CDDA Output Port 1 Channel Selection */ + buf[pos++] = 0xFF; /* CDDA Output Port 1 Volume */ + buf[pos++] = 0; /* CDDA Output Port 2 Channel Selection */ + buf[pos++] = 0; /* CDDA Output Port 2 Volume */ + buf[pos++] = 0; /* CDDA Output Port 3 Channel Selection */ + buf[pos++] = 0; /* CDDA Output Port 3 Volume */ + } + } + + if (type==GPMODE_ALL_PAGES || type==GPMODE_CAPABILITIES_PAGE) + { +// pclog("Capabilities page\n"); + /* &2A - CD-ROM capabilities and mechanical status */ + buf[pos++] = GPMODE_CAPABILITIES_PAGE; + buf[pos++] = 0x12; /* Page length */ + buf[pos++] = 0; buf[pos++] = 0; /* CD-R methods */ + buf[pos++] = 1; /* Supports audio play, not multisession */ + buf[pos++] = 0; /* Some other stuff not supported */ + buf[pos++] = 0; /* Some other stuff not supported (lock state + eject) */ + buf[pos++] = 0; /* Some other stuff not supported */ + buf[pos++] = (uint8_t) (CDROM_SPEED >> 8); + buf[pos++] = (uint8_t) CDROM_SPEED; /* Maximum speed */ + buf[pos++] = 0; buf[pos++] = 2; /* Number of audio levels - on and off only */ + buf[pos++] = 0; buf[pos++] = 0; /* Buffer size - none */ + buf[pos++] = (uint8_t) (CDROM_SPEED >> 8); + buf[pos++] = (uint8_t) CDROM_SPEED; /* Current speed */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; /* Drive digital format */ + buf[pos++] = 0; /* Reserved */ + buf[pos++] = 0; /* Reserved */ + } + + return pos; +} + +uint32_t atapi_get_cd_channel(int channel) +{ + return (page_flags[GPMODE_CDROM_AUDIO_PAGE] & PAGE_CHANGED) ? mode_pages_in[GPMODE_CDROM_AUDIO_PAGE][channel ? 8 : 6] : (channel + 1); +} + +uint32_t atapi_get_cd_volume(int channel) +{ + // return ((page_flags[GPMODE_CDROM_AUDIO_PAGE] & PAGE_CHANGED) && (mode_pages_in[GPMODE_CDROM_AUDIO_PAGE][channel ? 8 : 6] != 0)) ? mode_pages_in[GPMODE_CDROM_AUDIO_PAGE][channel ? 9 : 7] : 0xFF; + return (page_flags[GPMODE_CDROM_AUDIO_PAGE] & PAGE_CHANGED) ? mode_pages_in[GPMODE_CDROM_AUDIO_PAGE][channel ? 9 : 7] : 0xFF; +} + +/* + * Return the sector offset for the current register values + */ +static off64_t ide_get_sector(IDE *ide) +{ + if (ide->lba) + { + return (off64_t)ide->lba_addr + ide->skip512; + } + else + { + int heads = ide->hpc; + int sectors = ide->spt; + + return ((((off64_t) ide->cylinder * heads) + ide->head) * + sectors) + (ide->sector - 1) + ide->skip512; + } +} + +/** + * Move to the next sector using CHS addressing + */ +static void ide_next_sector(IDE *ide) +{ + if (ide->lba) + { + ide->lba_addr++; + } + else + { + ide->sector++; + if (ide->sector == (ide->spt + 1)) { + ide->sector = 1; + ide->head++; + if (ide->head == ide->hpc) { + ide->head = 0; + ide->cylinder++; + } + } + } +} + +#ifdef RPCEMU_IDE +static void loadhd(IDE *ide, int d, const char *fn) +{ + char pathname[512]; + + append_filename(pathname, rpcemu_get_datadir(), fn, 512); + + rpclog("Loading %s\n",pathname); + if (ide->hdfile == NULL) { + /* Try to open existing hard disk image */ + ide->hdfile = fopen64(pathname, "rb+"); + if (ide->hdfile == NULL) { + /* Failed to open existing hard disk image */ + if (errno == ENOENT) { + /* Failed because it does not exist, + so try to create new file */ + ide->hdfile = fopen64(pathname, "wb+"); + if (ide->hdfile == NULL) { + fatal("Cannot create file '%s': %s", + pathname, strerror(errno)); + } + } else { + /* Failed for another reason */ + fatal("Cannot open file '%s': %s", + pathname, strerror(errno)); + } + } + } + + fseek(ide->hdfile, 0xfc1, SEEK_SET); + ide->spt = getc(ide->hdfile); + ide->hpc = getc(ide->hdfile); + ide->skip512 = 1; +// rpclog("First check - spt %i hpc %i\n",ide.spt[0],ide.hpc[0]); + if (!ide->spt || !ide->hpc) + { + fseek(ide->hdfile, 0xdc1, SEEK_SET); + ide->spt = getc(ide->hdfile); + ide->hpc = getc(ide->hdfile); +// rpclog("Second check - spt %i hpc %i\n",ide.spt[0],ide.hpc[0]); + ide->skip512 = 0; + if (!ide->spt || !ide->hpc) + { + ide->spt=63; + ide->hpc=16; + ide->skip512 = 1; +// rpclog("Final check - spt %i hpc %i\n",ide.spt[0],ide.hpc[0]); + } + } + + ide->type = IDE_HDD; + + rpclog("%i %i %i\n",ide->spt,ide->hpc,ide->skip512); +} +#else +static void loadhd(IDE *ide, int d, const char *fn) +{ + if (ide->hdfile == NULL) { + /* Try to open existing hard disk image */ + ide->hdfile = fopen64(fn, "rb+"); + if (ide->hdfile == NULL) { + /* Failed to open existing hard disk image */ + if (errno == ENOENT) { + /* Failed because it does not exist, + so try to create new file */ + ide->hdfile = fopen64(fn, "wb+"); + if (ide->hdfile == NULL) { + ide->type = IDE_NONE; +/* fatal("Cannot create file '%s': %s", + fn, strerror(errno));*/ + return; + } + } else { + /* Failed for another reason */ + ide->type = IDE_NONE; +/* fatal("Cannot open file '%s': %s", + fn, strerror(errno));*/ + return; + } + } + } + + ide->spt = hdc[d].spt; + ide->hpc = hdc[d].hpc; + ide->tracks = hdc[d].tracks; + ide->type = IDE_HDD; +} +#endif + +void ide_set_signature(IDE *ide) +{ + ide->secount=1; + ide->sector=1; + ide->head=0; + ide->cylinder=(IDE_DRIVE_IS_CDROM(ide) ? 0xEB14 : ((ide->type == IDE_HDD) ? 0 : 0xFFFF)); + if (ide->type == IDE_HDD) ide->drive = 0; +} + +void resetide(void) +{ + int d; + + /* Close hard disk image files (if previously open) */ + for (d = 0; d < 4; d++) { + ide_drives[d].type = IDE_NONE; + if (ide_drives[d].hdfile != NULL) { + fclose(ide_drives[d].hdfile); + ide_drives[d].hdfile = NULL; + } + ide_drives[d].atastat = READY_STAT | DSC_STAT; + ide_drives[d].service = 0; + ide_drives[d].board = (d & 2) ? 1 : 0; + } + + for (d = 4; d < 6; d++) + { + ide_drives[d].type = IDE_NONE; + ide_drives[d].atastat = READY_STAT | DSC_STAT; + ide_drives[d].service = 0; + ide_drives[d].board = 2; + } + + page_flags[GPMODE_CDROM_AUDIO_PAGE] &= 0xFD; /* Clear changed flag for CDROM AUDIO mode page. */ + memset(mode_pages_in[GPMODE_CDROM_AUDIO_PAGE], 0, 256); /* Clear the page itself. */ + + idecallback[0]=idecallback[1]=0; +#ifdef RPCEMU_IDE + loadhd(&ide_drives[0], 0, "hd4.hdf"); + if (!config.cdromenabled) { + loadhd(&ide_drives[1], 1, "hd5.hdf"); + } + else + ide_drives[1].type = IDE_CDROM; +#else + for (d = 0; d < 4; d++) + { + ide_drives[d].packetstatus = 0xFF; + + if ((cdrom_channel == d) && cdrom_enabled) + { + ide_drives[d].type = IDE_CDROM; + } + else + { + loadhd(&ide_drives[d], d, ide_fn[d]); + } + + ide_set_signature(&ide_drives[d]); + } + + /* REMOVE WHEN SUBMITTING TO MAINLINE - START */ + for (d = 4; d < 6; d++) + { + ide_drives[d].packetstatus = 0xFF; + + if ((cdrom_channel == d) && cdrom_enabled) + { + ide_drives[d].type = IDE_CDROM; + } + else + { + ide_drives[d].type = IDE_NONE; + } + + ide_set_signature(&ide_drives[d]); + } + /* REMOVE WHEN SUBMITTING TO MAINLINE - END */ +#endif + + cur_ide[0] = 0; + cur_ide[1] = 2; + + cur_ide[2] = 4; + +// ide_drives[1].type = IDE_CDROM; + + page_flags[GPMODE_CDROM_AUDIO_PAGE] &= ~PAGE_CHANGED; +} + +int idetimes=0; +void writeidew(int ide_board, uint16_t val) +{ + IDE *ide = &ide_drives[cur_ide[ide_board]]; + + /*Some software issue excess writes after the 12 bytes required by the command, this will have all of them ignored*/ + if (ide->packetstatus && (ide->packetstatus != ATAPI_STATUS_PACKET_REQ)) + return; +#ifndef RPCEMU_IDE +/* if (ide_board && (cr0&1) && !(eflags&VM_FLAG)) + { +// pclog("Failed write IDE %04X:%08X\n",CS,pc); + return; + }*/ +#endif +#ifdef _RPCEMU_BIG_ENDIAN + val=(val>>8)|(val<<8); +#endif +// pclog("Write IDEw %04X\n",val); + ide->buffer[ide->pos >> 1] = val; + ide->pos+=2; + + if (ide->packetstatus == ATAPI_STATUS_PACKET_REQ) + { + if ((ide->pos>=prefix_len+4) && (page_flags[page_current] & PAGE_CHANGEABLE)) + { + mode_pages_in[page_current][ide->pos - prefix_len - 4] = ((uint8_t *) ide->buffer)[ide->pos - 2]; + mode_pages_in[page_current][ide->pos - prefix_len - 3] = ((uint8_t *) ide->buffer)[ide->pos - 1]; + } + if (ide->pos>=(ide->packlen+2)) + { + ide->packetstatus = ATAPI_STATUS_PACKET_RECEIVED; + timer_process(); + idecallback[ide_board]=6*IDE_TIME; + timer_update_outstanding(); +// pclog("Packet over!\n"); + ide_irq_lower(ide); + } + return; + } + else if (ide->packetstatus == ATAPI_STATUS_PACKET_RECEIVED) + return; + else if (ide->command == WIN_PACKETCMD && ide->pos>=0xC) + { + ide->pos=0; + ide->atastat = BUSY_STAT; + ide->packetstatus = ATAPI_STATUS_COMMAND; +/* idecallback[ide_board]=6*IDE_TIME;*/ + timer_process(); + callbackide(ide_board); + timer_update_outstanding(); +// idecallback[ide_board]=60*IDE_TIME; +// if ((ide->buffer[0]&0xFF)==0x43) idecallback[ide_board]=1*IDE_TIME; +// pclog("Packet now waiting!\n"); +/* if (ide->buffer[0]==0x243) + { + idetimes++; + output=3; + }*/ + } + else if (ide->pos>=512) + { + ide->pos=0; + ide->atastat = BUSY_STAT; + timer_process(); + if (ide->command == WIN_WRITE_MULTIPLE) + callbackide(ide_board); + else + idecallback[ide_board]=6*IDE_TIME; + timer_update_outstanding(); + } +} + +void writeidel(int ide_board, uint32_t val) +{ +// pclog("WriteIDEl %08X\n", val); + writeidew(ide_board, val); + writeidew(ide_board, val >> 16); +} + +void writeide(int ide_board, uint16_t addr, uint8_t val) +{ + IDE *ide = &ide_drives[cur_ide[ide_board]]; + IDE *ide_other = &ide_drives[cur_ide[ide_board] ^ 1]; +#ifndef RPCEMU_IDE +/* if (ide_board && (cr0&1) && !(eflags&VM_FLAG)) + { +// pclog("Failed write IDE %04X:%08X\n",CS,pc); + return; + }*/ +#endif +// if ((cr0&1) && !(eflags&VM_FLAG)) +// pclog("WriteIDE %04X %02X from %04X(%08X):%08X %i\n", addr, val, CS, cs, pc, ins); +// return; + addr|=0x80; + /* ONLY FOR EXPERIMENTAL */ + addr|=0x10; /* 1F0 | 10 = 1F0, 1E8 | 10 = 1F8 */ + addr&=0xFFF7; /* 1F0 & FFF7 = 1F0, 1F8 | FFF7 = 1F0 */ +// if (ide_board) pclog("Write IDEb %04X %02X %04X(%08X):%04X %i %02X %02X\n",addr,val,CS,cs,pc,ins,ide->atastat,ide_drives[0].atastat); + /*if (idedebug) */ +// pclog("Write IDE %08X %02X %04X:%08X\n",addr,val,CS,pc); +// int c; +// rpclog("Write IDE %08X %02X %08X %08X\n",addr,val,PC,armregs[12]); + + if (ide->type == IDE_NONE && (addr == 0x1f0 || addr == 0x1f7)) return; + + switch (addr) + { + case 0x1F0: /* Data */ + writeidew(ide_board, val | (val << 8)); + return; + + case 0x1F1: /* Features */ + ide->cylprecomp = val; + ide_other->cylprecomp = val; + return; + + case 0x1F2: /* Sector count */ + ide->secount = val; + ide_other->secount = val; + return; + + case 0x1F3: /* Sector */ + ide->sector = val; + ide->lba_addr = (ide->lba_addr & 0xFFFFF00) | val; + ide_other->sector = val; + ide_other->lba_addr = (ide_other->lba_addr & 0xFFFFF00) | val; + return; + + case 0x1F4: /* Cylinder low */ + ide->cylinder = (ide->cylinder & 0xFF00) | val; + ide->lba_addr = (ide->lba_addr & 0xFFF00FF) | (val << 8); + ide_other->cylinder = (ide_other->cylinder&0xFF00) | val; + ide_other->lba_addr = (ide_other->lba_addr&0xFFF00FF) | (val << 8); +// pclog("Write cylinder low %02X\n",val); + return; + + case 0x1F5: /* Cylinder high */ + ide->cylinder = (ide->cylinder & 0xFF) | (val << 8); + ide->lba_addr = (ide->lba_addr & 0xF00FFFF) | (val << 16); + ide_other->cylinder = (ide_other->cylinder & 0xFF) | (val << 8); + ide_other->lba_addr = (ide_other->lba_addr & 0xF00FFFF) | (val << 16); + return; + + case 0x1F6: /* Drive/Head */ +/* if (val==0xB0) + { + dumpregs(); + exit(-1); + }*/ + + if (cur_ide[ide_board] != ((val>>4)&1)+(ide_board<<1)) + { + cur_ide[ide_board]=((val>>4)&1)+(ide_board<<1); + + if (ide->reset || ide_other->reset) + { + ide->atastat = ide_other->atastat = READY_STAT | DSC_STAT; + ide->error = ide_other->error = 1; + ide->secount = ide_other->secount = 1; + ide->sector = ide_other->sector = 1; + ide->head = ide_other->head = 0; + ide->cylinder = ide_other->cylinder = 0; + ide->reset = ide_other->reset = 0; + // ide->blocksize = ide_other->blocksize = 0; + if (IDE_DRIVE_IS_CDROM(ide)) + ide->cylinder=0xEB14; + if (IDE_DRIVE_IS_CDROM(ide_other)) + ide_other->cylinder=0xEB14; + + idecallback[ide_board] = 0; + timer_update_outstanding(); + return; + } + + ide = &ide_drives[cur_ide[ide_board]]; + } + + ide->head = val & 0xF; + ide->lba = val & 0x40; + ide_other->head = val & 0xF; + ide_other->lba = val & 0x40; + + ide->lba_addr = (ide->lba_addr & 0x0FFFFFF) | ((val & 0xF) << 24); + ide_other->lba_addr = (ide_other->lba_addr & 0x0FFFFFF)|((val & 0xF) << 24); + + ide_irq_update(ide); + return; + + case 0x1F7: /* Command register */ + if (ide->type == IDE_NONE) return; +// pclog("IDE command %02X drive %i\n",val,ide.drive); + ide_irq_lower(ide); + ide->command=val; + +// pclog("New IDE command - %02X %i %i\n",ide->command,cur_ide[ide_board],ide_board); + ide->error=0; + switch (val) + { + case WIN_SRST: /* ATAPI Device Reset */ + if (IDE_DRIVE_IS_CDROM(ide)) ide->atastat = BUSY_STAT; + else ide->atastat = READY_STAT; + timer_process(); + idecallback[ide_board]=100*IDE_TIME; + timer_update_outstanding(); + return; + + case WIN_RESTORE: + case WIN_SEEK: +// pclog("WIN_RESTORE start\n"); + ide->atastat = READY_STAT; + timer_process(); + idecallback[ide_board]=100*IDE_TIME; + timer_update_outstanding(); + return; + + case WIN_READ_MULTIPLE: + if (!ide->blocksize && (ide->type != IDE_CDROM)) + fatal("READ_MULTIPLE - blocksize = 0\n"); +#if 0 + if (ide->lba) pclog("Read Multiple %i sectors from LBA addr %07X\n",ide->secount,ide->lba_addr); + else pclog("Read Multiple %i sectors from sector %i cylinder %i head %i %i\n",ide->secount,ide->sector,ide->cylinder,ide->head,ins); +#endif + ide->blockcount = 0; + + case WIN_READ: + case WIN_READ_NORETRY: + case WIN_READ_DMA: +/* if (ide.secount>1) + { + fatal("Read %i sectors from sector %i cylinder %i head %i\n",ide.secount,ide.sector,ide.cylinder,ide.head); + }*/ +#if 0 + if (ide->lba) pclog("Read %i sectors from LBA addr %07X\n",ide->secount,ide->lba_addr); + else pclog("Read %i sectors from sector %i cylinder %i head %i %i\n",ide->secount,ide->sector,ide->cylinder,ide->head,ins); +#endif + ide->atastat = BUSY_STAT; + timer_process(); + idecallback[ide_board]=200*IDE_TIME; + timer_update_outstanding(); + return; + + case WIN_WRITE_MULTIPLE: + if (!ide->blocksize && (ide->type != IDE_CDROM)) + fatal("Write_MULTIPLE - blocksize = 0\n"); +#if 0 + if (ide->lba) pclog("Write Multiple %i sectors from LBA addr %07X\n",ide->secount,ide->lba_addr); + else pclog("Write Multiple %i sectors to sector %i cylinder %i head %i\n",ide->secount,ide->sector,ide->cylinder,ide->head); +#endif + ide->blockcount = 0; + + case WIN_WRITE: + case WIN_WRITE_NORETRY: + /* if (ide.secount>1) + { + fatal("Write %i sectors to sector %i cylinder %i head %i\n",ide.secount,ide.sector,ide.cylinder,ide.head); + }*/ +#if 0 + if (ide->lba) pclog("Write %i sectors from LBA addr %07X\n",ide->secount,ide->lba_addr); + else pclog("Write %i sectors to sector %i cylinder %i head %i\n",ide->secount,ide->sector,ide->cylinder,ide->head); +#endif + ide->atastat = DRQ_STAT | DSC_STAT | READY_STAT; + ide->pos=0; + return; + + case WIN_WRITE_DMA: +#if 0 + if (ide->lba) pclog("Write %i sectors from LBA addr %07X\n",ide->secount,ide->lba_addr); + else pclog("Write %i sectors to sector %i cylinder %i head %i\n",ide->secount,ide->sector,ide->cylinder,ide->head); +#endif + ide->atastat = BUSY_STAT; + timer_process(); + idecallback[ide_board]=200*IDE_TIME; + timer_update_outstanding(); + return; + + case WIN_VERIFY: + case WIN_VERIFY_ONCE: +#if 0 + if (ide->lba) pclog("Read verify %i sectors from LBA addr %07X\n",ide->secount,ide->lba_addr); + else pclog("Read verify %i sectors from sector %i cylinder %i head %i\n",ide->secount,ide->sector,ide->cylinder,ide->head); +#endif + ide->atastat = BUSY_STAT; + timer_process(); + idecallback[ide_board]=200*IDE_TIME; + timer_update_outstanding(); + return; + + case WIN_FORMAT: +// pclog("Format track %i head %i\n",ide.cylinder,ide.head); + ide->atastat = DRQ_STAT; +// idecallback[ide_board]=200; + ide->pos=0; + return; + + case WIN_SPECIFY: /* Initialize Drive Parameters */ + ide->atastat = BUSY_STAT; + timer_process(); + idecallback[ide_board]=30*IDE_TIME; + timer_update_outstanding(); +// pclog("SPECIFY\n"); +// output=1; + return; + + case WIN_DRIVE_DIAGNOSTICS: /* Execute Drive Diagnostics */ + case WIN_PIDENTIFY: /* Identify Packet Device */ + case WIN_SET_MULTIPLE_MODE: /*Set Multiple Mode*/ +// output=1; + case WIN_SETIDLE1: /* Idle */ + ide->atastat = BUSY_STAT; + timer_process(); + callbackide(ide_board); +// idecallback[ide_board]=200*IDE_TIME; + timer_update_outstanding(); + return; + + case WIN_IDENTIFY: /* Identify Device */ + case 0xEF: +// output=3; +// timetolive=500; + ide->atastat = BUSY_STAT; + timer_process(); + idecallback[ide_board]=200*IDE_TIME; + timer_update_outstanding(); + return; + + case WIN_PACKETCMD: /* ATAPI Packet */ + ide->packetstatus = ATAPI_STATUS_IDLE; + ide->atastat = BUSY_STAT; + timer_process(); + idecallback[ide_board]=1;//30*IDE_TIME; + timer_update_outstanding(); + ide->pos=0; + return; + + case 0xF0: + default: + ide->atastat = READY_STAT | ERR_STAT | DSC_STAT; + ide->error = ABRT_ERR; + ide_irq_raise(ide); +/* fatal("Bad IDE command %02X\n", val);*/ + return; + } + + return; + + case 0x3F6: /* Device control */ + if ((ide->fdisk&4) && !(val&4) && (ide->type != IDE_NONE || ide_other->type != IDE_NONE)) + { + timer_process(); + idecallback[ide_board]=500*IDE_TIME; + timer_update_outstanding(); + ide->reset = ide_other->reset = 1; + ide->atastat = ide_other->atastat = BUSY_STAT; +// pclog("IDE Reset %i\n", ide_board); + } + ide->fdisk = ide_other->fdisk = val; + ide_irq_update(ide); + return; + } +// fatal("Bad IDE write %04X %02X\n", addr, val); +} + +uint8_t readide(int ide_board, uint16_t addr) +{ + IDE *ide = &ide_drives[cur_ide[ide_board]]; + uint8_t temp; + uint16_t tempw; + + addr|=0x80; + /* ONLY FOR EXPERIMENTAL */ + addr|=0x10; /* 1F0 | 10 = 1F0, 1E8 | 10 = 1F8 */ + addr&=0xFFF7; /* 1F0 & FFF7 = 1F0, 1F8 | FFF7 = 1F0 */ +#ifndef RPCEMU_IDE +/* if (ide_board && (cr0&1) && !(eflags&VM_FLAG)) + { +// pclog("Failed read IDE %04X:%08X\n",CS,pc); + return 0xFF; + }*/ +#endif +// if ((cr0&1) && !(eflags&VM_FLAG)) +// pclog("ReadIDE %04X from %04X(%08X):%08X\n", addr, CS, cs, pc); +// return 0xFF; + + if (ide->type == IDE_NONE && (addr == 0x1f0 || addr == 0x1f7)) return 0; +// /*if (addr!=0x1F7 && addr!=0x3F6) */pclog("Read IDEb %04X %02X %02X %i %04X:%04X %i %04X\n",addr,ide->atastat,(ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0),cur_ide[ide_board],CS,pc,ide_board, BX); +//rpclog("Read IDE %08X %08X %02X\n",addr,PC,iomd.irqb.mask); + switch (addr) + { + case 0x1F0: /* Data */ + tempw = readidew(ide_board); +// pclog("Read IDEW %04X\n", tempw); + temp = tempw & 0xff; + break; + + case 0x1F1: /* Error */ +// pclog("Read error %02X\n",ide.error); + temp = ide->error; + break; + + case 0x1F2: /* Sector count */ +// pclog("Read sector count %02X\n",ide->secount); + temp = (uint8_t)ide->secount; + break; + + case 0x1F3: /* Sector */ + temp = (uint8_t)ide->sector; + break; + + case 0x1F4: /* Cylinder low */ +// pclog("Read cyl low %02X\n",ide.cylinder&0xFF); + temp = (uint8_t)(ide->cylinder&0xFF); + break; + + case 0x1F5: /* Cylinder high */ +// pclog("Read cyl low %02X\n",ide.cylinder>>8); + temp = (uint8_t)(ide->cylinder>>8); + break; + + case 0x1F6: /* Drive/Head */ + temp = (uint8_t)(ide->head | ((cur_ide[ide_board] & 1) ? 0x10 : 0) | (ide->lba ? 0x40 : 0) | 0xa0); + break; + + case 0x1F7: /* Status */ + if (ide->type == IDE_NONE) + { +// pclog("Return status 00\n"); + temp = 0; + break; + } + ide_irq_lower(ide); + if (ide->type == IDE_CDROM) + { +// pclog("Read CDROM status %02X\n",(ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0)); + temp = (ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); + } + else + { +// && ide->service) return ide.atastat[ide.board]|SERVICE_STAT; +// pclog("Return status %02X %04X:%04X %02X %02X\n",ide->atastat, CS ,pc, AH, BH); + temp = ide->atastat; + } + break; + + case 0x3F6: /* Alternate Status */ +// pclog("3F6 read %02X\n",ide.atastat[ide.board]); +// if (output) output=0; + if (ide->type == IDE_NONE) + { +// pclog("Return status 00\n"); + temp = 0; + break; + } + if (ide->type == IDE_CDROM) + { +// pclog("Read CDROM status %02X\n",(ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0)); + temp = (ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0); + } + else + { +// && ide->service) return ide.atastat[ide.board]|SERVICE_STAT; +// pclog("Return status %02X\n",ide->atastat); + temp = ide->atastat; + } + break; + } +// if (ide_board) pclog("Read IDEb %04X %02X %02X %02X %i %04X:%04X %i\n", addr, temp, ide->atastat,(ide->atastat & ~DSC_STAT) | (ide->service ? SERVICE_STAT : 0),cur_ide[ide_board],CS,pc,ide_board); + return temp; +// fatal("Bad IDE read %04X\n", addr); +} + +uint16_t readidew(int ide_board) +{ + IDE *ide = &ide_drives[cur_ide[ide_board]]; + uint16_t temp; +#ifndef RPCEMU_IDE +/* if (ide_board && (cr0&1) && !(eflags&VM_FLAG)) + { +// pclog("Failed read IDEw %04X:%08X\n",CS,pc); + return 0xFFFF; + }*/ +#endif +// return 0xFFFF; +// pclog("Read IDEw %04X %04X:%04X %02X %i %i\n",ide->buffer[ide->pos >> 1],CS,pc,opcode,ins, ide->pos); + +//if (idedebug) pclog("Read IDEW %08X\n",PC); + + temp = ide->buffer[ide->pos >> 1]; + #ifdef _RPCEMU_BIG_ENDIAN + temp=(temp>>8)|(temp<<8); + #endif + ide->pos+=2; + if ((ide->command == WIN_PACKETCMD) && ((ide->packetstatus == ATAPI_STATUS_REQ_SENSE) || (ide->packetstatus==8))) + { + callnonreadcd(ide); + return temp; + } + if ((ide->pos>=512 && ide->command != WIN_PACKETCMD) || (ide->command == WIN_PACKETCMD && ide->pos>=ide->packlen)) + { +// pclog("Over! packlen %i %i\n",ide->packlen,ide->pos); + ide->pos=0; + if (ide->command == WIN_PACKETCMD)// && ide.packetstatus==6) + { +// pclog("Call readCD\n"); + callreadcd(ide); + } + else + { + ide->atastat = READY_STAT | DSC_STAT; + ide->packetstatus = ATAPI_STATUS_IDLE; + if (ide->command == WIN_READ || ide->command == WIN_READ_NORETRY || ide->command == WIN_READ_MULTIPLE) + { + ide->secount = (ide->secount - 1) & 0xff; + if (ide->secount) + { + ide_next_sector(ide); + ide->atastat = BUSY_STAT; + timer_process(); + if (ide->command == WIN_READ_MULTIPLE) + callbackide(ide_board); + else + idecallback[ide_board]=6*IDE_TIME; + timer_update_outstanding(); +// pclog("set idecallback\n"); +// callbackide(ide_board); + } +// else +// pclog("readidew done %02X\n", ide->atastat); + } + } + } +// pclog("Read IDEw %04X\n",temp); + return temp; +} + +uint32_t readidel(int ide_board) +{ + uint16_t temp; +// pclog("Read IDEl %i\n", ide_board); + temp = readidew(ide_board); + return temp | (readidew(ide_board) << 16); +} + +int times30=0; +void callbackide(int ide_board) +{ + IDE *ide = &ide_drives[cur_ide[ide_board]]; + IDE *ide_other = &ide_drives[cur_ide[ide_board] ^ 1]; + off64_t addr; + int c; + ext_ide = ide; +// return; + if (ide->command==0x30) times30++; +// if (times30==2240) output=1; + //if (times30==2471 && ide->command==0xA0) output=1; +///*if (ide_board) */pclog("CALLBACK %02X %i %i %i\n",ide->command,times30,ide->reset,cur_ide[ide_board]); +// if (times30==1294) +// output=1; + if (ide->reset) + { + ide->atastat = ide_other->atastat = READY_STAT | DSC_STAT; + ide->error = ide_other->error = 1; + ide->secount = ide_other->secount = 1; + ide->sector = ide_other->sector = 1; + ide->head = ide_other->head = 0; + ide->cylinder = ide_other->cylinder = 0; + ide->reset = ide_other->reset = 0; + if (IDE_DRIVE_IS_CDROM(ide)) + { + ide->cylinder=0xEB14; + atapi->stop(); + } + if (ide->type == IDE_NONE) + { + ide->cylinder=0xFFFF; + atapi->stop(); + } + if (IDE_DRIVE_IS_CDROM(ide_other)) + { + ide_other->cylinder=0xEB14; + atapi->stop(); + } + if (ide_other->type == IDE_NONE) + { + ide_other->cylinder=0xFFFF; + atapi->stop(); + } +// pclog("Reset callback\n"); + return; + } + switch (ide->command) + { + //Initialize the Task File Registers as follows: Status = 00h, Error = 01h, Sector Count = 01h, Sector Number = 01h, Cylinder Low = 14h, Cylinder High =EBh and Drive/Head = 00h. + case WIN_SRST: /*ATAPI Device Reset */ + ide->atastat = READY_STAT | DSC_STAT; + ide->error=1; /*Device passed*/ + ide->secount = ide->sector = 1; + ide_set_signature(ide); + if (IDE_DRIVE_IS_CDROM(ide)) + ide->atastat = 0; + ide_irq_raise(ide); + if (IDE_DRIVE_IS_CDROM(ide)) + ide->service = 0; + return; + + case WIN_RESTORE: + case WIN_SEEK: + if (IDE_DRIVE_IS_CDROM(ide)) { + pclog("WIN_RESTORE callback on CD-ROM\n"); + goto abort_cmd; + } +// pclog("WIN_RESTORE callback\n"); + ide->atastat = READY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + + case WIN_READ: + case WIN_READ_NORETRY: + if (IDE_DRIVE_IS_CDROM(ide)) { + ide_set_signature(ide); + goto abort_cmd; + } + addr = ide_get_sector(ide) * 512; +// pclog("Read %i %i %i %08X\n",ide.cylinder,ide.head,ide.sector,addr); + /* if (ide.cylinder || ide.head) + { + fatal("Read from other cylinder/head"); + }*/ + fseeko64(ide->hdfile, addr, SEEK_SET); + fread(ide->buffer, 512, 1, ide->hdfile); + ide->pos=0; + ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; +// pclog("Read sector callback %i %i %i offset %08X %i left %i %02X\n",ide.sector,ide.cylinder,ide.head,addr,ide.secount,ide.spt,ide.atastat[ide.board]); +// if (addr) output=3; + ide_irq_raise(ide); +#ifndef RPCEMU_IDE + readflash=1; +#endif + return; + + case WIN_READ_DMA: + if (IDE_DRIVE_IS_CDROM(ide)) { + goto abort_cmd; + } + addr = ide_get_sector(ide) * 512; + fseeko64(ide->hdfile, addr, SEEK_SET); + fread(ide->buffer, 512, 1, ide->hdfile); + ide->pos=0; + + if (ide_bus_master_read_sector) + { + if (ide_bus_master_read_sector(ide_board, (uint8_t *)ide->buffer)) + idecallback[ide_board]=6*IDE_TIME; /*DMA not performed, try again later*/ + else + { + /*DMA successful*/ + ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; + + ide->secount = (ide->secount - 1) & 0xff; + if (ide->secount) + { + ide_next_sector(ide); + ide->atastat = BUSY_STAT; + idecallback[ide_board]=6*IDE_TIME; + } + else + { + ide_irq_raise(ide); + } + } + } +#ifndef RPCEMU_IDE + readflash=1; +#endif + return; + + case WIN_READ_MULTIPLE: + if (IDE_DRIVE_IS_CDROM(ide)) { + goto abort_cmd; + } + addr = ide_get_sector(ide) * 512; +// pclog("Read multiple from %08X %i (%i) %i\n", addr, ide->blockcount, ide->blocksize, ide->secount); + fseeko64(ide->hdfile, addr, SEEK_SET); + fread(ide->buffer, 512, 1, ide->hdfile); + ide->pos=0; + ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; + if (!ide->blockcount)// || ide->secount == 1) + { +// pclog("Read multiple int\n"); + ide_irq_raise(ide); + } + ide->blockcount++; + if (ide->blockcount >= ide->blocksize) + ide->blockcount = 0; +#ifndef RPCEMU_IDE + readflash=1; +#endif + return; + + case WIN_WRITE: + case WIN_WRITE_NORETRY: + if (IDE_DRIVE_IS_CDROM(ide)) { + goto abort_cmd; + } + addr = ide_get_sector(ide) * 512; +// pclog("Write sector callback %i %i %i offset %08X %i left %i\n",ide.sector,ide.cylinder,ide.head,addr,ide.secount,ide.spt); + fseeko64(ide->hdfile, addr, SEEK_SET); + fwrite(ide->buffer, 512, 1, ide->hdfile); + ide_irq_raise(ide); + ide->secount = (ide->secount - 1) & 0xff; + if (ide->secount) + { + ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; + ide->pos=0; + ide_next_sector(ide); + } + else + ide->atastat = READY_STAT | DSC_STAT; +#ifndef RPCEMU_IDE + readflash=1; +#endif + return; + + case WIN_WRITE_DMA: + if (IDE_DRIVE_IS_CDROM(ide)) { + goto abort_cmd; + } + + if (ide_bus_master_write_sector) + { + if (ide_bus_master_write_sector(ide_board, (uint8_t *)ide->buffer)) + idecallback[ide_board]=6*IDE_TIME; /*DMA not performed, try again later*/ + else + { + /*DMA successful*/ + addr = ide_get_sector(ide) * 512; + fseeko64(ide->hdfile, addr, SEEK_SET); + fwrite(ide->buffer, 512, 1, ide->hdfile); + + ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; + + ide->secount = (ide->secount - 1) & 0xff; + if (ide->secount) + { + ide_next_sector(ide); + ide->atastat = BUSY_STAT; + idecallback[ide_board]=6*IDE_TIME; + } + else + { + ide_irq_raise(ide); + } + } + } +#ifndef RPCEMU_IDE + readflash=1; +#endif + return; + + case WIN_WRITE_MULTIPLE: + if (IDE_DRIVE_IS_CDROM(ide)) { + goto abort_cmd; + } + addr = ide_get_sector(ide) * 512; +// pclog("Write sector callback %i %i %i offset %08X %i left %i\n",ide.sector,ide.cylinder,ide.head,addr,ide.secount,ide.spt); + fseeko64(ide->hdfile, addr, SEEK_SET); + fwrite(ide->buffer, 512, 1, ide->hdfile); + ide->blockcount++; + if (ide->blockcount >= ide->blocksize || ide->secount == 1) + { + ide->blockcount = 0; + ide_irq_raise(ide); + } + ide->secount = (ide->secount - 1) & 0xff; + if (ide->secount) + { + ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; + ide->pos=0; + ide_next_sector(ide); + } + else + ide->atastat = READY_STAT | DSC_STAT; +#ifndef RPCEMU_IDE + readflash=1; +#endif + return; + + case WIN_VERIFY: + case WIN_VERIFY_ONCE: + if (IDE_DRIVE_IS_CDROM(ide)) { + goto abort_cmd; + } + ide->pos=0; + ide->atastat = READY_STAT | DSC_STAT; +// pclog("Read verify callback %i %i %i offset %08X %i left\n",ide.sector,ide.cylinder,ide.head,addr,ide.secount); + ide_irq_raise(ide); +#ifndef RPCEMU_IDE + readflash=1; +#endif + return; + + case WIN_FORMAT: + if (IDE_DRIVE_IS_CDROM(ide)) { + goto abort_cmd; + } + addr = ide_get_sector(ide) * 512; +// pclog("Format cyl %i head %i offset %08X %08X %08X secount %i\n",ide.cylinder,ide.head,addr,addr>>32,addr,ide.secount); + fseeko64(ide->hdfile, addr, SEEK_SET); + memset(ide->buffer, 0, 512); + for (c=0;csecount;c++) + { + fwrite(ide->buffer, 512, 1, ide->hdfile); + } + ide->atastat = READY_STAT | DSC_STAT; + ide_irq_raise(ide); +#ifndef RPCEMU_IDE + readflash=1; +#endif + return; + + case WIN_DRIVE_DIAGNOSTICS: + ide_set_signature(ide); + ide->error=1; /*No error detected*/ + if (IDE_DRIVE_IS_CDROM(ide)) + { + ide->atastat = 0; + } + else + { + ide->atastat = READY_STAT | DSC_STAT; + ide_irq_raise(ide); + } + return; + + case WIN_SPECIFY: /* Initialize Drive Parameters */ + if (IDE_DRIVE_IS_CDROM(ide)) { +#ifndef RPCEMU_IDE + pclog("IS CDROM - ABORT\n"); +#endif + goto abort_cmd; + } + ide->spt=ide->secount; + ide->hpc=ide->head+1; + ide->atastat = READY_STAT | DSC_STAT; +#ifndef RPCEMU_IDE +// pclog("SPECIFY - %i sectors per track, %i heads per cylinder %i %i\n",ide->spt,ide->hpc,cur_ide[ide_board],ide_board); +#endif + ide_irq_raise(ide); + return; + + case WIN_PIDENTIFY: /* Identify Packet Device */ + if (IDE_DRIVE_IS_CDROM(ide)) { +// pclog("ATAPI identify\n"); + ide_atapi_identify(ide); + ide->pos=0; + ide->error=0; + ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; + ide_irq_raise(ide); + return; + } +// pclog("Not ATAPI\n"); + goto abort_cmd; + + case WIN_SET_MULTIPLE_MODE: + if (IDE_DRIVE_IS_CDROM(ide)) { +#ifndef RPCEMU_IDE + pclog("IS CDROM - ABORT\n"); +#endif + goto abort_cmd; + } + ide->blocksize = ide->secount; + ide->atastat = READY_STAT | DSC_STAT; +#ifndef RPCEMU_IDE + pclog("Set multiple mode - %i\n", ide->blocksize); +#endif + ide_irq_raise(ide); + return; + + case WIN_SETIDLE1: /* Idle */ + case 0xEF: + goto abort_cmd; + + case WIN_IDENTIFY: /* Identify Device */ + if (ide->type == IDE_NONE) + { + goto abort_cmd; + } + if (IDE_DRIVE_IS_CDROM(ide)) + { + ide_set_signature(ide); + goto abort_cmd; + } + else + { + ide_identify(ide); + ide->pos=0; + ide->atastat = DRQ_STAT | READY_STAT | DSC_STAT; +// pclog("ID callback\n"); + ide_irq_raise(ide); + } + return; + + case WIN_PACKETCMD: /* ATAPI Packet */ + if (!IDE_DRIVE_IS_CDROM(ide)) goto abort_cmd; +// pclog("Packet callback! %i %08X\n",ide->packetstatus,ide); + + if (ide->packetstatus == ATAPI_STATUS_IDLE) + { + readcdmode=0; + ide->pos=0; + ide->secount = (uint8_t)((ide->secount&0xF8)|1); + ide->atastat = READY_STAT | DRQ_STAT |(ide->atastat&ERR_STAT); + //ide_irq_raise(ide); +// pclog("1 Preparing to recieve packet max DRQ count %04X\n",ide->cylinder); + } + else if (ide->packetstatus == ATAPI_STATUS_COMMAND) + { + ide->atastat = BUSY_STAT|(ide->atastat&ERR_STAT); +// pclog("Running ATAPI command 2\n"); + atapicommand(ide_board); +// exit(-1); + } + else if (ide->packetstatus == ATAPI_STATUS_COMPLETE) + { +// pclog("packetstatus==2\n"); + ide->atastat = READY_STAT; + ide->secount=3; + ide_irq_raise(ide); +// if (iomd.irqb.mask&2) output=1; + } + else if (ide->packetstatus == ATAPI_STATUS_DATA) + { + ide->atastat = READY_STAT|DRQ_STAT|(ide->atastat&ERR_STAT); +// rpclog("Recieve data packet 3! %02X\n",ide->atastat); + ide_irq_raise(ide); + ide->packetstatus=0xFF; + } + else if (ide->packetstatus == ATAPI_STATUS_PACKET_REQ) + { + ide->atastat = 0x58 | (ide->atastat & ERR_STAT); +// pclog("Send data packet 4!\n"); + ide_irq_raise(ide); +// ide.packetstatus=5; + ide->pos=2; + } + else if (ide->packetstatus == ATAPI_STATUS_PACKET_RECEIVED) + { +// pclog("Packetstatus 5 !\n"); + atapicommand(ide_board); + } + else if (ide->packetstatus == ATAPI_STATUS_READCD) /*READ CD callback*/ + { + ide->atastat = DRQ_STAT|(ide->atastat&ERR_STAT); +// pclog("Recieve data packet 6!\n"); + ide_irq_raise(ide); +// ide.packetstatus=0xFF; + } + else if (ide->packetstatus == ATAPI_STATUS_REQ_SENSE) /*REQUEST SENSE callback #1*/ + { + pclog("REQUEST SENSE callback #1: setting status to 0x5A\n"); + ide->atastat = 0x58 | (ide->atastat & ERR_STAT); + ide_irq_raise(ide); + } + else if (ide->packetstatus == ATAPI_STATUS_ERROR) /*Error callback*/ + { +// pclog("Packet error\n"); + ide->atastat = READY_STAT | ERR_STAT; + ide_irq_raise(ide); + } + else if (ide->packetstatus == ATAPI_STATUS_ERROR_2) /*Error callback with atastat already set - needed for the disc change stuff.*/ + { + //pclog("Packet check status\n"); + ide->atastat = ERR_STAT; + ide_irq_raise(ide); + } + return; + } + +abort_cmd: + ide->command = 0; + ide->atastat = READY_STAT | ERR_STAT | DSC_STAT; + ide->error = ABRT_ERR; + ide->pos = 0; + ide_irq_raise(ide); +} + +void ide_callback_pri() +{ + idecallback[0] = 0; + callbackide(0); +} + +void ide_callback_sec() +{ + idecallback[1] = 0; + callbackide(1); +} + +void ide_callback_ter() +{ + idecallback[2] = 0; + callbackide(2); +} + +/*ATAPI CD-ROM emulation*/ + +struct +{ + int sensekey,asc,ascq; +} atapi_sense; + +static uint8_t atapi_set_profile(uint8_t *buf, uint8_t *index, uint16_t profile) +{ + uint8_t *buf_profile = buf + 12; /* start of profiles */ + + buf_profile += ((*index) * 4); /* start of indexed profile */ + buf_profile[0] = (profile >> 8) & 0xff; + buf_profile[1] = profile & 0xff; + buf_profile[2] = ((buf_profile[0] == buf[6]) && (buf_profile[1] == buf[7])); + + /* each profile adds 4 bytes to the response */ + (*index)++; + buf[11] += 4; /* Additional Length */ + + return 4; +} + +static int atapi_read_structure(IDE *ide, int format, + const uint8_t *packet, uint8_t *buf) +{ + switch (format) { + case 0x0: /* Physical format information */ + { + int layer = packet[6]; + uint64_t total_sectors; + + if (layer != 0) + return -ASC_INV_FIELD_IN_CMD_PACKET; + + total_sectors >>= 2; + if (total_sectors == 0) + return -ASC_MEDIUM_NOT_PRESENT; + + buf[4] = 1; /* DVD-ROM, part version 1 */ + buf[5] = 0xf; /* 120mm disc, minimum rate unspecified */ + buf[6] = 1; /* one layer, read-only (per MMC-2 spec) */ + buf[7] = 0; /* default densities */ + + /* FIXME: 0x30000 per spec? */ + buf[8] = buf[9] = buf[10] = buf[11] = 0; /* start sector */ + buf[12] = (total_sectors >> 24) & 0xff; /* end sector */ + buf[13] = (total_sectors >> 16) & 0xff; + buf[14] = (total_sectors >> 8) & 0xff; + buf[15] = total_sectors & 0xff; + + buf[16] = (total_sectors >> 24) & 0xff; /* l0 end sector */ + buf[17] = (total_sectors >> 16) & 0xff; + buf[18] = (total_sectors >> 8) & 0xff; + buf[19] = total_sectors & 0xff; + + /* Size of buffer, not including 2 byte size field */ + buf[0] = ((2048+2)>>8)&0xff; + buf[1] = (2048+2)&0xff; + + /* 2k data + 4 byte header */ + return (2048 + 4); + } + + case 0x01: /* DVD copyright information */ + buf[4] = 0; /* no copyright data */ + buf[5] = 0; /* no region restrictions */ + + /* Size of buffer, not including 2 byte size field */ + buf[0] = ((4+2)>>8)&0xff; + buf[1] = (4+2)&0xff; + + /* 4 byte header + 4 byte data */ + return (4 + 4); + + case 0x03: /* BCA information - invalid field for no BCA info */ + return -ASC_INV_FIELD_IN_CMD_PACKET; + + case 0x04: /* DVD disc manufacturing information */ + /* Size of buffer, not including 2 byte size field */ + buf[0] = ((2048+2)>>8)&0xff; + buf[1] = (2048+2)&0xff; + + /* 2k data + 4 byte header */ + return (2048 + 4); + + case 0xff: + /* + * This lists all the command capabilities above. Add new ones + * in order and update the length and buffer return values. + */ + + buf[4] = 0x00; /* Physical format */ + buf[5] = 0x40; /* Not writable, is readable */ + buf[6] = ((2048+4)>>8)&0xff; + buf[7] = (2048+4)&0xff; + + buf[8] = 0x01; /* Copyright info */ + buf[9] = 0x40; /* Not writable, is readable */ + buf[10] = ((4+4)>>8)&0xff; + buf[11] = (4+4)&0xff; + + buf[12] = 0x03; /* BCA info */ + buf[13] = 0x40; /* Not writable, is readable */ + buf[14] = ((188+4)>>8)&0xff; + buf[15] = (188+4)&0xff; + + buf[16] = 0x04; /* Manufacturing info */ + buf[17] = 0x40; /* Not writable, is readable */ + buf[18] = ((2048+4)>>8)&0xff; + buf[19] = (2048+4)&0xff; + + /* Size of buffer, not including 2 byte size field */ + buf[6] = ((16+2)>>8)&0xff; + buf[7] = (16+2)&0xff; + + /* data written + 4 byte header */ + return (16 + 4); + + default: /* TODO: formats beyond DVD-ROM requires */ + return -ASC_INV_FIELD_IN_CMD_PACKET; + } +} + +static uint32_t atapi_event_status(IDE *ide, uint8_t *buffer) +{ + uint8_t event_code, media_status = 0; + + if (buffer[5]) + { + media_status = MS_TRAY_OPEN; + atapi->stop(); + } + else + { + media_status = MS_MEDIA_PRESENT; + } + + event_code = MEC_NO_CHANGE; + if (media_status != MS_TRAY_OPEN) + { + if (!buffer[4]) + { + event_code = MEC_NEW_MEDIA; + atapi->load(); + } + else if (buffer[4]==2) + { + event_code = MEC_EJECT_REQUESTED; + atapi->eject(); + } + } + + buffer[4] = event_code; + buffer[5] = media_status; + buffer[6] = 0; + buffer[7] = 0; + + return 8; +} + +static int changed_status = 0; + +void atapi_cmd_error(IDE *ide, uint8_t sensekey, uint8_t asc) +{ + ide->error = (sensekey << 4); + ide->atastat = READY_STAT | ERR_STAT; + ide->secount = (ide->secount & ~7) | 3; + ide->packetstatus = 0x80; + idecallback[ide->board]=50*IDE_TIME; +} + +uint8_t atapi_prev; +int toctimes=0; + +void atapi_insert_cdrom() +{ + atapi_sense.sensekey=SENSE_UNIT_ATTENTION; + atapi_sense.asc=ASC_MEDIUM_MAY_HAVE_CHANGED; + atapi_sense.ascq=0; +} + +void atapi_command_send_init(IDE *ide, uint8_t command, int req_length, int alloc_length) +{ + if (ide->cylinder == 0xffff) + ide->cylinder = 0xfffe; + + if ((ide->cylinder & 1) && !(alloc_length <= ide->cylinder)) + { + pclog("Odd byte count (0x%04x) to ATAPI command 0x%02x, using 0x%04x\n", ide->cylinder, command, ide->cylinder - 1); + ide->cylinder--; + } + + if (alloc_length < 0) + fatal("Allocation length < 0\n"); + if (alloc_length == 0) + alloc_length = ide->cylinder; + + // Status: 0x80 (busy), 0x08 (drq), 0x01 (err) + // Interrupt: 0x02 (i_o), 0x01 (c_d) + /* No atastat setting: PCem actually emulates the callback cycle. */ + ide->secount = 2; + + // no bytes transferred yet + ide->pos = 0; + + if ((ide->cylinder > req_length) || (ide->cylinder == 0)) + ide->cylinder = req_length; + if (ide->cylinder > alloc_length) + ide->cylinder = alloc_length; + + //pclog("atapi_command_send_init(ide, %02X, %04X, %04X)\n", command, req_length, alloc_length); + //pclog("IDE settings: Pos=%08X, Secount=%08X, Cylinder=%08X\n", ide->pos, ide->secount, ide->cylinder); +} + +static void atapi_command_ready(int ide_board, int packlen) +{ + IDE *ide = &ide_drives[cur_ide[ide_board]]; + ide->packetstatus = ATAPI_STATUS_REQ_SENSE; + idecallback[ide_board]=60*IDE_TIME; + ide->packlen=packlen; +} + +static void atapi_sense_clear(int command, int ignore_ua) +{ + if ((atapi_sense.sensekey == SENSE_UNIT_ATTENTION) || ignore_ua) + { + atapi_prev=command; + atapi_sense.sensekey=0; + atapi_sense.asc=0; + atapi_sense.ascq=0; + } +} + +int cd_status = CD_STATUS_EMPTY; +int prev_status; + +static void atapicommand(int ide_board) +{ + IDE *ide = &ide_drives[cur_ide[ide_board]]; + uint8_t *idebufferb = (uint8_t *) ide->buffer; + uint8_t rcdmode = 0; + int c; + int len; + int msf; + int pos=0; + unsigned char temp; + uint32_t size; + int is_error; + uint8_t page_code; + int max_len; + unsigned idx = 0; + unsigned size_idx; + unsigned preamble_len; + int toc_format; + int temp_command; + int alloc_length; + int completed; + +#ifndef RPCEMU_IDE + pclog("New ATAPI command %02X %i\n",idebufferb[0],ins); +#endif +// readflash=1; + msf=idebufferb[1]&2; + ide->cdlen=0; + + is_error = 0; + + if (atapi->medium_changed()) + { + atapi_insert_cdrom(); + } + /*If UNIT_ATTENTION is set, error out with NOT_READY. + VIDE-CDD.SYS will then issue a READ_TOC, which can pass through UNIT_ATTENTION and will clear sense. + NT 3.1 / AZTIDECD.SYS will then issue a REQUEST_SENSE, which can also pass through UNIT_ATTENTION but will clear sense AFTER sending it back. + In any case, if the command cannot pass through, set our state to errored.*/ + if (!(atapi_cmd_table[idebufferb[0]] & ALLOW_UA) && atapi_sense.sensekey == SENSE_UNIT_ATTENTION) + { + atapi_cmd_error(ide, atapi_sense.sensekey, atapi_sense.asc); + is_error = 1; + } + /*Unless the command issued was a REQUEST_SENSE or TEST_UNIT_READY, clear sense. + This is important because both VIDE-CDD.SYS and NT 3.1 / AZTIDECD.SYS rely on this behaving VERY specifically. + VIDE-CDD.SYS will clear sense through READ_TOC, while NT 3.1 / AZTIDECD.SYS will issue a REQUEST_SENSE.*/ + if ((idebufferb[0]!=GPCMD_REQUEST_SENSE) && (idebufferb[0]!=GPCMD_TEST_UNIT_READY)) + { + /* GPCMD_TEST_UNIT_READY is NOT supposed to clear sense! */ + atapi_sense_clear(idebufferb[0], 1); + } + + /*If our state has been set to errored, clear it, and return.*/ + if (is_error) + { + is_error = 0; + return; + } + + if ((atapi_cmd_table[idebufferb[0]] & CHECK_READY) && !atapi->ready()) + { + atapi_cmd_error(ide, SENSE_NOT_READY, ASC_MEDIUM_NOT_PRESENT); + atapi_sense.sensekey = SENSE_NOT_READY; + atapi_sense.asc = ASC_MEDIUM_NOT_PRESENT; + atapi_sense.ascq = 0; + return; + } + + prev_status = cd_status; + cd_status = atapi->status(); + if (((prev_status == CD_STATUS_PLAYING) || (prev_status == CD_STATUS_PAUSED)) && ((cd_status != CD_STATUS_PLAYING) && (cd_status != CD_STATUS_PAUSED))) + { + completed = 1; + } + else + { + completed = 0; + } + + switch (idebufferb[0]) + { + case GPCMD_TEST_UNIT_READY: + ide->packetstatus = ATAPI_STATUS_COMPLETE; + idecallback[ide_board]=50*IDE_TIME; + break; + + case GPCMD_REQUEST_SENSE: /* Used by ROS 4+ */ + alloc_length = idebufferb[4]; + temp_command = idebufferb[0]; + atapi_command_send_init(ide, temp_command, 18, alloc_length); + + /*Will return 18 bytes of 0*/ + memset(idebufferb,0,512); + + idebufferb[0]=0x80|0x70; + + if ((atapi_sense.sensekey > 0) || (cd_status < CD_STATUS_PLAYING)) + { + if (completed) + { + idebufferb[2]=SENSE_ILLEGAL_REQUEST; + idebufferb[12]=ASC_AUDIO_PLAY_OPERATION; + idebufferb[13]=ASCQ_AUDIO_PLAY_OPERATION_COMPLETED; + } + else + { + idebufferb[2]=atapi_sense.sensekey; + idebufferb[12]=atapi_sense.asc; + idebufferb[13]=atapi_sense.ascq; + } + } + else + { + idebufferb[2]=SENSE_ILLEGAL_REQUEST; + idebufferb[12]=ASC_AUDIO_PLAY_OPERATION; + idebufferb[13]=(cd_status == CD_STATUS_PLAYING) ? ASCQ_AUDIO_PLAY_OPERATION_IN_PROGRESS : ASCQ_AUDIO_PLAY_OPERATION_PAUSED; + } + + idebufferb[7]=10; + + // pclog("REQUEST SENSE start\n"); + atapi_command_ready(ide_board, 18); + + /* Clear the sense stuff as per the spec. */ + atapi_sense_clear(temp_command, 0); + break; + + case GPCMD_SET_SPEED: + ide->packetstatus = ATAPI_STATUS_COMPLETE; + idecallback[ide_board]=50*IDE_TIME; + break; + + case GPCMD_MECHANISM_STATUS: /*0xbd*/ + len=(idebufferb[7]<<16)|(idebufferb[8]<<8)|idebufferb[9]; + + if (len == 0) + fatal("Zero allocation length to MECHANISM STATUS not impl.\n"); + + atapi_command_send_init(ide, idebufferb[0], 8, alloc_length); + + idebufferb[0] = 0; + idebufferb[1] = 0; + idebufferb[2] = 0; + idebufferb[3] = 0; + idebufferb[4] = 0; + idebufferb[5] = 1; + idebufferb[6] = 0; + idebufferb[7] = 0; + // len = 8; + + atapi_command_ready(ide_board, 8); + break; + + case GPCMD_READ_TOC_PMA_ATIP: +// pclog("Read TOC ready? %08X\n",ide); + toctimes++; +// if (toctimes==2) output=3; +// pclog("Read TOC %02X\n",idebufferb[9]); + toc_format = idebufferb[2] & 0xf; + if (toc_format == 0) + toc_format = (idebufferb[9]>>6) & 3; + switch (toc_format) + { + case 0: /*Normal*/ + // pclog("ATAPI: READ TOC type requested: Normal\n"); + len=idebufferb[8]+(idebufferb[7]<<8); + len=atapi->readtoc(idebufferb,idebufferb[6],msf,len,0); + break; + case 1: /*Multi session*/ + // pclog("ATAPI: READ TOC type requested: Multi-session\n"); + len=idebufferb[8]+(idebufferb[7]<<8); + len=atapi->readtoc_session(idebufferb,msf,len); + idebufferb[0]=0; idebufferb[1]=0xA; + break; + case 2: /*Raw*/ + // pclog("ATAPI: READ TOC type requested: Raw TOC\n"); + len=idebufferb[8]+(idebufferb[7]<<8); + len=atapi->readtoc_raw(idebufferb,len); + break; + default: + // pclog("ATAPI: Unknown READ TOC type requested: %i\n", (idebufferb[9]>>6)); + ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + if (atapi_sense.sensekey == SENSE_UNIT_ATTENTION) + ide->error |= MCR_ERR; + ide->packetstatus = ATAPI_STATUS_ERROR; + idecallback[ide_board]=50*IDE_TIME; + return; +/* pclog("Bad read TOC format\n"); + pclog("Packet data :\n"); + for (c=0;c<12;c++) + pclog("%02X ",idebufferb[c]); + pclog("\n"); + exit(-1);*/ + } +// pclog("ATAPI buffer len %i\n",len); + ide->packetstatus = ATAPI_STATUS_DATA; + ide->cylinder=len; + ide->secount=2; + ide->pos=0; + idecallback[ide_board]=60*IDE_TIME; + ide->packlen=len; + return; + + case GPCMD_READ_CD: +// pclog("Read CD : start LBA %02X%02X%02X%02X Length %02X%02X%02X Flags %02X\n",idebufferb[2],idebufferb[3],idebufferb[4],idebufferb[5],idebufferb[6],idebufferb[7],idebufferb[8],idebufferb[9]); + rcdmode = idebufferb[9] & 0xF8; + if ((rcdmode != 0x10) && (rcdmode != 0xF8)) + { + ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + if (atapi_sense.sensekey == SENSE_UNIT_ATTENTION) + ide->error |= MCR_ERR; + atapi_sense.asc = ASC_ILLEGAL_OPCODE; + ide->packetstatus = ATAPI_STATUS_ERROR; + idecallback[ide_board]=50*IDE_TIME; + break; +// pclog("Bad flags bits %02X\n",idebufferb[9]); +// exit(-1); + } +/* if (idebufferb[6] || idebufferb[7] || (idebufferb[8]!=1)) + { + pclog("More than 1 sector!\n"); + exit(-1); + }*/ + ide->cdlen=(idebufferb[6]<<16)|(idebufferb[7]<<8)|idebufferb[8]; + ide->cdpos=(idebufferb[2]<<24)|(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; +// pclog("Read at %08X %08X\n",ide.cdpos,ide.cdpos*2048); + if (rcdmode == 0x10) + atapi->readsector(idebufferb,ide->cdpos); + else + atapi->readsector_raw(idebufferb,ide->cdpos); +#ifndef RPCEMU_IDE + readflash=1; +#endif + readcdmode = (rcdmode == 0xF8); + ide->cdpos++; + ide->cdlen--; + if (ide->cdlen >= 0) + ide->packetstatus = ATAPI_STATUS_READCD; + else + ide->packetstatus = ATAPI_STATUS_DATA; + ide->cylinder=(idebufferb[9] == 0x10) ? 2048 : 2352; + ide->secount=2; + ide->pos=0; + idecallback[ide_board]=60*IDE_TIME; + ide->packlen=(idebufferb[9] == 0x10) ? 2048 : 2352; + return; + + case GPCMD_READ_6: + case GPCMD_READ_10: + case GPCMD_READ_12: +// pclog("Read 10 : start LBA %02X%02X%02X%02X Length %02X%02X%02X Flags %02X\n",idebufferb[2],idebufferb[3],idebufferb[4],idebufferb[5],idebufferb[6],idebufferb[7],idebufferb[8],idebufferb[9]); + + readcdmode = 0; + + if (idebufferb[0] == GPCMD_READ_6) + { + ide->cdlen=idebufferb[4]; + ide->cdpos=((((uint32_t) idebufferb[1]) & 0x1f)<<16)|(((uint32_t) idebufferb[2])<<8)|((uint32_t) idebufferb[3]); + } + else if (idebufferb[0] == GPCMD_READ_10) + { + ide->cdlen=(idebufferb[7]<<8)|idebufferb[8]; + ide->cdpos=(idebufferb[2]<<24)|(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; + } + else + { + ide->cdlen=(((uint32_t) idebufferb[6])<<24)|(((uint32_t) idebufferb[7])<<16)|(((uint32_t) idebufferb[8])<<8)|((uint32_t) idebufferb[9]); + ide->cdpos=(((uint32_t) idebufferb[2])<<24)|(((uint32_t) idebufferb[3])<<16)|(((uint32_t) idebufferb[4])<<8)|((uint32_t) idebufferb[5]); + } + if (!ide->cdlen) + { +// pclog("All done - callback set\n"); + ide->packetstatus = ATAPI_STATUS_COMPLETE; + idecallback[ide_board]=20*IDE_TIME; + break; + } + + atapi->readsector(idebufferb,ide->cdpos); +#ifndef RPCEMU_IDE + readflash=1; +#endif + ide->cdpos++; + ide->cdlen--; + if (ide->cdlen >= 0) + ide->packetstatus = ATAPI_STATUS_READCD; + else + ide->packetstatus = ATAPI_STATUS_DATA; + ide->cylinder=2048; + ide->secount=2; + ide->pos=0; + idecallback[ide_board]=60*IDE_TIME; + ide->packlen=2048; + return; + + case GPCMD_READ_HEADER: + if (msf) + { + ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + if (atapi_sense.sensekey == SENSE_UNIT_ATTENTION) + { + ide->error |= MCR_ERR; + } + atapi_sense.asc = ASC_ILLEGAL_OPCODE; + ide->packetstatus = ATAPI_STATUS_ERROR; + idecallback[ide_board]=50*IDE_TIME; + break; +// pclog("Read Header MSF!\n"); +// exit(-1); + } + for (c=0;c<4;c++) idebufferb[c+4]=idebufferb[c+2]; + idebufferb[0]=1; /*2048 bytes user data*/ + idebufferb[1]=idebufferb[2]=idebufferb[3]=0; + + ide->packetstatus = ATAPI_STATUS_DATA; + ide->cylinder=8; + ide->secount=2; + ide->pos=0; + idecallback[ide_board]=60*IDE_TIME; + ide->packlen=8; + return; + + case GPCMD_MODE_SENSE_6: + case GPCMD_MODE_SENSE_10: + temp_command = idebufferb[0]; + + if (temp_command == GPCMD_MODE_SENSE_6) + len=idebufferb[4]; + else + len=(idebufferb[8]|(idebufferb[7]<<8)); + + temp=idebufferb[2] & 0x3F; + + memset(idebufferb, 0, len); + alloc_length = len; + // for (c=0;catastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + idecallback[ide_board]=50*IDE_TIME; + atapi_cmd_error(ide, atapi_sense.sensekey, atapi_sense.asc); + ide->atastat = 0x53; + ide->packetstatus = ATAPI_STATUS_ERROR; + atapi_sense.sensekey = SENSE_ILLEGAL_REQUEST; + atapi_sense.asc = ASC_INV_FIELD_IN_CMD_PACKET; + atapi_sense.ascq = 0; + return; + } + + if (temp_command == GPCMD_MODE_SENSE_6) + { + len = ide_atapi_mode_sense(ide,4,temp); + idebufferb[0] = len - 1; + idebufferb[1]=3; /*120mm data CD-ROM*/ + } + else + { + len = ide_atapi_mode_sense(ide,8,temp); + idebufferb[0]=(len - 2)>>8; + idebufferb[1]=(len - 2)&255; + idebufferb[2]=3; /*120mm data CD-ROM*/ + } + + atapi_command_send_init(ide, temp_command, len, alloc_length); + + atapi_command_ready(ide_board, len); + return; + + case GPCMD_MODE_SELECT_6: + case GPCMD_MODE_SELECT_10: + if (ide->packetstatus == ATAPI_STATUS_PACKET_RECEIVED) + { + ide->atastat = READY_STAT; + ide->secount=3; +// pclog("Recieve data packet!\n"); + ide_irq_raise(ide); + ide->packetstatus=0xFF; + ide->pos=0; + // pclog("Length - %02X%02X\n",idebufferb[0],idebufferb[1]); +// pclog("Page %02X length %02X\n",idebufferb[8],idebufferb[9]); + } + else + { + if (idebufferb[0] == GPCMD_MODE_SELECT_6) + { + len=idebufferb[4]; + prefix_len = 6; + } + else + { + len=(idebufferb[7]<<8)|idebufferb[8]; + prefix_len = 10; + } + page_current = idebufferb[2]; + if (page_flags[page_current] & PAGE_CHANGEABLE) + page_flags[GPMODE_CDROM_AUDIO_PAGE] |= PAGE_CHANGED; + ide->packetstatus = ATAPI_STATUS_PACKET_REQ; + ide->cylinder=len; + ide->secount=0; + ide->pos=0; + idecallback[ide_board]=60*IDE_TIME; + ide->packlen=len; +/* pclog("Waiting for ARM to send packet %i\n",len); + pclog("Packet data :\n"); + for (c=0;c<12;c++) + pclog("%02X ",idebufferb[c]); + pclog("\n");*/ + } + return; + + case GPCMD_GET_CONFIGURATION: + { + temp_command = idebufferb[0]; + /* XXX: could result in alignment problems in some architectures */ + len = (idebufferb[7]<<8)|idebufferb[8]; + alloc_length = len; + + uint8_t index = 0; + + /* only feature 0 is supported */ + if (idebufferb[2] != 0 || idebufferb[3] != 0) + { + ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + if (atapi_sense.sensekey == SENSE_UNIT_ATTENTION) + ide->error |= MCR_ERR; + atapi_sense.asc = ASC_INV_FIELD_IN_CMD_PACKET; + ide->packetstatus = ATAPI_STATUS_ERROR; + idecallback[ide_board]=50*IDE_TIME; + return; + } + + /* + * XXX: avoid overflow for io_buffer if len is bigger than + * the size of that buffer (dimensioned to max number of + * sectors to transfer at once) + * + * Only a problem if the feature/profiles grow. + */ + if (alloc_length > 512) /* XXX: assume 1 sector */ + alloc_length = 512; + + memset(idebufferb, 0, alloc_length); + /* + * the number of sectors from the media tells us which profile + * to use as current. 0 means there is no media + */ + if (len > CD_MAX_SECTORS ) + { + idebufferb[6] = (MMC_PROFILE_DVD_ROM >> 8) & 0xff; + idebufferb[7] = MMC_PROFILE_DVD_ROM & 0xff; + } + else if (len <= CD_MAX_SECTORS) + { + idebufferb[6] = (MMC_PROFILE_CD_ROM >> 8) & 0xff; + idebufferb[7] = MMC_PROFILE_CD_ROM & 0xff; + } + idebufferb[10] = 0x02 | 0x01; /* persistent and current */ + alloc_length = 12; /* headers: 8 + 4 */ + alloc_length += atapi_set_profile(idebufferb, &index, MMC_PROFILE_DVD_ROM); + alloc_length += atapi_set_profile(idebufferb, &index, MMC_PROFILE_CD_ROM); + idebufferb[0] = ((alloc_length-4) >> 24) & 0xff; + idebufferb[1] = ((alloc_length-4) >> 16) & 0xff; + idebufferb[2] = ((alloc_length-4) >> 8) & 0xff; + idebufferb[3] = (alloc_length-4) & 0xff; + + atapi_command_send_init(ide, temp_command, len, alloc_length); + + atapi_command_ready(ide_board, len); + } + break; + + case GPCMD_GET_EVENT_STATUS_NOTIFICATION: /*0x4a*/ + temp_command = idebufferb[0]; + alloc_length = len; + + { + struct + { + uint8_t opcode; + uint8_t polled; + uint8_t reserved2[2]; + uint8_t class; + uint8_t reserved3[2]; + uint16_t len; + uint8_t control; + } *gesn_cdb; + + struct + { + uint16_t len; + uint8_t notification_class; + uint8_t supported_events; + } *gesn_event_header; + unsigned int used_len; + + gesn_cdb = (void *)idebufferb; + gesn_event_header = (void *)idebufferb; + + /* It is fine by the MMC spec to not support async mode operations */ + if (!(gesn_cdb->polled & 0x01)) + { /* asynchronous mode */ + /* Only pollign is supported, asynchronous mode is not. */ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + idecallback[ide_board]=50*IDE_TIME; + atapi_cmd_error(ide, atapi_sense.sensekey, atapi_sense.asc); + ide->atastat = 0x53; + ide->packetstatus=0x80; + atapi_sense.sensekey = SENSE_ILLEGAL_REQUEST; + atapi_sense.asc = ASC_INV_FIELD_IN_CMD_PACKET; + atapi_sense.ascq = 0; + return; + } + + /* polling mode operation */ + + /* + * These are the supported events. + * + * We currently only support requests of the 'media' type. + * Notification class requests and supported event classes are bitmasks, + * but they are built from the same values as the "notification class" + * field. + */ + gesn_event_header->supported_events = 1 << GESN_MEDIA; + + /* + * We use |= below to set the class field; other bits in this byte + * are reserved now but this is useful to do if we have to use the + * reserved fields later. + */ + gesn_event_header->notification_class = 0; + + /* + * Responses to requests are to be based on request priority. The + * notification_class_request_type enum above specifies the + * priority: upper elements are higher prio than lower ones. + */ + if (gesn_cdb->class & (1 << GESN_MEDIA)) + { + gesn_event_header->notification_class |= GESN_MEDIA; + used_len = atapi_event_status(ide, idebufferb); + } + else + { + gesn_event_header->notification_class = 0x80; /* No event available */ + used_len = sizeof(*gesn_event_header); + } + gesn_event_header->len = used_len - sizeof(*gesn_event_header); + } + + atapi_command_send_init(ide, temp_command, len, alloc_length); + + atapi_command_ready(ide_board, len); + break; + + case GPCMD_READ_DISC_INFORMATION: + idebufferb[1] = 32; + idebufferb[2] = 0xe; /* last session complete, disc finalized */ + idebufferb[3] = 1; /* first track on disc */ + idebufferb[4] = 1; /* # of sessions */ + idebufferb[5] = 1; /* first track of last session */ + idebufferb[6] = 1; /* last track of last session */ + idebufferb[7] = 0x20; /* unrestricted use */ + idebufferb[8] = 0x00; /* CD-ROM */ + + len=34; + ide->packetstatus = ATAPI_STATUS_DATA; + ide->cylinder=len; + ide->secount=2; + ide->pos=0; + idecallback[ide_board]=60*IDE_TIME; + ide->packlen=len; + break; + + case GPCMD_PLAY_AUDIO_10: + case GPCMD_PLAY_AUDIO_12: + case GPCMD_PLAY_AUDIO_MSF: + /*This is apparently deprecated in the ATAPI spec, and apparently + has been since 1995 (!). Hence I'm having to guess most of it*/ + if (idebufferb[0] == GPCMD_PLAY_AUDIO_10) + { + pos=(idebufferb[2]<<24)|(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; + len=(idebufferb[7]<<8)|idebufferb[8]; + } + else if (idebufferb[0] == GPCMD_PLAY_AUDIO_MSF) + { + pos=(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; + len=(idebufferb[6]<<16)|(idebufferb[7]<<8)|idebufferb[8]; + } + else + { + pos=(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; + len=(idebufferb[7]<<16)|(idebufferb[8]<<8)|idebufferb[9]; + } + + + if ((cdrom_drive < 1) || (cdrom_drive == CDROM_ISO) || (cd_status <= CD_STATUS_DATA_ONLY) || + !atapi->is_track_audio(pos, (idebufferb[0] == GPCMD_PLAY_AUDIO_MSF) ? 1 : 0)) + { + ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + atapi_sense.sensekey = SENSE_ILLEGAL_REQUEST; + atapi_sense.asc = ASC_ILLEGAL_MODE_FOR_THIS_TRACK; + atapi_sense.ascq = 0; + ide->packetstatus = ATAPI_STATUS_ERROR; + idecallback[ide_board]=50*IDE_TIME; + atapi_cmd_error(ide, atapi_sense.sensekey, atapi_sense.asc); + break; + } + + atapi->playaudio(pos, len, (idebufferb[0] == GPCMD_PLAY_AUDIO_MSF) ? 1 : 0); + ide->packetstatus = ATAPI_STATUS_COMPLETE; + idecallback[ide_board]=50*IDE_TIME; + break; + + case GPCMD_READ_SUBCHANNEL: + temp=idebufferb[2]&0x40; + if (idebufferb[3]!=1) + { +// pclog("Read subchannel check condition %02X\n",idebufferb[3]); + ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + if (atapi_sense.sensekey == SENSE_UNIT_ATTENTION) + ide->error |= MCR_ERR; + // ide->discchanged=1; /* Fixes some bugs with NT 3.1. */ + atapi_sense.asc = ASC_ILLEGAL_OPCODE; + ide->packetstatus = ATAPI_STATUS_ERROR; + idecallback[ide_board]=50*IDE_TIME; + break; +/* pclog("Bad read subchannel!\n"); + pclog("Packet data :\n"); + for (c=0;c<12;c++) + pclog("%02X\n",idebufferb[c]); + dumpregs(); + exit(-1);*/ + } + pos=0; + idebufferb[pos++]=0; + idebufferb[pos++]=0; /*Audio status*/ + idebufferb[pos++]=0; idebufferb[pos++]=0; /*Subchannel length*/ + idebufferb[pos++]=1; /*Format code*/ + idebufferb[1]=atapi->getcurrentsubchannel(&idebufferb[5],msf); +// pclog("Read subchannel complete - audio status %02X\n",idebufferb[1]); + len=11+5; + if (!temp) len=4; + ide->packetstatus = ATAPI_STATUS_DATA; + ide->cylinder=len; + ide->secount=2; + ide->pos=0; + idecallback[ide_board]=1000*IDE_TIME; + ide->packlen=len; + break; + + case GPCMD_READ_DVD_STRUCTURE: + temp_command = idebufferb[0]; + int media = idebufferb[1]; + int format = idebufferb[7]; + int ret; + + len = (((uint32_t) idebufferb[6])<<24)|(((uint32_t) idebufferb[7])<<16)|(((uint32_t) idebufferb[8])<<8)|((uint32_t) idebufferb[9]); + alloc_length = len; + + if (format < 0xff) { + if (len <= CD_MAX_SECTORS) { + ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + atapi_sense.asc = ASC_INCOMPATIBLE_FORMAT; + ide->packetstatus = ATAPI_STATUS_ERROR; + idecallback[ide_board]=50*IDE_TIME; + break; + } else { + ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + if (atapi_sense.sensekey == SENSE_UNIT_ATTENTION) + ide->error |= MCR_ERR; + atapi_sense.asc = ASC_INV_FIELD_IN_CMD_PACKET; + ide->packetstatus = ATAPI_STATUS_ERROR; + idecallback[ide_board]=50*IDE_TIME; + return; + } + } + + memset(idebufferb, 0, alloc_length > 256 * 512 + 4 ? + 256 * 512 + 4 : alloc_length); + + switch (format) { + case 0x00 ... 0x7f: + case 0xff: + if (media == 0) { + ret = atapi_read_structure(ide, format, idebufferb, idebufferb); + + if (ret < 0) + atapi_cmd_error(ide, SENSE_ILLEGAL_REQUEST, -ret); + else + { + atapi_command_send_init(ide, temp_command, len, alloc_length); + atapi_command_ready(ide_board, len); + } + break; + } + /* TODO: BD support, fall through for now */ + + /* Generic disk structures */ + case 0x80: /* TODO: AACS volume identifier */ + case 0x81: /* TODO: AACS media serial number */ + case 0x82: /* TODO: AACS media identifier */ + case 0x83: /* TODO: AACS media key block */ + case 0x90: /* TODO: List of recognized format layers */ + case 0xc0: /* TODO: Write protection status */ + default: + ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + if (atapi_sense.sensekey == SENSE_UNIT_ATTENTION) + ide->error |= MCR_ERR; + atapi_sense.asc = ASC_INV_FIELD_IN_CMD_PACKET; + ide->packetstatus = ATAPI_STATUS_ERROR; + idecallback[ide_board]=50*IDE_TIME; + return; + } + break; + + case GPCMD_START_STOP_UNIT: + if (idebufferb[4]!=2 && idebufferb[4]!=3 && idebufferb[4]) + { + ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + if (atapi_sense.sensekey == SENSE_UNIT_ATTENTION) + ide->error |= MCR_ERR; + atapi_sense.asc = ASC_ILLEGAL_OPCODE; + ide->packetstatus = ATAPI_STATUS_ERROR; + idecallback[ide_board]=50*IDE_TIME; + break; +/* pclog("Bad start/stop unit command\n"); + pclog("Packet data :\n"); + for (c=0;c<12;c++) + pclog("%02X\n",idebufferb[c]); + exit(-1);*/ + } + if (!idebufferb[4]) atapi->stop(); + else if (idebufferb[4]==2) atapi->eject(); + else atapi->load(); + ide->packetstatus = ATAPI_STATUS_COMPLETE; + idecallback[ide_board]=50*IDE_TIME; + break; + + case GPCMD_INQUIRY: + page_code = idebufferb[2]; + max_len = idebufferb[4]; + alloc_length = max_len; + temp_command = idebufferb[0]; + + if (idebufferb[1] & 1) + { + preamble_len = 4; + size_idx = 3; + + idebufferb[idx++] = 05; + idebufferb[idx++] = page_code; + idebufferb[idx++] = 0; + + idx++; + + switch (page_code) + { + case 0x00: + idebufferb[idx++] = 0x00; + idebufferb[idx++] = 0x83; + break; + case 0x83: + if (idx + 24 > max_len) + { + atapi_cmd_error(ide, SENSE_ILLEGAL_REQUEST, ASC_DATA_PHASE_ERROR); + atapi_sense.sensekey = SENSE_ILLEGAL_REQUEST; + atapi_sense.asc = ASC_DATA_PHASE_ERROR; + return; + } + idebufferb[idx++] = 0x02; + idebufferb[idx++] = 0x00; + idebufferb[idx++] = 0x00; + idebufferb[idx++] = 20; + ide_padstr8(idebufferb + idx, 20, "53R141"); /* Serial */ + idx += 20; + + if (idx + 72 > max_len) + { + goto atapi_out; + } + idebufferb[idx++] = 0x02; + idebufferb[idx++] = 0x01; + idebufferb[idx++] = 0x00; + idebufferb[idx++] = 68; + ide_padstr8(idebufferb + idx, 8, "PCem"); /* Vendor */ + idx += 8; + ide_padstr8(idebufferb + idx, 40, "PCemCD v1.0"); /* Product */ + idx += 40; + ide_padstr8(idebufferb + idx, 20, "53R141"); /* Product */ + idx += 20; + + break; + default: + atapi_cmd_error(ide, SENSE_ILLEGAL_REQUEST, ASC_INV_FIELD_IN_CMD_PACKET); + atapi_sense.sensekey = SENSE_ILLEGAL_REQUEST; + atapi_sense.asc = ASC_INV_FIELD_IN_CMD_PACKET; + return; + } + } + else + { + preamble_len = 5; + size_idx = 4; + + idebufferb[0] = 5; /*CD-ROM*/ + idebufferb[1] = 0x80; /*Removable*/ + idebufferb[2] = 0; + idebufferb[3] = 0x21; + idebufferb[4] = 31; + idebufferb[5] = 0; + idebufferb[6] = 0; + idebufferb[7] = 0; +#ifdef RPCEMU_IDE + ide_padstr8(idebufferb + 8, 8, "RPCemu"); /* Vendor */ + ide_padstr8(idebufferb + 16, 16, "RPCemuCD"); /* Product */ +#else + ide_padstr8(idebufferb + 8, 8, "PCem"); /* Vendor */ + ide_padstr8(idebufferb + 16, 16, "PCemCD"); /* Product */ +#endif + ide_padstr8(idebufferb + 32, 4, "1.0"); /* Revision */ + + idx = 36; + } + +atapi_out: + idebufferb[size_idx] = idx - preamble_len; + len=idx; + + atapi_command_send_init(ide, temp_command, len, alloc_length); + + atapi_command_ready(ide_board, len); + break; + + case GPCMD_PREVENT_REMOVAL: + ide->packetstatus = ATAPI_STATUS_COMPLETE; + idecallback[ide_board]=50*IDE_TIME; + break; + + case GPCMD_PAUSE_RESUME: + if (idebufferb[8]&1) atapi->resume(); + else atapi->pause(); + ide->packetstatus = ATAPI_STATUS_COMPLETE; + idecallback[ide_board]=50*IDE_TIME; + break; + + case GPCMD_SEEK: + pos=(idebufferb[3]<<16)|(idebufferb[4]<<8)|idebufferb[5]; + atapi->seek(pos); + ide->packetstatus = ATAPI_STATUS_COMPLETE; + idecallback[ide_board]=50*IDE_TIME; + break; + + case GPCMD_READ_CDROM_CAPACITY: + atapi_command_send_init(ide, temp_command, 8, 8); + size = atapi->size(); + idebufferb[0] = (size >> 24) & 0xff; + idebufferb[1] = (size >> 16) & 0xff; + idebufferb[2] = (size >> 8) & 0xff; + idebufferb[3] = size & 0xff; + idebufferb[4] = (2048 >> 24) & 0xff; + idebufferb[5] = (2048 >> 16) & 0xff; + idebufferb[6] = (2048 >> 8) & 0xff; + idebufferb[7] = 2048 & 0xff; + len=8; + atapi_command_ready(ide_board, len); + break; + + case GPCMD_SEND_DVD_STRUCTURE: + default: +bad_atapi_command: + ide->atastat = READY_STAT | ERR_STAT; /*CHECK CONDITION*/ + ide->error = (SENSE_ILLEGAL_REQUEST << 4) | ABRT_ERR; + if (atapi_sense.sensekey == SENSE_UNIT_ATTENTION) + ide->error |= MCR_ERR; + atapi_sense.sensekey = SENSE_ILLEGAL_REQUEST; + atapi_sense.asc = ASC_ILLEGAL_OPCODE; + ide->packetstatus = ATAPI_STATUS_ERROR; + idecallback[ide_board]=50*IDE_TIME; + break; + + case GPCMD_STOP_PLAY_SCAN: + atapi->stop(); + ide->packetstatus = ATAPI_STATUS_COMPLETE; + idecallback[ide_board]=50*IDE_TIME; + break; +/* default: + pclog("Bad ATAPI command %02X\n",idebufferb[0]); + pclog("Packet data :\n"); + for (c=0;c<12;c++) + pclog("%02X\n",idebufferb[c]); + exit(-1);*/ + } +} + +static void callnonreadcd(IDE *ide) /* Callabck for non-Read CD commands */ +{ + ide_irq_lower(ide); + if (ide->pos >= ide->packlen) + { + // pclog("Command finished, setting callback\n"); + ide->packetstatus = ATAPI_STATUS_COMPLETE; + idecallback[ide->board]=20*IDE_TIME; + } + else + { + // pclog("Command not finished, keep sending data\n"); + ide->atastat = BUSY_STAT; + ide->packetstatus = ATAPI_STATUS_REQ_SENSE; + ide->cylinder=2; + ide->secount=2; + idecallback[ide->board]=60*IDE_TIME; + } +} + +static void callreadcd(IDE *ide) +{ + ide_irq_lower(ide); + if (ide->cdlen<=0) + { +// pclog("All done - callback set\n"); + ide->packetstatus = ATAPI_STATUS_COMPLETE; + idecallback[ide->board]=20*IDE_TIME; + return; + } +// pclog("Continue readcd! %i blocks left\n",ide->cdlen); + ide->atastat = BUSY_STAT; + + if (readcdmode) + atapi->readsector_raw((uint8_t *) ide->buffer, ide->cdpos); + else + atapi->readsector((uint8_t *) ide->buffer, ide->cdpos); +#ifndef RPCEMU_IDE + readflash=1; +#endif + ide->cdpos++; + ide->cdlen--; + ide->packetstatus = ATAPI_STATUS_READCD; + ide->cylinder=readcdmode ? 2352 : 2048; + ide->secount=2; + ide->pos=0; + idecallback[ide->board]=60*IDE_TIME; + ide->packlen=readcdmode ? 2352 : 2048; +} + + + +void ide_write_pri(uint16_t addr, uint8_t val, void *priv) +{ + writeide(0, addr, val); +} +void ide_write_pri_w(uint16_t addr, uint16_t val, void *priv) +{ + writeidew(0, val); +} +void ide_write_pri_l(uint16_t addr, uint32_t val, void *priv) +{ + writeidel(0, val); +} +uint8_t ide_read_pri(uint16_t addr, void *priv) +{ + return readide(0, addr); +} +uint16_t ide_read_pri_w(uint16_t addr, void *priv) +{ + return readidew(0); +} +uint32_t ide_read_pri_l(uint16_t addr, void *priv) +{ + return readidel(0); +} + +void ide_write_sec(uint16_t addr, uint8_t val, void *priv) +{ + writeide(1, addr, val); +} +void ide_write_sec_w(uint16_t addr, uint16_t val, void *priv) +{ + writeidew(1, val); +} +void ide_write_sec_l(uint16_t addr, uint32_t val, void *priv) +{ + writeidel(1, val); +} +uint8_t ide_read_sec(uint16_t addr, void *priv) +{ + return readide(1, addr); +} +uint16_t ide_read_sec_w(uint16_t addr, void *priv) +{ + return readidew(1); +} +uint32_t ide_read_sec_l(uint16_t addr, void *priv) +{ + return readidel(1); +} + +/* *** REMOVE FROM CODE SUBMITTED TO MAINLINE - START *** */ +void ide_write_ter(uint16_t addr, uint8_t val, void *priv) +{ + writeide(2, addr, val); +} +void ide_write_ter_w(uint16_t addr, uint16_t val, void *priv) +{ + writeidew(2, val); +} +void ide_write_ter_l(uint16_t addr, uint32_t val, void *priv) +{ + writeidel(2, val); +} +uint8_t ide_read_ter(uint16_t addr, void *priv) +{ + return readide(2, addr); +} +uint16_t ide_read_ter_w(uint16_t addr, void *priv) +{ + return readidew(2); +} +uint32_t ide_read_ter_l(uint16_t addr, void *priv) +{ + return readidel(2); +} +/* *** REMOVE FROM CODE SUBMITTED TO MAINLINE - END *** */ + +void ide_pri_enable() +{ + io_sethandler(0x01f0, 0x0008, ide_read_pri, ide_read_pri_w, ide_read_pri_l, ide_write_pri, ide_write_pri_w, ide_write_pri_l, NULL); + io_sethandler(0x03f6, 0x0001, ide_read_pri, NULL, NULL, ide_write_pri, NULL, NULL , NULL); +} + +void ide_pri_disable() +{ + io_removehandler(0x01f0, 0x0008, ide_read_pri, ide_read_pri_w, ide_read_pri_l, ide_write_pri, ide_write_pri_w, ide_write_pri_l, NULL); + io_removehandler(0x03f6, 0x0001, ide_read_pri, NULL, NULL, ide_write_pri, NULL, NULL , NULL); +} + +void ide_sec_enable() +{ + io_sethandler(0x0170, 0x0008, ide_read_sec, ide_read_sec_w, ide_read_sec_l, ide_write_sec, ide_write_sec_w, ide_write_sec_l, NULL); + io_sethandler(0x0376, 0x0001, ide_read_sec, NULL, NULL, ide_write_sec, NULL, NULL , NULL); +} + +void ide_sec_disable() +{ + io_removehandler(0x0170, 0x0008, ide_read_sec, ide_read_sec_w, ide_read_sec_l, ide_write_sec, ide_write_sec_w, ide_write_sec_l, NULL); + io_removehandler(0x0376, 0x0001, ide_read_sec, NULL, NULL, ide_write_sec, NULL, NULL , NULL); +} + +/* *** REMOVE FROM CODE SUBMITTED TO MAINLINE - START *** */ +void ide_ter_enable() +{ + io_sethandler(0x0168, 0x0008, ide_read_ter, ide_read_ter_w, ide_read_ter_l, ide_write_ter, ide_write_ter_w, ide_write_ter_l, NULL); + io_sethandler(0x036e, 0x0001, ide_read_ter, NULL, NULL, ide_write_ter, NULL, NULL , NULL); +} + +void ide_ter_disable() +{ + io_removehandler(0x0168, 0x0008, ide_read_ter, ide_read_ter_w, ide_read_ter_l, ide_write_ter, ide_write_ter_w, ide_write_ter_l, NULL); + io_removehandler(0x036e, 0x0001, ide_read_ter, NULL, NULL, ide_write_ter, NULL, NULL , NULL); +} + +void ide_ter_init() +{ + ide_ter_enable(); + + timer_add(ide_callback_ter, &idecallback[2], &idecallback[2], NULL); +} +/* *** REMOVE FROM CODE SUBMITTED TO MAINLINE - END *** */ + +void ide_init() +{ + ide_pri_enable(); + ide_sec_enable(); + ide_bus_master_read_sector = ide_bus_master_write_sector = NULL; + + timer_add(ide_callback_pri, &idecallback[0], &idecallback[0], NULL); + timer_add(ide_callback_sec, &idecallback[1], &idecallback[1], NULL); +} + +void ide_set_bus_master(int (*read_sector)(int channel, uint8_t *data), int (*write_sector)(int channel, uint8_t *data), void (*set_irq)(int channel)) +{ + ide_bus_master_read_sector = read_sector; + ide_bus_master_write_sector = write_sector; + ide_bus_master_set_irq = set_irq; +} diff --git a/src/ide.h b/src/ide.h new file mode 100644 index 000000000..f4861a232 --- /dev/null +++ b/src/ide.h @@ -0,0 +1,60 @@ +#ifndef __IDE__ +#define __IDE__ + +struct IDE; + +extern void writeide(int ide_board, uint16_t addr, uint8_t val); +extern void writeidew(int ide_board, uint16_t val); +extern uint8_t readide(int ide_board, uint16_t addr); +extern uint16_t readidew(int ide_board); +extern void callbackide(int ide_board); +extern void resetide(void); +extern void ide_init(); +extern void ide_ter_init(); +extern void ide_pri_enable(); +extern void ide_sec_enable(); +extern void ide_ter_enable(); +extern void ide_pri_disable(); +extern void ide_sec_disable(); +extern void ide_ter_disable(); +extern void ide_set_bus_master(int (*read_sector)(int channel, uint8_t *data), int (*write_sector)(int channel, uint8_t *data), void (*set_irq)(int channel)); + +/*ATAPI stuff*/ +typedef struct ATAPI +{ + int (*ready)(void); + int (*medium_changed)(void); + int (*readtoc)(uint8_t *b, uint8_t starttrack, int msf, int maxlen, int single); + int (*readtoc_session)(uint8_t *b, int msf, int maxlen); + int (*readtoc_raw)(uint8_t *b, int maxlen); + uint8_t (*getcurrentsubchannel)(uint8_t *b, int msf); + void (*readsector)(uint8_t *b, int sector); + void (*readsector_raw)(uint8_t *b, int sector); + void (*playaudio)(uint32_t pos, uint32_t len, int ismsf); + void (*seek)(uint32_t pos); + void (*load)(void); + void (*eject)(void); + void (*pause)(void); + void (*resume)(void); + uint32_t (*size)(void); + int (*status)(void); + int (*is_track_audio)(uint32_t pos, int ismsf); + void (*stop)(void); + void (*exit)(void); +} ATAPI; + +extern ATAPI *atapi; + +void atapi_discchanged(); + +void atapi_insert_cdrom(); + +extern int ideboard; + +extern int idecallback[3]; + +extern char ide_fn[4][512]; + +extern int cdrom_channel; + +#endif //__IDE__ diff --git a/src/intel.c b/src/intel.c new file mode 100644 index 000000000..5b96fca6f --- /dev/null +++ b/src/intel.c @@ -0,0 +1,81 @@ +#include "ibm.h" +#include "cpu.h" +#include "io.h" +#include "mem.h" +#include "pit.h" +#include "timer.h" + +#include "intel.h" + +uint8_t batman_brdconfig(uint16_t port, void *p) +{ +// pclog("batman_brdconfig read port=%04x\n", port); + switch (port) + { + case 0x73: + return 0xff; + case 0x75: + return 0xdf; + } + return 0; +} + +static uint16_t batman_timer_latch; +static int batman_timer = 0; +static void batman_timer_over(void *p) +{ + batman_timer = 0; +} + +static void batman_timer_write(uint16_t addr, uint8_t val, void *p) +{ + if (addr & 1) + batman_timer_latch = (batman_timer_latch & 0xff) | (val << 8); + else + batman_timer_latch = (batman_timer_latch & 0xff00) | val; + batman_timer = batman_timer_latch * TIMER_USEC; +} + +static uint8_t batman_timer_read(uint16_t addr, void *p) +{ + uint16_t batman_timer_latch; + + cycles -= (int)PITCONST; + + timer_clock(); + + if (batman_timer < 0) + return 0; + + batman_timer_latch = batman_timer / TIMER_USEC; + + if (addr & 1) + return batman_timer_latch >> 8; + return batman_timer_latch & 0xff; +} + +void intel_batman_init() +{ + io_sethandler(0x0073, 0x0001, batman_brdconfig, NULL, NULL, NULL, NULL, NULL, NULL); + io_sethandler(0x0075, 0x0001, batman_brdconfig, NULL, NULL, NULL, NULL, NULL, NULL); + + io_sethandler(0x0078, 0x0002, batman_timer_read, NULL, NULL, batman_timer_write, NULL, NULL, NULL); + timer_add(batman_timer_over, &batman_timer, &batman_timer, NULL); +} + + +uint8_t endeavor_brdconfig(uint16_t port, void *p) +{ +// pclog("endeavor_brdconfig read port=%04x\n", port); + switch (port) + { + case 0x79: + return 0xff; + } + return 0; +} + +void intel_endeavor_init() +{ + io_sethandler(0x0079, 0x0001, endeavor_brdconfig, NULL, NULL, NULL, NULL, NULL, NULL); +} diff --git a/src/intel.h b/src/intel.h new file mode 100644 index 000000000..9032cca83 --- /dev/null +++ b/src/intel.h @@ -0,0 +1,2 @@ +void intel_batman_init(); +void intel_endeavor_init(); diff --git a/src/intel_flash.c b/src/intel_flash.c new file mode 100644 index 000000000..e3434ae1c --- /dev/null +++ b/src/intel_flash.c @@ -0,0 +1,419 @@ +#include +#include "ibm.h" +#include "device.h" +#include "mem.h" + +enum +{ + CMD_READ_ARRAY = 0xff, + CMD_IID = 0x90, + CMD_READ_STATUS = 0x70, + CMD_CLEAR_STATUS = 0x50, + CMD_ERASE_SETUP = 0x20, + CMD_ERASE_CONFIRM = 0xd0, + CMD_ERASE_SUSPEND = 0xb0, + CMD_PROGRAM_SETUP = 0x40 +}; + +typedef struct flash_t +{ + uint32_t command, status; + uint32_t data_addr1, data_addr2, data_start, boot_start; + uint32_t main_start[2], main_end[2], main_len[2]; + uint32_t flash_id, invert_high_pin; + mem_mapping_t read_mapping, write_mapping; + mem_mapping_t read_mapping_h, write_mapping_h; +} flash_t; + +static flash_t flash; + +char flash_path[1024]; + +#if 0 +mem_mapping_t flash_null_mapping[4]; + +uint8_t flash_read_null(uint32_t addr, void *priv) +{ + return 0xff; +} + +uint16_t flash_read_nullw(uint32_t addr, void *priv) +{ + return 0xffff; +} + +uint32_t flash_read_nulll(uint32_t addr, void *priv) +{ +// pclog("Read BIOS %08X %02X %04X:%04X\n", addr, *(uint32_t *)&rom[addr & biosmask], CS, pc); + return 0xffffffff; +} + +void flash_null_mapping_disable() +{ + mem_mapping_disable(&flash_null_mapping[0]); + mem_mapping_disable(&flash_null_mapping[1]); + mem_mapping_disable(&flash_null_mapping[2]); + mem_mapping_disable(&flash_null_mapping[3]); +} + +void flash_null_mapping_enable() +{ + mem_mapping_enable(&flash_null_mapping[0]); + mem_mapping_enable(&flash_null_mapping[1]); + mem_mapping_enable(&flash_null_mapping[2]); + mem_mapping_enable(&flash_null_mapping[3]); +} + +void flash_add_null_mapping() +{ + mem_mapping_add(&flash_null_mapping[0], 0xe0000, 0x04000, flash_read_null, flash_read_nullw, flash_read_nulll, mem_write_null, mem_write_nullw, mem_write_nulll, NULL, MEM_MAPPING_EXTERNAL, 0); + mem_mapping_add(&flash_null_mapping[1], 0xe4000, 0x04000, flash_read_null, flash_read_nullw, flash_read_nulll, mem_write_null, mem_write_nullw, mem_write_nulll, NULL, MEM_MAPPING_EXTERNAL, 0); + mem_mapping_add(&flash_null_mapping[2], 0xe8000, 0x04000, flash_read_null, flash_read_nullw, flash_read_nulll, mem_write_null, mem_write_nullw, mem_write_nulll, NULL, MEM_MAPPING_EXTERNAL, 0); + mem_mapping_add(&flash_null_mapping[3], 0xec000, 0x04000, flash_read_null, flash_read_nullw, flash_read_nulll, mem_write_null, mem_write_nullw, mem_write_nulll, NULL, MEM_MAPPING_EXTERNAL, 0); + + flash_null_mapping_disable(); +} +#endif + +static uint8_t flash_read(uint32_t addr, void *p) +{ + flash_t *flash = (flash_t *)p; + // pclog("flash_read : addr=%08x command=%02x %04x:%08x\n", addr, flash->command, CS, pc); + switch (flash->command) + { + case CMD_IID: + if (addr & 1) + return flash->flash_id; + return 0x89; + + default: + return flash->status; + } +} + +static void flash_write(uint32_t addr, uint8_t val, void *p) +{ + flash_t *flash = (flash_t *)p; + int i; + // pclog("flash_write : addr=%08x val=%02x command=%02x %04x:%08x\n", addr, val, flash->command, CS, pc); + switch (flash->command) + { + case CMD_ERASE_SETUP: + if (val == CMD_ERASE_CONFIRM) + { + // pclog("flash_write: erase %05x\n", addr & 0x1ffff); + + if ((addr & 0x1f000) == flash->data_addr1) + memset(&rom[flash->data_addr1], 0xff, 0x1000); + if ((addr & 0x1f000) == flash->data_addr2) + memset(&rom[flash->data_addr2], 0xff, 0x1000); + if (((addr & 0x1ffff) >= flash->main_start[0]) && ((addr & 0x1ffff) <= flash->main_end[0]) && flash->main_len[0]) + memset(&rom[flash->main_start[0]], 0xff, flash->main_len[0]); + if (((addr & 0x1ffff) >= flash->main_start[1]) && ((addr & 0x1ffff) <= flash->main_end[1]) && flash->main_len[1]) + memset(&rom[flash->main_start[1]], 0xff, flash->main_len[1]); + + flash->status = 0x80; + } + flash->command = CMD_READ_STATUS; + break; + + case CMD_PROGRAM_SETUP: + // pclog("flash_write: program %05x %02x\n", addr & 0x1ffff, val); + if ((addr & 0x1e000) != (flash->boot_start & 0x1e000)) + rom[addr & 0x1ffff] = val; + flash->command = CMD_READ_STATUS; + flash->status = 0x80; + break; + + default: + flash->command = val; + switch (val) + { + case CMD_CLEAR_STATUS: + flash->status = 0; + break; + + case CMD_IID: + case CMD_READ_STATUS: + for (i = 0; i < 8; i++) + { + mem_mapping_disable((addr & 0x8000000) ? &bios_high_mapping[i] : &bios_mapping[i]); + } + mem_mapping_enable((addr & 0x8000000) ? &flash->read_mapping_h : &flash->read_mapping); + break; + + case CMD_READ_ARRAY: + for (i = 0; i < 8; i++) + { + mem_mapping_enable((addr & 0x8000000) ? &bios_high_mapping[i] : &bios_mapping[i]); + } + mem_mapping_disable((addr & 0x8000000) ? &flash->read_mapping_h : &flash->read_mapping); +#if 0 + if ((romset == ROM_MB500N) || (romset == ROM_430VX) || (romset == ROM_P55VA) || (romset == ROM_P55TVP4) || (romset == ROM_440FX)) + { + for (i = 0; i < 4; i++) + { + mem_mapping_disable(&bios_mapping[i]); + } + + flash_null_mapping_enable(); + } + pclog("; This line needed\n"); +#endif + break; + } + } +} + +void *intel_flash_init(int type) +{ + FILE *f; + flash_t *flash = malloc(sizeof(flash_t)); + char fpath[1024]; + memset(flash, 0, sizeof(flash_t)); + + // pclog("Initializing Flash (type = %i)\n", type); + + memset(flash_path, 0, 1024); + + switch(romset) + { + case ROM_REVENGE: + strcpy(flash_path, "roms/revenge/"); + break; + case ROM_586MC1: + strcpy(flash_path, "roms/586mc1/"); + break; + case ROM_PLATO: + strcpy(flash_path, "roms/plato/"); + break; + case ROM_ENDEAVOR: + strcpy(flash_path, "roms/endeavor/"); + break; + case ROM_MB500N: + strcpy(flash_path, "roms/mb500n/"); + break; + case ROM_P54TP4XE: + strcpy(flash_path, "roms/p54tp4xe/"); + break; + case ROM_ACERM3A: + strcpy(flash_path, "roms/acerm3a/"); + break; + case ROM_ACERV35N: + strcpy(flash_path, "roms/acerv35n/"); + break; + case ROM_P55TVP4: + strcpy(flash_path, "roms/p55tvp4/"); + break; + case ROM_P55T2P4: + strcpy(flash_path, "roms/p55t2p4/"); + break; + case ROM_430VX: + strcpy(flash_path, "roms/430vx/"); + break; + case ROM_P55VA: + strcpy(flash_path, "roms/p55va/"); + break; + case ROM_440FX: + strcpy(flash_path, "roms/440fx/"); + break; + case ROM_KN97: + strcpy(flash_path, "roms/kn97/"); + break; + } + // pclog("Flash init: Path is: %s\n", flash_path); + + switch(type) + { + case 0: + flash->data_addr1 = 0xc000; + flash->data_addr2 = 0xd000; + flash->data_start = 0xc000; + flash->boot_start = 0xe000; + flash->main_start[0] = 0x0000; + flash->main_end[0] = 0xbfff; + flash->main_len[0] = 0xc000; + flash->main_start[1] = 0x10000; + flash->main_end[1] = 0x1ffff; + flash->main_len[1] = 0x10000; + break; + case 1: + flash->data_addr1 = 0x1c000; + flash->data_addr2 = 0x1d000; + flash->data_start = 0x1c000; + flash->boot_start = 0x1e000; + flash->main_start[0] = 0x00000; + flash->main_end[0] = 0x1bfff; + flash->main_len[0] = 0x1c000; + flash->main_start[1] = flash->main_end[1] = flash->main_len[1] = 0; + break; + case 2: + flash->data_addr1 = 0x3000; + flash->data_addr2 = 0x2000; + flash->data_start = 0x2000; + flash->boot_start = 0x00000; + flash->main_start[0] = 0x04000; + flash->main_end[0] = 0x1ffff; + flash->main_len[0] = 0x1c000; + flash->main_start[1] = flash->main_end[1] = flash->main_len[1] = 0; + break; + } + + flash->flash_id = (type != 2) ? 0x94 : 0x95; + flash->invert_high_pin = (type == 0) ? 1 : 0; + + mem_mapping_add(&flash->read_mapping, + 0xe0000, + 0x20000, + flash_read, NULL, NULL, + NULL, NULL, NULL, + NULL, MEM_MAPPING_EXTERNAL, (void *)flash); + mem_mapping_add(&flash->write_mapping, + 0xe0000, + 0x20000, + NULL, NULL, NULL, + flash_write, NULL, NULL, + NULL, MEM_MAPPING_EXTERNAL, (void *)flash); + mem_mapping_disable(&flash->read_mapping); + if (type > 0) + { + mem_mapping_add(&flash->read_mapping_h, + 0xfffe0000, + 0x20000, + flash_read, NULL, NULL, + NULL, NULL, NULL, + NULL, 0, (void *)flash); + mem_mapping_add(&flash->write_mapping_h, + 0xfffe0000, + 0x20000, + NULL, NULL, NULL, + flash_write, NULL, NULL, + NULL, 0, (void *)flash); + mem_mapping_disable(&flash->read_mapping_h); + /* if (romset != ROM_P55TVP4) */ mem_mapping_disable(&flash->write_mapping); + } + flash->command = CMD_READ_ARRAY; + flash->status = 0; + + if ((romset == ROM_586MC1) || (romset == ROM_MB500N) || (type == 0)) + { + memset(&rom[flash->data_addr2], 0xFF, 0x1000); + } + else + { + memset(&rom[flash->data_start], 0xFF, 0x2000); + } + + if ((romset != ROM_586MC1) && (romset != ROM_MB500N) && (type > 0)) + { + memset(fpath, 0, 1024); + strcpy(fpath, flash_path); + strcat(fpath, "dmi.bin"); + f = romfopen(fpath, "rb"); + if (f) + { + fread(&rom[flash->data_addr1], 0x1000, 1, f); + fclose(f); + } + } + memset(fpath, 0, 1024); + strcpy(fpath, flash_path); + strcat(fpath, "escd.bin"); + f = romfopen(fpath, "rb"); + if (f) + { + fread(&rom[flash->data_addr2], 0x1000, 1, f); + fclose(f); + } + +#if 0 + flash_add_null_mapping(); +#endif + + return flash; +} + +/* For AMI BIOS'es - Intel 28F001BXT with high address pin inverted. */ +void *intel_flash_bxt_ami_init() +{ + return intel_flash_init(0); +} + +/* For Award BIOS'es - Intel 28F001BXT with high address pin not inverted. */ +void *intel_flash_bxt_init() +{ + return intel_flash_init(1); +} + +/* For Acerd BIOS'es - Intel 28F001BXB. */ +void *intel_flash_bxb_init() +{ + return intel_flash_init(2); +} + +void intel_flash_close(void *p) +{ + FILE *f; + flash_t *flash = (flash_t *)p; + + char fpath[1024]; + + // pclog("Flash close: Path is: %s\n", flash_path); + + if ((romset != ROM_586MC1) && (romset != ROM_MB500N)) + { + memset(fpath, 0, 1024); + strcpy(fpath, flash_path); + strcat(fpath, "dmi.bin"); + f = romfopen(fpath, "wb"); + fwrite(&rom[flash->data_addr1], 0x1000, 1, f); + fclose(f); + } + memset(fpath, 0, 1024); + strcpy(fpath, flash_path); + strcat(fpath, "escd.bin"); + f = romfopen(fpath, "wb"); + fwrite(&rom[flash->data_addr2], 0x1000, 1, f); + fclose(f); + + free(flash); +} + +device_t intel_flash_bxt_ami_device = +{ + "Intel 28F001BXT Flash BIOS", + 0, + intel_flash_bxt_ami_init, + intel_flash_close, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +device_t intel_flash_bxt_device = +{ + "Intel 28F001BXT Flash BIOS", + 0, + intel_flash_bxt_init, + intel_flash_close, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +device_t intel_flash_bxb_device = +{ + "Intel 28F001BXT Flash BIOS", + 0, + intel_flash_bxb_init, + intel_flash_close, + NULL, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/intel_flash.h b/src/intel_flash.h new file mode 100644 index 000000000..e8e0c1bc7 --- /dev/null +++ b/src/intel_flash.h @@ -0,0 +1,3 @@ +extern device_t intel_flash_bxt_ami_device; +extern device_t intel_flash_bxt_device; +extern device_t intel_flash_bxb_device; diff --git a/src/io.c b/src/io.c new file mode 100644 index 000000000..53a2ddbbf --- /dev/null +++ b/src/io.c @@ -0,0 +1,202 @@ +#include "ibm.h" +#include "ide.h" +#include "io.h" +#include "video.h" +#include "cpu.h" + +uint8_t (*port_inb[0x10000][2])(uint16_t addr, void *priv); +uint16_t (*port_inw[0x10000][2])(uint16_t addr, void *priv); +uint32_t (*port_inl[0x10000][2])(uint16_t addr, void *priv); + +void (*port_outb[0x10000][2])(uint16_t addr, uint8_t val, void *priv); +void (*port_outw[0x10000][2])(uint16_t addr, uint16_t val, void *priv); +void (*port_outl[0x10000][2])(uint16_t addr, uint32_t val, void *priv); + +void *port_priv[0x10000][2]; + +void io_init() +{ + int c; + pclog("io_init\n"); + for (c = 0; c < 0x10000; c++) + { + port_inb[c][0] = port_inw[c][0] = port_inl[c][0] = NULL; + port_outb[c][0] = port_outw[c][0] = port_outl[c][0] = NULL; + port_inb[c][1] = port_inw[c][1] = port_inl[c][1] = NULL; + port_outb[c][1] = port_outw[c][1] = port_outl[c][1] = NULL; + port_priv[c][0] = port_priv[c][1] = NULL; + } +} + +void io_sethandler(uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv) +{ + int c; + for (c = 0; c < size; c++) + { + if (!port_inb[ base + c][0] && !port_inw[ base + c][0] && !port_inl[ base + c][0] && + !port_outb[base + c][0] && !port_outw[base + c][0] && !port_outl[base + c][0]) + { + port_inb[ base + c][0] = inb; + port_inw[ base + c][0] = inw; + port_inl[ base + c][0] = inl; + port_outb[base + c][0] = outb; + port_outw[base + c][0] = outw; + port_outl[base + c][0] = outl; + port_priv[base + c][0] = priv; + } + else if (!port_inb[ base + c][1] && !port_inw[ base + c][1] && !port_inl[ base + c][1] && + !port_outb[base + c][1] && !port_outw[base + c][1] && !port_outl[base + c][1]) + { + port_inb[ base + c][1] = inb; + port_inw[ base + c][1] = inw; + port_inl[ base + c][1] = inl; + port_outb[base + c][1] = outb; + port_outw[base + c][1] = outw; + port_outl[base + c][1] = outl; + port_priv[base + c][1] = priv; + } + } +} + +void io_removehandler(uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv) +{ + int c; + for (c = 0; c < size; c++) + { + if (port_priv[base + c][0] == priv) + { + if (port_inb[ base + c][0] == inb) + port_inb[ base + c][0] = NULL; + if (port_inw[ base + c][0] == inw) + port_inw[ base + c][0] = NULL; + if (port_inl[ base + c][0] == inl) + port_inl[ base + c][0] = NULL; + if (port_outb[ base + c][0] == outb) + port_outb[ base + c][0] = NULL; + if (port_outw[ base + c][0] == outw) + port_outw[ base + c][0] = NULL; + if (port_outl[ base + c][0] == outl) + port_outl[ base + c][0] = NULL; + } + if (port_priv[base + c][1] == priv) + { + if (port_inb[ base + c][1] == inb) + port_inb[ base + c][1] = NULL; + if (port_inw[ base + c][1] == inw) + port_inw[ base + c][1] = NULL; + if (port_inl[ base + c][1] == inl) + port_inl[ base + c][1] = NULL; + if (port_outb[ base + c][1] == outb) + port_outb[ base + c][1] = NULL; + if (port_outw[ base + c][1] == outw) + port_outw[ base + c][1] = NULL; + if (port_outl[ base + c][1] == outl) + port_outl[ base + c][1] = NULL; + } + } +} + +uint8_t cgamode,cgastat=0,cgacol; +int hsync; +uint8_t lpt2dat; +int sw9; +int t237=0; +uint8_t inb(uint16_t port) +{ + uint8_t temp = 0xff; + + if (port_inb[port][0]) + temp &= port_inb[port][0](port, port_priv[port][0]); + if (port_inb[port][1]) + temp &= port_inb[port][1](port, port_priv[port][1]); + + /* if (!port_inb[port][0] && !port_inb[port][1]) + pclog("Bad INB %04X %04X:%04X\n", port, CS, pc); */ + + return temp; +} + +uint8_t cpu_readport(uint32_t port) { return inb(port); } + +void outb(uint16_t port, uint8_t val) +{ + if (port_outb[port][0]) + port_outb[port][0](port, val, port_priv[port][0]); + if (port_outb[port][1]) + port_outb[port][1](port, val, port_priv[port][1]); + + /* if (!port_outb[port][0] && !port_outb[port][1]) + pclog("Bad OUTB %04X %02X %04X:%08X\n", port, val, CS, pc); */ + return; +} + +uint16_t inw(uint16_t port) +{ +// pclog("INW %04X\n", port); + if (port_inw[port][0]) + return port_inw[port][0](port, port_priv[port][0]); + if (port_inw[port][1]) + return port_inw[port][1](port, port_priv[port][1]); + + return inb(port) | (inb(port + 1) << 8); +} + +void outw(uint16_t port, uint16_t val) +{ +// printf("OUTW %04X %04X %04X:%08X\n",port,val, CS, pc); +/* if ((port & ~0xf) == 0xf000) + pclog("OUTW %04X %04X\n", port, val);*/ + + if (port_outw[port][0]) + port_outw[port][0](port, val, port_priv[port][0]); + if (port_outw[port][1]) + port_outw[port][1](port, val, port_priv[port][1]); + + if (port_outw[port][0] || port_outw[port][1]) + return; + + outb(port,val); + outb(port+1,val>>8); +} + +uint32_t inl(uint16_t port) +{ +// pclog("INL %04X\n", port); + if (port_inl[port][0]) + return port_inl[port][0](port, port_priv[port][0]); + if (port_inl[port][1]) + return port_inl[port][1](port, port_priv[port][1]); + + return inw(port) | (inw(port + 2) << 16); +} + +void outl(uint16_t port, uint32_t val) +{ +/* if ((port & ~0xf) == 0xf000) + pclog("OUTL %04X %08X\n", port, val);*/ + + if (port_outl[port][0]) + port_outl[port][0](port, val, port_priv[port][0]); + if (port_outl[port][1]) + port_outl[port][1](port, val, port_priv[port][1]); + + if (port_outl[port][0] || port_outl[port][1]) + return; + + outw(port, val); + outw(port + 2, val >> 16); +} diff --git a/src/io.h b/src/io.h new file mode 100644 index 000000000..84792374d --- /dev/null +++ b/src/io.h @@ -0,0 +1,19 @@ +void io_init(); + +void io_sethandler(uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv); + +void io_removehandler(uint16_t base, int size, + uint8_t (*inb)(uint16_t addr, void *priv), + uint16_t (*inw)(uint16_t addr, void *priv), + uint32_t (*inl)(uint16_t addr, void *priv), + void (*outb)(uint16_t addr, uint8_t val, void *priv), + void (*outw)(uint16_t addr, uint16_t val, void *priv), + void (*outl)(uint16_t addr, uint32_t val, void *priv), + void *priv); diff --git a/src/jim.c b/src/jim.c new file mode 100644 index 000000000..54f7d1a65 --- /dev/null +++ b/src/jim.c @@ -0,0 +1,79 @@ +#include +#include +#include "ibm.h" +#include "io.h" + +uint8_t europcdat[16]; +struct +{ + uint8_t dat[16]; + int stat; + int addr; +} europc_rtc; + +void writejim(uint16_t addr, uint8_t val, void *p) +{ + if ((addr&0xFF0)==0x250) europcdat[addr&0xF]=val; + switch (addr) + { + case 0x25A: +// printf("Write RTC stat %i val %02X\n",europc_rtc.stat,val); + switch (europc_rtc.stat) + { + case 0: + europc_rtc.addr=val&0xF; + europc_rtc.stat++; +// printf("RTC addr now %02X - contents %02X\n",val&0xF,europc_rtc.dat[europc_rtc.addr]); + break; + case 1: + europc_rtc.dat[europc_rtc.addr]=(europc_rtc.dat[europc_rtc.addr]&0xF)|(val<<4); + europc_rtc.stat++; + break; + case 2: + europc_rtc.dat[europc_rtc.addr]=(europc_rtc.dat[europc_rtc.addr]&0xF0)|(val&0xF); + europc_rtc.stat=0; + break; + } + break; + } +// printf("Write JIM %04X %02X\n",addr,val); +} + +uint8_t readjim(uint16_t addr, void *p) +{ +// printf("Read JIM %04X\n",addr); + switch (addr) + { + case 0x250: case 0x251: case 0x252: case 0x253: return 0; + case 0x254: case 0x255: case 0x256: case 0x257: return europcdat[addr&0xF]; + case 0x25A: + if (europc_rtc.stat==1) + { + europc_rtc.stat=2; + return europc_rtc.dat[europc_rtc.addr]>>4; + } + if (europc_rtc.stat==2) + { + europc_rtc.stat=0; + return europc_rtc.dat[europc_rtc.addr]&0xF; + } + return 0; + } + return 0; +} + +void jim_init() +{ + uint8_t viddat; + memset(europc_rtc.dat,0,16); + europc_rtc.dat[0xF]=1; + europc_rtc.dat[3]=1; + europc_rtc.dat[4]=1; + europc_rtc.dat[5]=0x88; + if (gfxcard==GFX_CGA) viddat=0x12; + else if (gfxcard==GFX_MDA || gfxcard==GFX_HERCULES || gfxcard==GFX_INCOLOR) viddat=3; + else viddat=0x10; + europc_rtc.dat[0xB]=viddat; + europc_rtc.dat[0xD]=viddat; /*Checksum*/ + io_sethandler(0x250, 0x10, readjim, NULL, NULL, writejim, NULL, NULL, NULL); +} diff --git a/src/jim.h b/src/jim.h new file mode 100644 index 000000000..632d31e03 --- /dev/null +++ b/src/jim.h @@ -0,0 +1 @@ +void jim_init(); diff --git a/src/joystick_standard.c b/src/joystick_standard.c new file mode 100644 index 000000000..6f961a896 --- /dev/null +++ b/src/joystick_standard.c @@ -0,0 +1,208 @@ +#include +#include "ibm.h" +#include "device.h" +#include "timer.h" +#include "gameport.h" +#include "joystick_standard.h" +#include "plat-joystick.h" + +static void *joystick_standard_init() +{ +} + +static void joystick_standard_close(void *p) +{ +} + +static uint8_t joystick_standard_read(void *p) +{ + uint8_t ret = 0xf0; + + if (JOYSTICK_PRESENT(0)) + { + if (joystick_state[0].button[0]) + ret &= ~0x10; + if (joystick_state[0].button[1]) + ret &= ~0x20; + } + if (JOYSTICK_PRESENT(1)) + { + if (joystick_state[1].button[0]) + ret &= ~0x40; + if (joystick_state[1].button[1]) + ret &= ~0x80; + } + + return ret; +} + +static uint8_t joystick_standard_read_4button(void *p) +{ + uint8_t ret = 0xf0; + + if (JOYSTICK_PRESENT(0)) + { + if (joystick_state[0].button[0]) + ret &= ~0x10; + if (joystick_state[0].button[1]) + ret &= ~0x20; + if (joystick_state[0].button[2]) + ret &= ~0x40; + if (joystick_state[0].button[3]) + ret &= ~0x80; + } + + return ret; +} + +static void joystick_standard_write(void *p) +{ +} + +static int joystick_standard_read_axis(void *p, int axis) +{ + switch (axis) + { + case 0: + if (!JOYSTICK_PRESENT(0)) + return AXIS_NOT_PRESENT; + return joystick_state[0].axis[0]; + case 1: + if (!JOYSTICK_PRESENT(0)) + return AXIS_NOT_PRESENT; + return joystick_state[0].axis[1]; + case 2: + if (!JOYSTICK_PRESENT(1)) + return AXIS_NOT_PRESENT; + return joystick_state[1].axis[0]; + case 3: + if (!JOYSTICK_PRESENT(1)) + return AXIS_NOT_PRESENT; + return joystick_state[1].axis[1]; + } +} + +static int joystick_standard_read_axis_4button(void *p, int axis) +{ + if (!JOYSTICK_PRESENT(0)) + return AXIS_NOT_PRESENT; + + switch (axis) + { + case 0: + return joystick_state[0].axis[0]; + case 1: + return joystick_state[0].axis[1]; + case 2: + return 0; + case 3: + return 0; + } +} +static int joystick_standard_read_axis_6button(void *p, int axis) +{ + if (!JOYSTICK_PRESENT(0)) + return AXIS_NOT_PRESENT; + + switch (axis) + { + case 0: + return joystick_state[0].axis[0]; + case 1: + return joystick_state[0].axis[1]; + case 2: + return joystick_state[0].button[4] ? -32767 : 32768; + case 3: + return joystick_state[0].button[5] ? -32767 : 32768; + } +} +static int joystick_standard_read_axis_8button(void *p, int axis) +{ + if (!JOYSTICK_PRESENT(0)) + return AXIS_NOT_PRESENT; + + switch (axis) + { + case 0: + return joystick_state[0].axis[0]; + case 1: + return joystick_state[0].axis[1]; + case 2: + if (joystick_state[0].button[4]) + return -32767; + if (joystick_state[0].button[6]) + return 32768; + return 0; + case 3: + if (joystick_state[0].button[5]) + return -32767; + if (joystick_state[0].button[7]) + return 32768; + return 0; + } +} + +static void joystick_standard_a0_over(void *p) +{ +} + +joystick_if_t joystick_standard = +{ + .name = "Standard 2-button joystick(s)", + .init = joystick_standard_init, + .close = joystick_standard_close, + .read = joystick_standard_read, + .write = joystick_standard_write, + .read_axis = joystick_standard_read_axis, + .a0_over = joystick_standard_a0_over, + .max_joysticks = 2, + .axis_count = 2, + .button_count = 2, + .axis_names = {"X axis", "Y axis"}, + .button_names = {"Button 1", "Button 2"} +}; +joystick_if_t joystick_standard_4button = +{ + .name = "Standard 4-button joystick", + .init = joystick_standard_init, + .close = joystick_standard_close, + .read = joystick_standard_read_4button, + .write = joystick_standard_write, + .read_axis = joystick_standard_read_axis_4button, + .a0_over = joystick_standard_a0_over, + .max_joysticks = 1, + .axis_count = 2, + .button_count = 4, + .axis_names = {"X axis", "Y axis"}, + .button_names = {"Button 1", "Button 2", "Button 3", "Button 4"} +}; +joystick_if_t joystick_standard_6button = +{ + .name = "Standard 6-button joystick", + .init = joystick_standard_init, + .close = joystick_standard_close, + .read = joystick_standard_read_4button, + .write = joystick_standard_write, + .read_axis = joystick_standard_read_axis_6button, + .a0_over = joystick_standard_a0_over, + .max_joysticks = 1, + .axis_count = 2, + .button_count = 6, + .axis_names = {"X axis", "Y axis"}, + .button_names = {"Button 1", "Button 2", "Button 3", "Button 4", "Button 5", "Button 6"} +}; +joystick_if_t joystick_standard_8button = +{ + .name = "Standard 8-button joystick", + .init = joystick_standard_init, + .close = joystick_standard_close, + .read = joystick_standard_read_4button, + .write = joystick_standard_write, + .read_axis = joystick_standard_read_axis_8button, + .a0_over = joystick_standard_a0_over, + .max_joysticks = 1, + .axis_count = 2, + .button_count = 8, + .axis_names = {"X axis", "Y axis"}, + .button_names = {"Button 1", "Button 2", "Button 3", "Button 4", "Button 5", "Button 6", "Button 7", "Button 8"} +}; diff --git a/src/joystick_standard.h b/src/joystick_standard.h new file mode 100644 index 000000000..7150058a8 --- /dev/null +++ b/src/joystick_standard.h @@ -0,0 +1,4 @@ +extern joystick_if_t joystick_standard; +extern joystick_if_t joystick_standard_4button; +extern joystick_if_t joystick_standard_6button; +extern joystick_if_t joystick_standard_8button; diff --git a/src/joystick_sw_pad.c b/src/joystick_sw_pad.c new file mode 100644 index 000000000..007dd5492 --- /dev/null +++ b/src/joystick_sw_pad.c @@ -0,0 +1,251 @@ +/*Sidewinder game pad notes : + + - Write to 0x201 starts packet transfer (5*N or 15*N bits) + - Currently alternates between Mode A and Mode B (is there any way of + actually controlling which is used?) + - Windows 9x drivers require Mode B when more than 1 pad connected + - Packet preceeded by high data (currently 50us), and followed by low + data (currently 160us) - timings are probably wrong, but good enough + for everything I've tried + - Analogue inputs are only used to time ID packet request. If A0 timing + out is followed after ~64us by another 0x201 write then an ID packet + is triggered + - Sidewinder game pad ID is 'H0003' + - ID is sent in Mode A (1 bit per clock), but data bit 2 must change + during ID packet transfer, or Windows 9x drivers won't use Mode B. I + don't know if it oscillates, mirrors the data transfer, or something + else - the drivers only check that it changes at least 10 times during + the transfer + - Some DOS stuff will write to 0x201 while a packet is being transferred. + This seems to be ignored. +*/ + +#include +#include "ibm.h" +#include "device.h" +#include "timer.h" +#include "gameport.h" +#include "joystick_sw_pad.h" +#include "plat-joystick.h" + +typedef struct +{ + int poll_time; + int poll_left; + int poll_clock; + uint64_t poll_data; + int poll_mode; + + int trigger_time; + int data_mode; +} sw_data; + +static void sw_timer_over(void *p) +{ + sw_data *sw = (sw_data *)p; + + while (sw->poll_time <= 0 && sw->poll_left) + { + sw->poll_clock = !sw->poll_clock; + + if (sw->poll_clock) + { + sw->poll_data >>= (sw->poll_mode ? 3 : 1); + sw->poll_left--; + } + + if (sw->poll_left == 1 && !sw->poll_clock) + sw->poll_time += TIMER_USEC * 160; + else if (sw->poll_left) + sw->poll_time += TIMER_USEC * 5; + else + sw->poll_time = 0; + } + + if (!sw->poll_left) + sw->poll_time = 0; +} + +static void sw_trigger_timer_over(void *p) +{ + sw_data *sw = (sw_data *)p; + + sw->trigger_time = 0; +} + +static int sw_parity(uint16_t data) +{ + int bits_set = 0; + + while (data) + { + bits_set++; + data &= (data - 1); + } + + return bits_set & 1; +} + +static void *sw_init() +{ + sw_data *sw = (sw_data *)malloc(sizeof(sw_data)); + memset(sw, 0, sizeof(sw_data)); + + timer_add(sw_timer_over, &sw->poll_time, &sw->poll_time, sw); + timer_add(sw_trigger_timer_over, &sw->trigger_time, &sw->trigger_time, sw); + + return sw; +} + +static void sw_close(void *p) +{ + sw_data *sw = (sw_data *)p; + + free(sw); +} + +static uint8_t sw_read(void *p) +{ + sw_data *sw = (sw_data *)p; + uint8_t temp = 0; + + if (!JOYSTICK_PRESENT(0)) + return 0xff; + + if (sw->poll_time) + { + if (sw->poll_clock) + temp |= 0x10; + + if (sw->poll_mode) + temp |= (sw->poll_data & 7) << 5; + else + { + temp |= ((sw->poll_data & 1) << 5) | 0xc0; + if (sw->poll_left > 31 && !(sw->poll_left & 1)) + temp &= ~0x80; + } + } + else + temp |= 0xf0; + + return temp; +} + +static void sw_write(void *p) +{ + sw_data *sw = (sw_data *)p; + int time_since_last = sw->trigger_time / TIMER_USEC; + + if (!JOYSTICK_PRESENT(0)) + return; + + timer_process(); + + if (!sw->poll_left) + { + sw->poll_clock = 1; + sw->poll_time = TIMER_USEC * 50; + + if (time_since_last > 9900 && time_since_last < 9940) + { +// pclog("sw sends ID packet\n"); + sw->poll_mode = 0; + sw->poll_left = 49; + sw->poll_data = 0x2400ull | (0x1830ull << 15) | (0x19b0ull << 30); + } + else + { + int c; + +// pclog("sw sends data packet %08x %i\n", cpu_state.pc, data_packets++); + + sw->poll_mode = sw->data_mode; + sw->data_mode = !sw->data_mode; + + if (sw->poll_mode) + { + sw->poll_left = 1; + sw->poll_data = 7; + } + else + { + sw->poll_left = 1; + sw->poll_data = 1; + } + + for (c = 0; c < 4; c++) + { + uint64_t data = 0x3fff; + int b; + + if (!JOYSTICK_PRESENT(c)) + break; + + if (joystick_state[c].axis[1] < -16383) + data &= ~1; + if (joystick_state[c].axis[1] > 16383) + data &= ~2; + if (joystick_state[c].axis[0] > 16383) + data &= ~4; + if (joystick_state[c].axis[0] < -16383) + data &= ~8; + + for (b = 0; b < 10; b++) + { + if (joystick_state[c].button[b]) + data &= ~(1 << (b + 4)); + } + + if (sw_parity(data)) + data |= 0x4000; + + if (sw->poll_mode) + { + sw->poll_left += 5; + sw->poll_data |= (data << (c*15 + 3)); + } + else + { + sw->poll_left += 15; + sw->poll_data |= (data << (c*15 + 1)); + } + } + } + } + + sw->trigger_time = 0; + + timer_update_outstanding(); +} + +static int sw_read_axis(void *p, int axis) +{ + if (!JOYSTICK_PRESENT(0)) + return AXIS_NOT_PRESENT; + + return 0; /*No analogue support on Sidewinder game pad*/ +} + +static void sw_a0_over(void *p) +{ + sw_data *sw = (sw_data *)p; + + sw->trigger_time = TIMER_USEC * 10000; +} + +joystick_if_t joystick_sw_pad = +{ + .name = "Microsoft SideWinder Pad", + .init = sw_init, + .close = sw_close, + .read = sw_read, + .write = sw_write, + .read_axis = sw_read_axis, + .a0_over = sw_a0_over, + .max_joysticks = 4, + .axis_count = 2, + .button_count = 10, + .axis_names = {"X axis", "Y axis"}, + .button_names = {"A", "B", "C", "X", "Y", "Z", "L", "R", "Start", "M"} +}; diff --git a/src/joystick_sw_pad.h b/src/joystick_sw_pad.h new file mode 100644 index 000000000..ba5ceb680 --- /dev/null +++ b/src/joystick_sw_pad.h @@ -0,0 +1 @@ +extern joystick_if_t joystick_sw_pad; diff --git a/src/keyboard.c b/src/keyboard.c new file mode 100644 index 000000000..f1ad9d31d --- /dev/null +++ b/src/keyboard.c @@ -0,0 +1,503 @@ +#include "ibm.h" +#include "plat-keyboard.h" +#include "keyboard.h" + +int keybsendcallback = 0; + +typedef struct +{ + int scancodes_make[9]; + int scancodes_break[9]; +} scancode; + +/*272 = 256 + 16 fake interim scancodes for disambiguation purposes.*/ +static scancode scancode_set1[272] = +{ + { {-1}, {-1} }, { {0x01, -1}, {0x81, -1} }, { {0x02, -1}, {0x82, -1} }, { {0x03, -1}, {0x83, -1} }, + { {0x04, -1}, {0x84, -1} }, { {0x05, -1}, {0x85, -1} }, { {0x06, -1}, {0x86, -1} }, { {0x07, -1}, {0x87, -1} }, + { {0x08, -1}, {0x88, -1} }, { {0x09, -1}, {0x89, -1} }, { {0x0a, -1}, {0x8a, -1} }, { {0x0b, -1}, {0x8b, -1} }, + { {0x0c, -1}, {0x8c, -1} }, { {0x0d, -1}, {0x8d, -1} }, { {0x0e, -1}, {0x8e, -1} }, { {0x0f, -1}, {0x8f, -1} }, + { {0x10, -1}, {0x90, -1} }, { {0x11, -1}, {0x91, -1} }, { {0x12, -1}, {0x92, -1} }, { {0x13, -1}, {0x93, -1} }, + { {0x14, -1}, {0x94, -1} }, { {0x15, -1}, {0x95, -1} }, { {0x16, -1}, {0x96, -1} }, { {0x17, -1}, {0x97, -1} }, + { {0x18, -1}, {0x98, -1} }, { {0x19, -1}, {0x99, -1} }, { {0x1a, -1}, {0x9a, -1} }, { {0x1b, -1}, {0x9b, -1} }, + { {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, { {0x1e, -1}, {0x9e, -1} }, { {0x1f, -1}, {0x9f, -1} }, + { {0x20, -1}, {0xa0, -1} }, { {0x21, -1}, {0xa1, -1} }, { {0x22, -1}, {0xa2, -1} }, { {0x23, -1}, {0xa3, -1} }, + { {0x24, -1}, {0xa4, -1} }, { {0x25, -1}, {0xa5, -1} }, { {0x26, -1}, {0xa6, -1} }, { {0x27, -1}, {0xa7, -1} }, + { {0x28, -1}, {0xa8, -1} }, { {0x29, -1}, {0xa9, -1} }, { {0x2a, -1}, {0xaa, -1} }, { {0x2b, -1}, {0xab, -1} }, + { {0x2c, -1}, {0xac, -1} }, { {0x2d, -1}, {0xad, -1} }, { {0x2e, -1}, {0xae, -1} }, { {0x2f, -1}, {0xaf, -1} }, + { {0x30, -1}, {0xb0, -1} }, { {0x31, -1}, {0xb1, -1} }, { {0x32, -1}, {0xb2, -1} }, { {0x33, -1}, {0xb3, -1} }, + { {0x34, -1}, {0xb4, -1} }, { {0x35, -1}, {0xb5, -1} }, { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} }, + { {0x38, -1}, {0xb8, -1} }, { {0x39, -1}, {0xb9, -1} }, { {0x3a, -1}, {0xba, -1} }, { {0x3b, -1}, {0xbb, -1} }, + { {0x3c, -1}, {0xbc, -1} }, { {0x3d, -1}, {0xbd, -1} }, { {0x3e, -1}, {0xbe, -1} }, { {0x3f, -1}, {0xbf, -1} }, + { {0x40, -1}, {0xc0, -1} }, { {0x41, -1}, {0xc1, -1} }, { {0x42, -1}, {0xc2, -1} }, { {0x43, -1}, {0xc3, -1} }, + { {0x44, -1}, {0xc4, -1} }, { {0x45, -1}, {0xc5, -1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} }, + { {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, { {0x4a, -1}, {0xca, -1} }, { {0x4b, -1}, {0xcb, -1} }, + { {0x4c, -1}, {0xcc, -1} }, { {0x4d, -1}, {0xcd, -1} }, { {0x4e, -1}, {0xce, -1} }, { {0x4f, -1}, {0xcf, -1} }, + { {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} }, + { {0x54, -1}, {0xd4, -1} }, { {0x55, -1}, {0xd5, -1} }, { {0x56, -1}, {0xd6, -1} }, { {0x57, -1}, {0xd7, -1} }, + { {0x58, -1}, {0xd8, -1} }, { {0x59, -1}, {0xd9, -1} }, { {0x5a, -1}, {0xda, -1} }, { {0x5b, -1}, {0xdb, -1} }, + { {0x5c, -1}, {0xdc, -1} }, { {0x5d, -1}, {0xdd, -1} }, { {0x5e, -1}, {0xde, -1} }, { {0x5f, -1}, {0xdf, -1} }, + { {0x60, -1}, {0xe0, -1} }, { {0x61, -1}, {0xe1, -1} }, { {0x62, -1}, {0xe2, -1} }, { {0x63, -1}, {0xe3, -1} }, + { {0x64, -1}, {0xe4, -1} }, { {0x65, -1}, {0xe5, -1} }, { {0x66, -1}, {0xe6, -1} }, { {0x67, -1}, {0xe7, -1} }, + { {0x68, -1}, {0xe8, -1} }, { {0x69, -1}, {0xe9, -1} }, { {0x6a, -1}, {0xea, -1} }, { {0x6b, -1}, {0xeb, -1} }, + { {0x6c, -1}, {0xec, -1} }, { {0x6d, -1}, {0xed, -1} }, { {0x6e, -1}, {0xee, -1} }, { {0x6f, -1}, {0xef, -1} }, + { {0x70, -1}, {0xf0, -1} }, { {0x71, -1}, {0xf1, -1} }, { {0x72, -1}, {0xf2, -1} }, { {0x73, -1}, {0xf3, -1} }, + { {0x74, -1}, {0xf4, -1} }, { {0x75, -1}, {0xf5, -1} }, { {0x76, -1}, {0xf6, -1} }, { {0x77, -1}, {0xf7, -1} }, + { {0x78, -1}, {0xf8, -1} }, { {0x79, -1}, {0xf9, -1} }, { {0x7a, -1}, {0xfa, -1} }, { {0x7b, -1}, {0xfb, -1} }, + { {0x7c, -1}, {0xfc, -1} }, { {0x7d, -1}, {0xfd, -1} }, { {0x7e, -1}, {0xfe, -1} }, { {0x7f, -1}, {0xff, -1} }, + + { {0x80, -1}, {-1} }, { {0x81, -1}, {-1} }, { {0x82, -1}, {-1} }, { {0xe0, 0x03, -1}, {0xe0, 0x83, -1} }, /*80*/ + { {0xe0, 0x04, -1}, {0xe0, 0x84, -1} }, { {0x85, -1}, {-1} }, { {0x86, -1}, {-1} }, { {0x87, -1}, {-1} }, /*84*/ + { {0xe0, 0x08, -1}, {0xe0, 0x88, -1} }, { {0xe0, 0x09, -1}, {0xe0, 0x89, -1} }, { {0xe0, 0x0a, -1}, {0xe0, 0x8a, -1} }, { {0xe0, 0x0b, -1}, {0xe0, 0x8b, -1} }, /*88*/ + { {0xe0, 0x0c, -1}, {0xe0, 0x8c, -1} }, { {-1}, {-1} }, { {0xe0, 0x0e, -1}, {0xe0, 0x8e, -1} }, { {0xe0, 0x0f, -1}, {0xe0, 0x8f, -1} }, /*8c*/ + { {0xe0, 0x10, -1}, {0xe0, 0x90, -1} }, { {0xe0, 0x11, -1}, {0xe0, 0x91, -1} }, { {0xe0, 0x12, -1}, {0xe0, 0x92, -1} }, { {0xe0, 0x13, -1}, {0xe0, 0x93, -1} }, /*90*/ + { {0xe0, 0x14, -1}, {0xe0, 0x94, -1} }, { {0xe0, 0x15, -1}, {0xe0, 0x95, -1} }, { {0xe0, 0x16, -1}, {0xe0, 0x96, -1} }, { {0xe0, 0x17, -1}, {0xe0, 0x97, -1} }, /*94*/ + { {0xe0, 0x18, -1}, {0xe0, 0x98, -1} }, { {0xe0, 0x19, -1}, {0xe0, 0x99, -1} }, { {0xe0, 0x1a, -1}, {0xe0, 0x9a, -1} }, { {0xe0, 0x1b, -1}, {0xe0, 0x9b, -1} }, /*98*/ + { {0xe0, 0x1c, -1}, {0xe0, 0x9c, -1} }, { {0xe0, 0x1d, -1}, {0xe0, 0x9d, -1} }, { {0xe0, 0x1e, -1}, {0xe0, 0x9e, -1} }, { {0xe0, 0x1f, -1}, {0xe0, 0x9f, -1} }, /*9c*/ + { {0xe0, 0x20, -1}, {0xe0, 0xa0, -1} }, { {0xe0, 0x21, -1}, {0xe0, 0xa1, -1} }, { {0xe0, 0x22, -1}, {0xe0, 0xa2, -1} }, { {0xe0, 0x23, -1}, {0xe0, 0xa3, -1} }, /*a0*/ + { {0xe0, 0x24, -1}, {0xe0, 0xa4, -1} }, { {0xe0, 0x25, -1}, {0xe0, 0xa5, -1} }, { {0xe0, 0x26, -1}, {0xe0, 0xa6, -1} }, { {-1}, {-1} }, /*a4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a8*/ + { {0xe0, 0x2c, -1}, {0xe0, 0xac, -1} }, { {0xe0, 0x2d, -1}, {0xe0, 0xad, -1} }, { {0xe0, 0x2e, -1}, {0xe0, 0xae, -1} }, { {0xe0, 0x2f, -1}, {0xe0, 0xaf, -1} }, /*ac*/ + { {0xe0, 0x30, -1}, {0xe0, 0xb0, -1} }, { {0xe0, 0x31, -1}, {0xe0, 0xb1, -1} }, { {0xe0, 0x32, -1}, {0xe0, 0xb2, -1} }, { {-1}, {-1} }, /*b0*/ + { {0xe0, 0x34, -1}, {0xe0, 0xb4, -1} }, { {0xe0, 0x35, -1}, {0xe0, 0xb5, -1} }, { {-1}, {-1} }, { {0xe0, 0x37, -1}, {0xe0, 0xb7, -1} }, /*b4*/ + { {0xe0, 0x38, -1}, {0xe0, 0xb8, -1} }, { {-1}, {-1} }, { {0xe0, 0x3a, -1}, {0xe0, 0xba, -1} }, { {0xe0, 0x3b, -1}, {0xe0, 0xbb, -1} }, /*b8*/ + { {0xe0, 0x3c, -1}, {0xe0, 0xbc, -1} }, { {0xe0, 0x3d, -1}, {0xe0, 0xbd, -1} }, { {0xe0, 0x3e, -1}, {0xe0, 0xbe, -1} }, { {0xe0, 0x3f, -1}, {0xe0, 0xbf, -1} }, /*bc*/ + { {0xe0, 0x40, -1}, {0xe0, 0xc0, -1} }, { {0xe0, 0x41, -1}, {0xe0, 0xc1, -1} }, { {0xe0, 0x42, -1}, {0xe0, 0xc2, -1} }, { {0xe0, 0x43, -1}, {0xe0, 0xc3, -1} }, /*c0*/ + { {0xe0, 0x44, -1}, {0xe0, 0xc4, -1} }, { {-1}, {-1} }, { {0xe0, 0x46, -1}, {0xe0, 0xc6, -1} }, { {0xe0, 0xaa, 0xe0, 0x47, -1}, {0xe0, 0xc7, 0xe0, 0x2a, -1} }, /*c4*/ + { {0xe0, 0xaa, 0xe0, 0x48, -1}, {0xe0, 0xc8, 0xe0, 0x2a, -1} }, { {0xe0, 0xaa, 0xe0, 0x49, -1}, {0xe0, 0xc9, 0xe0, 0x2a, -1} }, { {-1}, {-1} }, { {0xe, 0xaa, 0xe0, 0x4b, -1}, {0xe0, 0xcb, 0xe0, 0x2a, -1} }, /*c8*/ + { {0xe0, 0x4c, -1}, {0xe0, 0xcc, -1} }, { {0xe0, 0xaa, 0xe0, 0x4d, -1}, {0xe0, 0xcd, 0xe0, 0x2a, -1} }, { {0xe0, 0x4e, -1}, {0xe0, 0xce, -1} }, { {0xe0, 0xaa, 0xe0, 0x4f, -1}, {0xe0, 0xcf, 0xe0, 0x2a, -1} }, /*cc*/ + { {0xe0, 0xaa, 0xe0, 0x50, -1}, {0xe0, 0xd0, 0xe0, 0x2a, -1} }, { {0xe0, 0xaa, 0xe0, 0x51, -1}, {0xe0, 0xd1, 0xe0, 0x2a, -1} }, { {0xe0, 0xaa, 0xe0, 0x52, -1}, {0xe0, 0xd2, 0xe0, 0x2a, -1} }, { {0xe0, 0xaa, 0xe0, 0x53, -1}, {0xe0, 0xd3, 0xe0, 0x2a, -1} }, /*d0*/ + { {0xd4, -1}, {-1} }, { {0xe0, 0x55, -1}, {0xe0, 0xd5, -1} }, { {-1}, {-1} }, { {0xe0, 0x57, -1}, {0xe0, 0xd7, -1} }, /*d4*/ + { {0xe0, 0x58, -1}, {0xe0, 0xd8, -1} }, { {0xe0, 0x59, -1}, {0xe0, 0xd9, -1} }, { {0xe0, 0x5a, -1}, {0xe0, 0xaa, -1} }, { {0xe0, 0x5b, -1}, {0xe0, 0xdb, -1} }, /*d8*/ + { {0xe0, 0x5c, -1}, {0xe0, 0xdc, -1} }, { {0xe0, 0x5d, -1}, {0xe0, 0xdd, -1} }, { {0xe0, 0x5e, -1}, {0xe0, 0xee, -1} }, { {0xe0, 0x5f, -1}, {0xe0, 0xdf, -1} }, /*dc*/ + { {-1}, {-1} }, { {0xe0, 0x61, -1}, {0xe0, 0xe1, -1} }, { {0xe0, 0x62, -1}, {0xe0, 0xe2, -1} }, { {0xe0, 0x63, -1}, {0xe0, 0xe3, -1} }, /*e0*/ + { {0xe0, 0x64, -1}, {0xe0, 0xe4, -1} }, { {0xe0, 0x65, -1}, {0xe0, 0xe5, -1} }, { {0xe0, 0x66, -1}, {0xe0, 0xe6, -1} }, { {0xe0, 0x67, -1}, {0xe0, 0xe7, -1} }, /*e4*/ + { {0xe0, 0x68, -1}, {0xe0, 0xe8, -1} }, { {0xe0, 0x69, -1}, {0xe0, 0xe9, -1} }, { {0xe0, 0x6a, -1}, {0xe0, 0xea, -1} }, { {0xe0, 0x6b, -1}, {0xe0, 0xeb, -1} }, /*e8*/ + { {0xe0, 0x6c, -1}, {0xe0, 0xec, -1} }, { {0xe0, 0x6d, -1}, {0xe0, 0xed, -1} }, { {0xe0, 0x6e, -1}, {0xe0, 0xee, -1} }, { {-1}, {-1} }, /*ec*/ + { {0xe0, 0x70, -1}, {0xe0, 0xf0, -1} }, { {0xf1, -1}, {-1} }, { {0xf2, -1}, {-1} }, { {0xe0, 0x73, -1}, {0xe0, 0xf3, -1} }, /*f0*/ + { {0xe0, 0x74, -1}, {0xe0, 0xf4, -1} }, { {0xe0, 0x75, -1}, {0xe0, 0xf5, -1} }, { {-1}, {-1} }, { {0xe0, 0x77, -1}, {0xe0, 0xf7, -1} }, /*f4*/ + { {0xe0, 0x78, -1}, {0xe0, 0xf8, -1} }, { {0xe0, 0x79, -1}, {0xe0, 0xf9, -1} }, { {0xe0, 0x7a, -1}, {0xe0, 0xfa, -1} }, { {0xe0, 0x7b, -1}, {0xe0, 0xfb, -1} }, /*f8*/ + { {0xe0, 0x7c, -1}, {0xe0, 0xfc, -1} }, { {0xe0, 0x7d, -1}, {0xe0, 0xfd, -1} }, { {0xe0, 0x7e, -1}, {0xe0, 0xfe, -1} }, { {0xe1, 0x1d, -1}, {0xe1, 0x9d, -1} }, /*fc*/ + + { {-1}, {-1} }, { {0xe0, 0x01, -1}, {0xe0, 0x81, -1} }, { {0xe0, 0x02, -1}, {0xe0, 0x82, -1} }, { {0xe0, 0xaa, -1}, {0xe0, 0x2a, -1} }, /*100*/ + { {-1}, {-1} }, { {0xe0, 0x05, -1}, {0xe0, 0x85, -1} }, { {0xe0, 0x06, -1}, {0xe0, 0x86, -1} }, { {0xe0, 0x07, -1}, {0xe0, 0x87, -1} }, /*104*/ + { {0xe0, 0x71, -1}, {0xe0, 0xf1, -1} }, { {0xe0, 0x72, -1}, {0xe0, 0xf2, -1} }, { {0xe0, 0x7f, -1}, {0xe0, 0xff, -1} }, { {0xe0, 0xe1, -1}, {-1} }, /*108*/ + { {0xe0, 0xee, -1}, {-1} }, { {0xe0, 0xf1, -1}, {-1} }, { {0xe0, 0xfe, -1}, {-1} }, { {0xe0, 0xff, -1}, {-1} } /*10c*/ +}; + +static scancode scancode_set2[272] = +{ + { {-1}, {-1} }, { {0x76, -1}, {0xF0, 0x76, -1} }, { {0x16, -1}, {0xF0, 0x16, -1} }, { {0x1E, -1}, {0xF0, 0x1E, -1} }, + { {0x26, -1}, {0xF0, 0x26, -1} }, { {0x25, -1}, {0xF0, 0x25, -1} }, { {0x2E, -1}, {0xF0, 0x2E, -1} }, { {0x36, -1}, {0xF0, 0x36, -1} }, + { {0x3D, -1}, {0xF0, 0x3D, -1} }, { {0x3E, -1}, {0xF0, 0x3E, -1} }, { {0x46, -1}, {0xF0, 0x46, -1} }, { {0x45, -1}, {0xF0, 0x45, -1} }, + { {0x4E, -1}, {0xF0, 0x4E, -1} }, { {0x55, -1}, {0xF0, 0x55, -1} }, { {0x66, -1}, {0xF0, 0x66, -1} }, { {0x0D, -1}, {0xF0, 0x0D, -1} }, + { {0x15, -1}, {0xF0, 0x15, -1} }, { {0x1D, -1}, {0xF0, 0x1D, -1} }, { {0x24, -1}, {0xF0, 0x24, -1} }, { {0x2D, -1}, {0xF0, 0x2D, -1} }, + { {0x2C, -1}, {0xF0, 0x2C, -1} }, { {0x35, -1}, {0xF0, 0x35, -1} }, { {0x3C, -1}, {0xF0, 0x3C, -1} }, { {0x43, -1}, {0xF0, 0x43, -1} }, + { {0x44, -1}, {0xF0, 0x44, -1} }, { {0x4D, -1}, {0xF0, 0x4D, -1} }, { {0x54, -1}, {0xF0, 0x54, -1} }, { {0x5B, -1}, {0xF0, 0x5B, -1} }, + { {0x5A, -1}, {0xF0, 0x5A, -1} }, { {0x14, -1}, {0xF0, 0x14, -1} }, { {0x1C, -1}, {0xF0, 0x1C, -1} }, { {0x1B, -1}, {0xF0, 0x1B, -1} }, + { {0x23, -1}, {0xF0, 0x23, -1} }, { {0x2B, -1}, {0xF0, 0x2B, -1} }, { {0x34, -1}, {0xF0, 0x34, -1} }, { {0x33, -1}, {0xF0, 0x33, -1} }, + { {0x3B, -1}, {0xF0, 0x3B, -1} }, { {0x42, -1}, {0xF0, 0x42, -1} }, { {0x4B, -1}, {0xF0, 0x4B, -1} }, { {0x4C, -1}, {0xF0, 0x4C, -1} }, + { {0x52, -1}, {0xF0, 0x52, -1} }, { {0x0E, -1}, {0xF0, 0x0E, -1} }, { {0x12, -1}, {0xF0, 0x12, -1} }, { {0x5D, -1}, {0xF0, 0x5D, -1} }, + { {0x1A, -1}, {0xF0, 0x1A, -1} }, { {0x22, -1}, {0xF0, 0x22, -1} }, { {0x21, -1}, {0xF0, 0x21, -1} }, { {0x2A, -1}, {0xF0, 0x2A, -1} }, + { {0x32, -1}, {0xF0, 0x32, -1} }, { {0x31, -1}, {0xF0, 0x31, -1} }, { {0x3A, -1}, {0xF0, 0x3A, -1} }, { {0x41, -1}, {0xF0, 0x41, -1} }, + { {0x49, -1}, {0xF0, 0x49, -1} }, { {0x4A, -1}, {0xF0, 0x4A, -1} }, { {0x59, -1}, {0xF0, 0x59, -1} }, { {0x7C, -1}, {0xF0, 0x7C, -1} }, + { {0x11, -1}, {0xF0, 0x11, -1} }, { {0x29, -1}, {0xF0, 0x29, -1} }, { {0x58, -1}, {0xF0, 0x58, -1} }, { {0x05, -1}, {0xF0, 0x05, -1} }, + { {0x06, -1}, {0xF0, 0x06, -1} }, { {0x04, -1}, {0xF0, 0x04, -1} }, { {0x0C, -1}, {0xF0, 0x0C, -1} }, { {0x03, -1}, {0xF0, 0x03, -1} }, + { {0x0B, -1}, {0xF0, 0x0B, -1} }, { {0x83, -1}, {0xF0, 0x83, -1} }, { {0x0A, -1}, {0xF0, 0x0A, -1} }, { {0x01, -1}, {0xF0, 0x01, -1} }, + { {0x09, -1}, {0xF0, 0x09, -1} }, { {0x77, -1}, {0xF0, 0x77, -1} }, { {0x7E, -1}, {0xF0, 0x7E, -1} }, { {0x6C, -1}, {0xF0, 0x6C, -1} }, + { {0x75, -1}, {0xF0, 0x75, -1} }, { {0x7D, -1}, {0xF0, 0x7D, -1} }, { {0x7B, -1}, {0xF0, 0x7B, -1} }, { {0x6B, -1}, {0xF0, 0x6B, -1} }, + { {0x73, -1}, {0xF0, 0x73, -1} }, { {0x74, -1}, {0xF0, 0x74, -1} }, { {0x79, -1}, {0xF0, 0x79, -1} }, { {0x69, -1}, {0xF0, 0x69, -1} }, + { {0x72, -1}, {0xF0, 0x72, -1} }, { {0x7A, -1}, {0xF0, 0x7A, -1} }, { {0x70, -1}, {0xF0, 0x70, -1} }, { {0x71, -1}, {0xF0, 0x71, -1} }, + { {0x84, -1}, {0xF0, 0x84, -1} }, { {0x60, -1}, {0xF0, 0x60, -1} }, { {0x61, -1}, {0xF0, 0x61, -1} }, { {0x78, -1}, {0xF0, 0x78, -1} }, /*54*/ + { {0x07, -1}, {0xF0, 0x07, -1} }, { {0x0F, -1}, {0xF0, 0x0F, -1} }, { {0x17, -1}, {0xF0, 0x17, -1} }, { {0x1F, -1}, {0xF0, 0x1F, -1} }, /*58*/ + { {0x27, -1}, {0xF0, 0x27, -1} }, { {0x2F, -1}, {0xF0, 0x2F, -1} }, { {0x37, -1}, {0xF0, 0x37, -1} }, { {0x3F, -1}, {0xF0, 0x3F, -1} }, /*5c*/ + { {0x47, -1}, {0xF0, 0x47, -1} }, { {0x4F, -1}, {0xF0, 0x4F, -1} }, { {0x56, -1}, {0xF0, 0x56, -1} }, { {0x5E, -1}, {0xF0, 0x5E, -1} }, /*60*/ + { {0x08, -1}, {0xF0, 0x08, -1} }, { {0x10, -1}, {0xF0, 0x10, -1} }, { {0x18, -1}, {0xF0, 0x18, -1} }, { {0x20, -1}, {0xF0, 0x20, -1} }, /*64*/ + { {0x28, -1}, {0xF0, 0x28, -1} }, { {0x30, -1}, {0xF0, 0x30, -1} }, { {0x38, -1}, {0xF0, 0x38, -1} }, { {0x40, -1}, {0xF0, 0x40, -1} }, /*68*/ + { {0x48, -1}, {0xF0, 0x48, -1} }, { {0x50, -1}, {0xF0, 0x50, -1} }, { {0x57, -1}, {0xF0, 0x57, -1} }, { {0x6F, -1}, {0xF0, 0x6F, -1} }, /*6c*/ + { {0x13, -1}, {0xF0, 0x13, -1} }, { {0x19, -1}, {0xF0, 0x19, -1} }, { {0x39, -1}, {0xF0, 0x39, -1} }, { {0x51, -1}, {0xF0, 0x51, -1} }, /*70*/ + { {0x53, -1}, {0xF0, 0x53, -1} }, { {0x5C, -1}, {0xF0, 0x5C, -1} }, { {0x5F, -1}, {0xF0, 0x5F, -1} }, { {0x62, -1}, {0xF0, 0x62, -1} }, /*74*/ + { {0x63, -1}, {0xF0, 0x63, -1} }, { {0x64, -1}, {0xF0, 0x64, -1} }, { {0x65, -1}, {0xF0, 0x65, -1} }, { {0x67, -1}, {0xF0, 0x67, -1} }, /*78*/ + { {0x68, -1}, {0xF0, 0x68, -1} }, { {0x6A, -1}, {0xF0, 0x6A, -1} }, { {0x6D, -1}, {0xF0, 0x6D, -1} }, { {0x6E, -1}, {0xF0, 0x6E, -1} }, /*7c*/ + + { {0x80, -1}, {0xF0, 0x80, -1} }, { {0x81, -1}, {0xF0, 0x81, -1} }, { {0x82, -1}, {0xF0, 0x82, -1} }, { {0xe0, 0x1E, -1}, {0xe0, 0xF0, 0x1E, -1} }, /*80*/ + { {0xe0, 0x26, -1}, {0xe0, 0xF0, 0x26, -1} }, { {0x85, -1}, {0xF0, 0x85, -1} }, { {0x86, -1}, {0xF0, 0x86, -1} }, { {0x87, -1}, {0xF0, 0x87, -1} }, /*84*/ + { {0xe0, 0x3D, -1}, {0xe0, 0xF0, 0x3D, -1} }, { {0xe0, 0x3E, -1}, {0xe0, 0xF0, 0x3E, -1} }, { {0xe0, 0x46, -1}, {0xe0, 0xF0, 0x46, -1} }, { {0xe0, 0x45, -1}, {0xe0, 0xF0, 0x45, -1} }, /*88*/ + { {0xe0, 0x4E, -1}, {0xe0, 0xF0, 0x4E, -1} }, { {-1}, {-1} }, { {0xe0, 0x66, -1}, {0xe0, 0xF0, 0x66, -1} }, { {0xe0, 0x0D, -1}, {0xe0, 0xF0, 0x0D, -1} }, /*8c*/ + { {0xe0, 0x15, -1}, {0xe0, 0xF0, 0x15, -1} }, { {0xe0, 0x1D, -1}, {0xe0, 0xF0, 0x1D, -1} }, { {0xe0, 0x24, -1}, {0xe0, 0xF0, 0x24, -1} }, { {0xe0, 0x2D, -1}, {0xe0, 0xF0, 0x2D, -1} }, /*90*/ + { {0xe0, 0x2C, -1}, {0xe0, 0xF0, 0x2C, -1} }, { {0xe0, 0x35, -1}, {0xe0, 0xF0, 0x35, -1} }, { {0xe0, 0x3C, -1}, {0xe0, 0xF0, 0x3C, -1} }, { {0xe0, 0x43, -1}, {0xe0, 0xF0, 0x43, -1} }, /*94*/ + { {0xe0, 0x44, -1}, {0xe0, 0xF0, 0x44, -1} }, { {0xe0, 0x4D, -1}, {0xe0, 0xF0, 0x4D, -1} }, { {0xe0, 0x54, -1}, {0xe0, 0xF0, 0x54, -1} }, { {0xe0, 0x5B, -1}, {0xe0, 0xF0, 0x5B, -1} }, /*98*/ + { {0xe0, 0x5A, -1}, {0xe0, 0xF0, 0x5A, -1} }, { {0xe0, 0x14, -1}, {0xe0, 0xF0, 0x14, -1} }, { {0xe0, 0x1C, -1}, {0xe0, 0xF0, 0x1C, -1} }, { {0xe0, 0x1B, -1}, {0xe0, 0xF0, 0x1B, -1} }, /*9c*/ + { {0xe0, 0x23, -1}, {0xe0, 0xF0, 0x23, -1} }, { {0xe0, 0x2B, -1}, {0xe0, 0xF0, 0x2B, -1} }, { {0xe0, 0x34, -1}, {0xe0, 0xF0, 0x34, -1} }, { {0xe0, 0x33, -1}, {0xe0, 0xF0, 0x33, -1} }, /*a0*/ + { {0xe0, 0x3B, -1}, {0xe0, 0xF0, 0x3B, -1} }, { {0xe0, 0x42, -1}, {0xe0, 0xF0, 0x42, -1} }, { {0xe0, 0x4B, -1}, {0xe0, 0xF0, 0x4B, -1} }, { {-1}, {-1} }, /*a4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a8*/ + { {0xe0, 0x1A, -1}, {0xe0, 0xF0, 0x1A, -1} }, { {0xe0, 0x22, -1}, {0xe0, 0xF0, 0x22, -1} }, { {0xe0, 0x21, -1}, {0xe0, 0xF0, 0x21, -1} }, { {0xe0, 0x2A, -1}, {0xe0, 0xF0, 0x2A, -1} }, /*ac*/ + { {0xe0, 0x32, -1}, {0xe0, 0xF0, 0x32, -1} }, { {0xe0, 0x31, -1}, {0xe0, 0xF0, 0x31, -1} }, { {0xe0, 0x3A, -1}, {0xe0, 0xF0, 0x3A, -1} }, { {-1}, {-1} }, /*b0*/ + { {0xe0, 0x49, -1}, {0xe0, 0xF0, 0x49, -1} }, { {0xe0, 0x4A, -1}, {0xe0, 0xF0, 0x4A, -1} }, { {-1}, {-1} }, { {0xe0, 0x7C, -1}, {0xe0, 0xF0, 0x7C, -1} }, /*b4*/ + { {0xe0, 0x11, -1}, {0xe0, 0xF0, 0x11, -1} }, { {-1}, {-1} }, { {0xe0, 0x58, -1}, {0xe0, 0xF0, 0x58, -1} }, { {0xe0, 0x05, -1}, {0xe0, 0xF0, 0x05, -1} }, /*b8*/ + { {0xe0, 0x06, -1}, {0xe0, 0xF0, 0x06, -1} }, { {0xe0, 0x04, -1}, {0xe0, 0xF0, 0x04, -1} }, { {0xe0, 0x0C, -1}, {0xe0, 0xF0, 0x0C, -1} }, { {0xe0, 0x03, -1}, {0xe0, 0xF0, 0x03, -1} }, /*bc*/ + { {0xe0, 0x0B, -1}, {0xe0, 0xF0, 0x0B, -1} }, { {0xe0, 0x02, -1}, {0xe0, 0xF0, 0x02, -1} }, { {0xe0, 0x0A, -1}, {0xe0, 0xF0, 0x0A, -1} }, { {0xe0, 0x01, -1}, {0xe0, 0xF0, 0x01, -1} }, /*c0*/ + { {0xe0, 0x09, -1}, {0xe0, 0xF0, 0x09, -1} }, { {-1}, {-1} }, { {0xe0, 0x7E, -1}, {0xe0, 0xF0, 0x7E, -1} }, { {0xe0, 0xf0, 0x12, 0xe0, 0x6C, -1}, {0xe0, 0xF0, 0x6C, 0xe0, 0x12, -1} }, /*c4*/ + { {0xe0, 0xf0, 0x12, 0xe0, 0x75, -1}, {0xe0, 0xF0, 0x75, 0xe0, 0x12, -1} }, { {0xe0, 0xf0, 0x12, 0xe0, 0x7D, -1}, {0xe0, 0xF0, 0x7D, 0xe0, 0x12, -1} }, { {-1}, {-1} }, { {0xe0, 0xf0, 0x12, 0xe0, 0x6B, -1}, {0xe0, 0xF0, 0x6B, 0xe0, 0x12, -1} }, /*c8*/ + { {0xe0, 0x73, -1}, {0xe0, 0xF0, 0x73, -1} }, { {0xe0, 0xf0, 0x12, 0xe0, 0x74, -1}, {0xe0, 0xF0, 0x74, 0xe0, 0x12, -1} }, { {0xe0, 0x79, -1}, {0xe0, 0xF0, 0x79, -1} }, { {0xe0, 0xf0, 0x12, 0xe0, 0x69, -1}, {0xe0, 0xF0, 0x69, 0xe0, 0x12, -1} }, /*cc*/ + { {0xe0, 0xf0, 0x12, 0xe0, 0x72, -1}, {0xe0, 0xF0, 0x72, 0xe0, 0x12, -1} }, { {0xe0, 0xf0, 0x12, 0xe0, 0x7A, -1}, {0xe0, 0xF0, 0x7A, 0xe0, 0x12, -1} }, { {0xe0, 0xf0, 0x12, 0xe0, 0x70, -1}, {0xe0, 0xF0, 0x70, 0xe0, 0x12, -1} }, { {0xe0, 0xf0, 0x12, 0xe0, 0x71, -1}, {0xe0, 0xF0, 0x71, 0xe0, 0x12, -1} }, /*d0*/ + { {0xd4, -1}, {0xF0, 0xD4, -1} }, { {0xe0, 0x60, -1}, {0xe0, 0xF0, 0x60, -1} }, { {-1}, {-1} }, { {0xe0, 0x78, -1}, {0xe0, 0xF0, 0x78, -1} }, /*d4*/ + { {0xe0, 0x07, -1}, {0xe0, 0xF0, 0x07, -1} }, { {0xe0, 0x0F, -1}, {0xe0, 0xF0, 0x0F, -1} }, { {0xe0, 0x17, -1}, {0xe0, 0xF0, 0x17, -1} }, { {0xe0, 0x1F, -1}, {0xe0, 0xF0, 0x1F, -1} }, /*d8*/ + { {0xe0, 0x27, -1}, {0xe0, 0xF0, 0x27, -1} }, { {0xe0, 0x2F, -1}, {0xe0, 0xF0, 0x2F, -1} }, { {0xe0, 0x37, -1}, {0xe0, 0xF0, 0x37, -1} }, { {0xe0, 0x3F, -1}, {0xe0, 0xF0, 0x3F, -1} }, /*dc*/ + { {-1}, {-1} }, { {0xe0, 0x4F, -1}, {0xe0, 0xF0, 0x4F, -1} }, { {0xe0, 0x56, -1}, {0xe0, 0xF0, 0x56, -1} }, { {0xe0, 0x5E, -1}, {0xe0, 0xF0, 0x5E, -1} }, /*e0*/ + { {0xe0, 0x08, -1}, {0xe0, 0xF0, 0x08, -1} }, { {0xe0, 0x10, -1}, {0xe0, 0xF0, 0x10, -1} }, { {0xe0, 0x18, -1}, {0xe0, 0xF0, 0x18, -1} }, { {0xe0, 0x20, -1}, {0xe0, 0xF0, 0x20, -1} }, /*e4*/ + { {0xe0, 0x28, -1}, {0xe0, 0xF0, 0x28, -1} }, { {0xe0, 0x30, -1}, {0xe0, 0xF0, 0x30, -1} }, { {0xe0, 0x38, -1}, {0xe0, 0xF0, 0x38, -1} }, { {0xe0, 0x40, -1}, {0xe0, 0xF0, 0x40, -1} }, /*e8*/ + { {0xe0, 0x48, -1}, {0xe0, 0xF0, 0x48, -1} }, { {0xe0, 0x50, -1}, {0xe0, 0xF0, 0x50, -1} }, { {0xe0, 0x57, -1}, {0xe0, 0xF0, 0x57, -1} }, { {-1}, {-1} }, /*ec*/ + { {0xe0, 0x13, -1}, {0xe0, 0xF0, 0x13, -1} }, { {0xf1, -1}, {0xF0, 0xF1, -1} }, { {0xf2, -1}, {0xF0, 0xF2, -1} }, { {0xe0, 0x51, -1}, {0xe0, 0xF0, 0x51, -1} }, /*f0*/ + { {0xe0, 0x53, -1}, {0xe0, 0xF0, 0x53, -1} }, { {0xe0, 0x5C, -1}, {0xe0, 0xF0, 0x5C, -1} }, { {-1}, {-1} }, { {0xe0, 0x62, -1}, {0xe0, 0xF0, 0x62, -1} }, /*f4*/ + { {0xe0, 0x63, -1}, {0xe0, 0xF0, 0x63, -1} }, { {0xe0, 0x64, -1}, {0xe0, 0xF0, 0x64, -1} }, { {0xe0, 0x65, -1}, {0xe0, 0xF0, 0x65, -1} }, { {0xe0, 0x67, -1}, {0xe0, 0xF0, 0x67, -1} }, /*f8*/ + { {0xe0, 0x68, -1}, {0xe0, 0xF0, 0x68, -1} }, { {0xe0, 0x6A, -1}, {0xe0, 0xF0, 0x6A, -1} }, { {0xe0, 0x6D, -1}, {0xe0, 0xF0, 0x6D, -1} }, { {0xe1, 0x14, -1}, {0xe1, 0xf0, 0x14, -1} }, /*fc*/ + + { {-1}, {-1} }, { {0xe0, 0x76, -1}, {0xe0, 0xF0, 0x76, -1} }, { {0xe0, 0x16, -1}, {0xe0, 0xF0, 0x16, -1} }, { {0xe0, 0xf0, 0x12, -1}, {0xe0, 0x12, -1} }, /*100*/ + { {-1}, {-1} }, { {0xe0, 0x25, -1}, {0xe0, 0xF0, 0x25, -1} }, { {0xe0, 0x2E, -1}, {0xe0, 0xF0, 0x2E, -1} }, { {0xe0, 0x36, -1}, {0xe0, 0xF0, 0x36, -1} }, /*104*/ + { {0xe0, 0x19, -1}, {0xe0, 0xF0, 0x19, -1} }, { {0xe0, 0x39, -1}, {0xe0, 0xF0, 0x39, -1} }, { {0xe0, 0x6E, -1}, {0xe0, 0xF0, 0x6E, -1} }, { {0xe0, 0xe1, -1}, {0xe0, 0xF0, 0xE1, -1} }, /*108*/ + { {0xe0, 0xee, -1}, {0xe0, 0xF0, 0xEE, -1} }, { {0xe0, 0xf1, -1}, {0xe0, 0xF0, 0xF1, -1} }, { {0xe0, 0xfe, -1}, {0xe0, 0xF0, 0xFE, -1} }, { {0xe0, 0xff, -1}, {0xe0, 0xF0, 0xFF, -1} } /*10c*/ +}; + +static scancode scancode_set3[272] = +{ + { {-1}, {-1} }, { {0x08, -1}, {0xF0, 0x08, -1} }, { {0x16, -1}, {0xF0, 0x16, -1} }, { {0x1E, -1}, {0xF0, 0x1E, -1} }, + { {0x26, -1}, {0xF0, 0x26, -1} }, { {0x25, -1}, {0xF0, 0x25, -1} }, { {0x2E, -1}, {0xF0, 0x2E, -1} }, { {0x36, -1}, {0xF0, 0x36, -1} }, + { {0x3D, -1}, {0xF0, 0x3D, -1} }, { {0x3E, -1}, {0xF0, 0x3E, -1} }, { {0x46, -1}, {0xF0, 0x46, -1} }, { {0x45, -1}, {0xF0, 0x45, -1} }, + { {0x4E, -1}, {0xF0, 0x4E, -1} }, { {0x55, -1}, {0xF0, 0x55, -1} }, { {0x66, -1}, {0xF0, 0x66, -1} }, { {0x0D, -1}, {0xF0, 0x0D, -1} }, + { {0x15, -1}, {0xF0, 0x15, -1} }, { {0x1D, -1}, {0xF0, 0x1D, -1} }, { {0x24, -1}, {0xF0, 0x24, -1} }, { {0x2D, -1}, {0xF0, 0x2D, -1} }, + { {0x2C, -1}, {0xF0, 0x2C, -1} }, { {0x35, -1}, {0xF0, 0x35, -1} }, { {0x3C, -1}, {0xF0, 0x3C, -1} }, { {0x43, -1}, {0xF0, 0x43, -1} }, + { {0x44, -1}, {0xF0, 0x44, -1} }, { {0x4D, -1}, {0xF0, 0x4D, -1} }, { {0x54, -1}, {0xF0, 0x54, -1} }, { {0x5B, -1}, {0xF0, 0x5B, -1} }, + { {0x5A, -1}, {0xF0, 0x5A, -1} }, { {0x11, -1}, {0xF0, 0x11, -1} }, { {0x1C, -1}, {0xF0, 0x1C, -1} }, { {0x1B, -1}, {0xF0, 0x1B, -1} }, + { {0x23, -1}, {0xF0, 0x23, -1} }, { {0x2B, -1}, {0xF0, 0x2B, -1} }, { {0x34, -1}, {0xF0, 0x34, -1} }, { {0x33, -1}, {0xF0, 0x33, -1} }, + { {0x3B, -1}, {0xF0, 0x3B, -1} }, { {0x42, -1}, {0xF0, 0x42, -1} }, { {0x4B, -1}, {0xF0, 0x4B, -1} }, { {0x4C, -1}, {0xF0, 0x4C, -1} }, + { {0x52, -1}, {0xF0, 0x52, -1} }, { {0x0E, -1}, {0xF0, 0x0E, -1} }, { {0x12, -1}, {0xF0, 0x12, -1} }, { {0x5D, -1}, {0xF0, 0x5D, -1} }, + { {0x1A, -1}, {0xF0, 0x1A, -1} }, { {0x22, -1}, {0xF0, 0x22, -1} }, { {0x21, -1}, {0xF0, 0x21, -1} }, { {0x2A, -1}, {0xF0, 0x2A, -1} }, + { {0x32, -1}, {0xF0, 0x32, -1} }, { {0x31, -1}, {0xF0, 0x31, -1} }, { {0x3A, -1}, {0xF0, 0x3A, -1} }, { {0x41, -1}, {0xF0, 0x41, -1} }, + { {0x49, -1}, {0xF0, 0x49, -1} }, { {0x4A, -1}, {0xF0, 0x4A, -1} }, { {0x59, -1}, {0xF0, 0x59, -1} }, { {0x7E, -1}, {0xF0, 0x7E, -1} }, + { {0x19, -1}, {0xF0, 0x19, -1} }, { {0x29, -1}, {0xF0, 0x29, -1} }, { {0x14, -1}, {0xF0, 0x14, -1} }, { {0x07, -1}, {0xF0, 0x07, -1} }, + { {0x0F, -1}, {0xF0, 0x0F, -1} }, { {0x17, -1}, {0xF0, 0x17, -1} }, { {0x1F, -1}, {0xF0, 0x1F, -1} }, { {0x27, -1}, {0xF0, 0x27, -1} }, + { {0x2F, -1}, {0xF0, 0x2F, -1} }, { {0x37, -1}, {0xF0, 0x37, -1} }, { {0x3F, -1}, {0xF0, 0x3F, -1} }, { {0x47, -1}, {0xF0, 0x47, -1} }, + { {0x4F, -1}, {0xF0, 0x4F, -1} }, { {0x76, -1}, {0xF0, 0x76, -1} }, { {0x5F, -1}, {0xF0, 0x5F, -1} }, { {0x6C, -1}, {0xF0, 0x6C, -1} }, + { {0x75, -1}, {0xF0, 0x75, -1} }, { {0x7D, -1}, {0xF0, 0x7D, -1} }, { {0x84, -1}, {0xF0, 0x84, -1} }, { {0x6B, -1}, {0xF0, 0x6B, -1} }, + { {0x73, -1}, {0xF0, 0x73, -1} }, { {0x74, -1}, {0xF0, 0x74, -1} }, { {0x7C, -1}, {0xF0, 0x7C, -1} }, { {0x69, -1}, {0xF0, 0x69, -1} }, + { {0x72, -1}, {0xF0, 0x72, -1} }, { {0x7A, -1}, {0xF0, 0x7A, -1} }, { {0x70, -1}, {0xF0, 0x70, -1} }, { {0x71, -1}, {0xF0, 0x71, -1} }, + { {0x57, -1}, {0xF0, 0x57, -1} }, { {0x60, -1}, {0xF0, 0x60, -1} }, { {-1}, {-1} }, { {0x56, -1}, {0xF0, 0x56, -1} }, + { {0x5E, -1}, {0xF0, 0x5E, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, + { {-1}, {-1} }, { {0x10, -1}, {0xF0, 0x10, -1} }, { {0x18, -1}, {0xF0, 0x18, -1} }, { {0x20, -1}, {0xF0, 0x20, -1} }, + { {0x28, -1}, {0xF0, 0x28, -1} }, { {0x30, -1}, {0xF0, 0x30, -1} }, { {0x38, -1}, {0xF0, 0x38, -1} }, { {0x40, -1}, {0xF0, 0x40, -1} }, + { {0x48, -1}, {0xF0, 0x48, -1} }, { {0x50, -1}, {0xF0, 0x50, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, + { {0x87, -1}, {0xF0, 0x87, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {0x51, -1}, {0xF0, 0x51, -1} }, + { {0x53, -1}, {0xF0, 0x53, -1} }, { {0x5C, -1}, {0xF0, 0x5C, -1} }, { {-1}, {-1} }, { {0x62, -1}, {0xF0, 0x62, -1} }, + { {0x63, -1}, {0xF0, 0x63, -1} }, { {0x86, -1}, {0xF0, 0x86, -1} }, { {-1}, {-1} }, { {0x85, -1}, {0xF0, 0x85, -1} }, + { {0x68, -1}, {0xF0, 0x68, -1} }, { {0x13, -1}, {0xF0, 0x13, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, + + { {0x80, -1}, {0xF0, 0x80, -1} }, { {0x81, -1}, {0xF0, 0x81, -1} }, { {0x82, -1}, {0xF0, 0x82, -1} }, { {0xe0, 0x1E, -1}, {0xe0, 0xF0, 0x1E, -1} }, /*80*/ + { {0xe0, 0x26, -1}, {0xe0, 0xF0, 0x26, -1} }, { {0x85, -1}, {0xF0, 0x85, -1} }, { {0x86, -1}, {0xF0, 0x86, -1} }, { {0x87, -1}, {0xF0, 0x87, -1} }, /*84*/ + { {0xe0, 0x3D, -1}, {0xe0, 0xF0, 0x3D, -1} }, { {0xe0, 0x3E, -1}, {0xe0, 0xF0, 0x3E, -1} }, { {0xe0, 0x46, -1}, {0xe0, 0xF0, 0x46, -1} }, { {0xe0, 0x45, -1}, {0xe0, 0xF0, 0x45, -1} }, /*88*/ + { {0xe0, 0x4E, -1}, {0xe0, 0xF0, 0x4E, -1} }, { {-1}, {-1} }, { {0xe0, 0x66, -1}, {0xe0, 0xF0, 0x66, -1} }, { {0xe0, 0x0D, -1}, {0xe0, 0xF0, 0x0D, -1} }, /*8c*/ + { {0xe0, 0x15, -1}, {0xe0, 0xF0, 0x15, -1} }, { {0xe0, 0x1D, -1}, {0xe0, 0xF0, 0x1D, -1} }, { {0xe0, 0x24, -1}, {0xe0, 0xF0, 0x24, -1} }, { {0xe0, 0x2D, -1}, {0xe0, 0xF0, 0x2D, -1} }, /*90*/ + { {0xe0, 0x2C, -1}, {0xe0, 0xF0, 0x2C, -1} }, { {0xe0, 0x35, -1}, {0xe0, 0xF0, 0x35, -1} }, { {0xe0, 0x3C, -1}, {0xe0, 0xF0, 0x3C, -1} }, { {0xe0, 0x43, -1}, {0xe0, 0xF0, 0x43, -1} }, /*94*/ + { {0xe0, 0x44, -1}, {0xe0, 0xF0, 0x44, -1} }, { {0xe0, 0x4D, -1}, {0xe0, 0xF0, 0x4D, -1} }, { {0xe0, 0x54, -1}, {0xe0, 0xF0, 0x54, -1} }, { {0xe0, 0x5B, -1}, {0xe0, 0xF0, 0x5B, -1} }, /*98*/ + { {0x79, -1}, {0xF0, 0x79, -1} }, { {0x58, -1}, {0xF0, 0x58, -1} }, { {0xe0, 0x1C, -1}, {0xe0, 0xF0, 0x1C, -1} }, { {0xe0, 0x1B, -1}, {0xe0, 0xF0, 0x1B, -1} }, /*9c*/ + { {0xe0, 0x23, -1}, {0xe0, 0xF0, 0x23, -1} }, { {0xe0, 0x2B, -1}, {0xe0, 0xF0, 0x2B, -1} }, { {0xe0, 0x34, -1}, {0xe0, 0xF0, 0x34, -1} }, { {0xe0, 0x33, -1}, {0xe0, 0xF0, 0x33, -1} }, /*a0*/ + { {0xe0, 0x3B, -1}, {0xe0, 0xF0, 0x3B, -1} }, { {0xe0, 0x42, -1}, {0xe0, 0xF0, 0x42, -1} }, { {0xe0, 0x4B, -1}, {0xe0, 0xF0, 0x4B, -1} }, { {-1}, {-1} }, /*a4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a8*/ + { {0xe0, 0x1A, -1}, {0xe0, 0xF0, 0x1A, -1} }, { {0xe0, 0x22, -1}, {0xe0, 0xF0, 0x22, -1} }, { {0xe0, 0x21, -1}, {0xe0, 0xF0, 0x21, -1} }, { {0xe0, 0x2A, -1}, {0xe0, 0xF0, 0x2A, -1} }, /*ac*/ + { {0xe0, 0x32, -1}, {0xe0, 0xF0, 0x32, -1} }, { {0xe0, 0x31, -1}, {0xe0, 0xF0, 0x31, -1} }, { {0xe0, 0x3A, -1}, {0xe0, 0xF0, 0x3A, -1} }, { {-1}, {-1} }, /*b0*/ + { {0xe0, 0x49, -1}, {0xe0, 0xF0, 0x49, -1} }, { {0x77, -1}, {0xF0, 0x77, -1} }, { {-1}, {-1} }, { {0x57, -1}, {0xF0, 0x57, -1} }, /*b4*/ + { {0x39, -1}, {0xF0, 0x39, -1} }, { {-1}, {-1} }, { {0xe0, 0x58, -1}, {0xe0, 0xF0, 0x58, -1} }, { {0xe0, 0x05, -1}, {0xe0, 0xF0, 0x05, -1} }, /*b8*/ + { {0xe0, 0x06, -1}, {0xe0, 0xF0, 0x06, -1} }, { {0xe0, 0x04, -1}, {0xe0, 0xF0, 0x04, -1} }, { {0xe0, 0x0C, -1}, {0xe0, 0xF0, 0x0C, -1} }, { {0xe0, 0x03, -1}, {0xe0, 0xF0, 0x03, -1} }, /*bc*/ + { {0xe0, 0x0B, -1}, {0xe0, 0xF0, 0x0B, -1} }, { {0xe0, 0x02, -1}, {0xe0, 0xF0, 0x02, -1} }, { {0xe0, 0x0A, -1}, {0xe0, 0xF0, 0x0A, -1} }, { {0xe0, 0x01, -1}, {0xe0, 0xF0, 0x01, -1} }, /*c0*/ + { {0xe0, 0x09, -1}, {0xe0, 0xF0, 0x09, -1} }, { {-1}, {-1} }, { {0xe0, 0x7E, -1}, {0xe0, 0xF0, 0x7E, -1} }, { {0x6E, -1}, {0xF0, 0x6E, -1} }, /*c4*/ + { {0x63, -1}, {0xF0, 0x63, -1} }, { {0x6F, -1}, {0xF0, 0x6F, -1} }, { {-1}, {-1} }, { {0x61, -1}, {0xF0, 0x61, -1} }, /*c8*/ + { {0xe0, 0x73, -1}, {0xe0, 0xF0, 0x73, -1} }, { {0x6A, -1}, {0xF0, 0x6A, -1} }, { {0xe0, 0x79, -1}, {0xe0, 0xF0, 0x79, -1} }, { {0x65, -1}, {0xF0, 0x65, -1} }, /*cc*/ + { {0x60, -1}, {0xe0, 0x60, -1} }, { {0x6D, -1}, {0xF0, 0x6D, -1} }, { {0x67, -1}, {0xF0, 0x67, -1} }, { {0x64, -1}, {0xF0, 0x64, -1} }, /*d0*/ + { {0xd4, -1}, {0xF0, 0xD4, -1} }, { {0xe0, 0x60, -1}, {0xe0, 0xF0, 0x60, -1} }, { {-1}, {-1} }, { {0xe0, 0x78, -1}, {0xe0, 0xF0, 0x78, -1} }, /*d4*/ + { {0xe0, 0x07, -1}, {0xe0, 0xF0, 0x07, -1} }, { {0xe0, 0x0F, -1}, {0xe0, 0xF0, 0x0F, -1} }, { {0xe0, 0x17, -1}, {0xe0, 0xF0, 0x17, -1} }, { {0x8B, -1}, {0xF0, 0x8B, -1} }, /*d8*/ + { {0x8C, -1}, {0xF0, 0x8C, -1} }, { {0x8D, -1}, {0xF0, 0x8D, -1} }, { {-1}, {-1} }, { {0x7F, -1}, {0xF0, 0x7F, -1} }, /*dc*/ + { {-1}, {-1} }, { {0xe0, 0x4F, -1}, {0xe0, 0xF0, 0x4F, -1} }, { {0xe0, 0x56, -1}, {0xe0, 0xF0, 0x56, -1} }, { {-1}, {-1} }, /*e0*/ + { {0xe0, 0x08, -1}, {0xe0, 0xF0, 0x08, -1} }, { {0xe0, 0x10, -1}, {0xe0, 0xF0, 0x10, -1} }, { {0xe0, 0x18, -1}, {0xe0, 0xF0, 0x18, -1} }, { {0xe0, 0x20, -1}, {0xe0, 0xF0, 0x20, -1} }, /*e4*/ + { {0xe0, 0x28, -1}, {0xe0, 0xF0, 0x28, -1} }, { {0xe0, 0x30, -1}, {0xe0, 0xF0, 0x30, -1} }, { {0xe0, 0x38, -1}, {0xe0, 0xF0, 0x38, -1} }, { {0xe0, 0x40, -1}, {0xe0, 0xF0, 0x40, -1} }, /*e8*/ + { {0xe0, 0x48, -1}, {0xe0, 0xF0, 0x48, -1} }, { {0xe0, 0x50, -1}, {0xe0, 0xF0, 0x50, -1} }, { {0xe0, 0x57, -1}, {0xe0, 0xF0, 0x57, -1} }, { {-1}, {-1} }, /*ec*/ + { {0xe0, 0x13, -1}, {0xe0, 0xF0, 0x13, -1} }, { {0xf1, -1}, {0xF0, 0xF1, -1} }, { {0xf2, -1}, {0xF0, 0xF2, -1} }, { {0xe0, 0x51, -1}, {0xe0, 0xF0, 0x51, -1} }, /*f0*/ + { {0xe0, 0x53, -1}, {0xe0, 0xF0, 0x53, -1} }, { {0xe0, 0x5C, -1}, {0xe0, 0xF0, 0x5C, -1} }, { {-1}, {-1} }, { {0xe0, 0x62, -1}, {0xe0, 0xF0, 0x62, -1} }, /*f4*/ + { {0xe0, 0x63, -1}, {0xe0, 0xF0, 0x63, -1} }, { {0xe0, 0x64, -1}, {0xe0, 0xF0, 0x64, -1} }, { {0xe0, 0x65, -1}, {0xe0, 0xF0, 0x65, -1} }, { {0xe0, 0x67, -1}, {0xe0, 0xF0, 0x67, -1} }, /*f8*/ + { {0xe0, 0x68, -1}, {0xe0, 0xF0, 0x68, -1} }, { {0xe0, 0x6A, -1}, {0xe0, 0xF0, 0x6A, -1} }, { {0xe0, 0x6D, -1}, {0xe0, 0xF0, 0x6D, -1} }, { {0x62, -1}, {0xF0, 0x62, -1} }, /*fc*/ + + { {-1}, {-1} }, { {0xe0, 0x76, -1}, {0xe0, 0xF0, 0x76, -1} }, { {0xe0, 0x16, -1}, {0xe0, 0xF0, 0x16, -1} }, { {-1}, {-1} }, /*100*/ + { {-1}, {-1} }, { {0xe0, 0x25, -1}, {0xe0, 0xF0, 0x25, -1} }, { {0xe0, 0x2E, -1}, {0xe0, 0xF0, 0x2E, -1} }, { {0xe0, 0x36, -1}, {0xe0, 0xF0, 0x36, -1} }, /*104*/ + { {0xe0, 0x19, -1}, {0xe0, 0xF0, 0x19, -1} }, { {0xe0, 0x39, -1}, {0xe0, 0xF0, 0x39, -1} }, { {0xe0, 0x6E, -1}, {0xe0, 0xF0, 0x6E, -1} }, { {0xe0, 0xe1, -1}, {0xe0, 0xF0, 0xE1, -1} }, /*108*/ + { {0xe0, 0xee, -1}, {0xe0, 0xF0, 0xEE, -1} }, { {0xe0, 0xf1, -1}, {0xe0, 0xF0, 0xF1, -1} }, { {0xe0, 0xfe, -1}, {0xe0, 0xF0, 0xFE, -1} }, { {0xe0, 0xff, -1}, {0xe0, 0xF0, 0xFF, -1} } /*10c*/ +}; + +/*XT keyboard has no escape scancodes, and no scancodes beyond 53*/ +static scancode scancode_xt[272] = +{ + { {-1}, {-1} }, { {0x01, -1}, {0x81, -1} }, { {0x02, -1}, {0x82, -1} }, { {0x03, -1}, {0x83, -1} }, + { {0x04, -1}, {0x84, -1} }, { {0x05, -1}, {0x85, -1} }, { {0x06, -1}, {0x86, -1} }, { {0x07, -1}, {0x87, -1} }, + { {0x08, -1}, {0x88, -1} }, { {0x09, -1}, {0x89, -1} }, { {0x0a, -1}, {0x8a, -1} }, { {0x0b, -1}, {0x8b, -1} }, + { {0x0c, -1}, {0x8c, -1} }, { {0x0d, -1}, {0x8d, -1} }, { {0x0e, -1}, {0x8e, -1} }, { {0x0f, -1}, {0x8f, -1} }, + { {0x10, -1}, {0x90, -1} }, { {0x11, -1}, {0x91, -1} }, { {0x12, -1}, {0x92, -1} }, { {0x13, -1}, {0x93, -1} }, + { {0x14, -1}, {0x94, -1} }, { {0x15, -1}, {0x95, -1} }, { {0x16, -1}, {0x96, -1} }, { {0x17, -1}, {0x97, -1} }, + { {0x18, -1}, {0x98, -1} }, { {0x19, -1}, {0x99, -1} }, { {0x1a, -1}, {0x9a, -1} }, { {0x1b, -1}, {0x9b, -1} }, + { {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, { {0x1e, -1}, {0x9e, -1} }, { {0x1f, -1}, {0x9f, -1} }, + { {0x20, -1}, {0xa0, -1} }, { {0x21, -1}, {0xa1, -1} }, { {0x22, -1}, {0xa2, -1} }, { {0x23, -1}, {0xa3, -1} }, + { {0x24, -1}, {0xa4, -1} }, { {0x25, -1}, {0xa5, -1} }, { {0x26, -1}, {0xa6, -1} }, { {0x27, -1}, {0xa7, -1} }, + { {0x28, -1}, {0xa8, -1} }, { {0x29, -1}, {0xa9, -1} }, { {0x2a, -1}, {0xaa, -1} }, { {0x2b, -1}, {0xab, -1} }, + { {0x2c, -1}, {0xac, -1} }, { {0x2d, -1}, {0xad, -1} }, { {0x2e, -1}, {0xae, -1} }, { {0x2f, -1}, {0xaf, -1} }, + { {0x30, -1}, {0xb0, -1} }, { {0x31, -1}, {0xb1, -1} }, { {0x32, -1}, {0xb2, -1} }, { {0x33, -1}, {0xb3, -1} }, + { {0x34, -1}, {0xb4, -1} }, { {0x35, -1}, {0xb5, -1} }, { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} }, + { {0x38, -1}, {0xb8, -1} }, { {0x39, -1}, {0xb9, -1} }, { {0x3a, -1}, {0xba, -1} }, { {0x3b, -1}, {0xbb, -1} }, + { {0x3c, -1}, {0xbc, -1} }, { {0x3d, -1}, {0xbd, -1} }, { {0x3e, -1}, {0xbe, -1} }, { {0x3f, -1}, {0xbf, -1} }, + { {0x40, -1}, {0xc0, -1} }, { {0x41, -1}, {0xc1, -1} }, { {0x42, -1}, {0xc2, -1} }, { {0x43, -1}, {0xc3, -1} }, + { {0x44, -1}, {0xc4, -1} }, { {0x45, -1}, {0xc5, -1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} }, + { {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, { {0x4a, -1}, {0xca, -1} }, { {0x4b, -1}, {0xcb, -1} }, + { {0x4c, -1}, {0xcc, -1} }, { {0x4d, -1}, {0xcd, -1} }, { {0x4e, -1}, {0xce, -1} }, { {0x4f, -1}, {0xcf, -1} }, + { {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} }, + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*54*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*58*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*5c*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*60*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*64*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*68*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*6c*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*70*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*74*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*78*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*7c*/ + + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*80*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*84*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*88*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*8c*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*90*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*94*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*98*/ + { {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*9c*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {0xaa, -1}, {0x2a, -1} }, { {-1}, {-1} }, /*a8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*ac*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*b0*/ + { {-1}, {-1} }, { {0x35, -1}, {0xb5, -1} }, { {0xb6, -1}, {0x36, -1} }, { {0x37, -1}, {0xb7, -1} }, /*b4*/ + { {0x38, -1}, {0xb8, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*b8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*bc*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*c0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} }, /*c4*/ + { {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, { {-1}, {-1} }, { {0x4b, -1}, {0xcb, -1} }, /*c8*/ + { {-1}, {-1} }, { {0x4d, -1}, {0xcd, -1} }, { {-1}, {-1} }, { {0x4f, -1}, {0xcf, -1} }, /*cc*/ + { {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} }, /*d0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*d4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*d8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*dc*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*ec*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*fc*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*100*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*104*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*108*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*10c*/ +}; + +/*Tandy keyboard has slightly different scancodes to XT*/ +static scancode scancode_tandy[272] = +{ + { {-1}, {-1} }, { {0x01, -1}, {0x81, -1} }, { {0x02, -1}, {0x82, -1} }, { {0x03, -1}, {0x83, -1} }, + { {0x04, -1}, {0x84, -1} }, { {0x05, -1}, {0x85, -1} }, { {0x06, -1}, {0x86, -1} }, { {0x07, -1}, {0x87, -1} }, + { {0x08, -1}, {0x88, -1} }, { {0x09, -1}, {0x89, -1} }, { {0x0a, -1}, {0x8a, -1} }, { {0x0b, -1}, {0x8b, -1} }, + { {0x0c, -1}, {0x8c, -1} }, { {0x0d, -1}, {0x8d, -1} }, { {0x0e, -1}, {0x8e, -1} }, { {0x0f, -1}, {0x8f, -1} }, + { {0x10, -1}, {0x90, -1} }, { {0x11, -1}, {0x91, -1} }, { {0x12, -1}, {0x92, -1} }, { {0x13, -1}, {0x93, -1} }, + { {0x14, -1}, {0x94, -1} }, { {0x15, -1}, {0x95, -1} }, { {0x16, -1}, {0x96, -1} }, { {0x17, -1}, {0x97, -1} }, + { {0x18, -1}, {0x98, -1} }, { {0x19, -1}, {0x99, -1} }, { {0x1a, -1}, {0x9a, -1} }, { {0x1b, -1}, {0x9b, -1} }, + { {0x1c, -1}, {0x9c, -1} }, { {0x1d, -1}, {0x9d, -1} }, { {0x1e, -1}, {0x9e, -1} }, { {0x1f, -1}, {0x9f, -1} }, + { {0x20, -1}, {0xa0, -1} }, { {0x21, -1}, {0xa1, -1} }, { {0x22, -1}, {0xa2, -1} }, { {0x23, -1}, {0xa3, -1} }, + { {0x24, -1}, {0xa4, -1} }, { {0x25, -1}, {0xa5, -1} }, { {0x26, -1}, {0xa6, -1} }, { {0x27, -1}, {0xa7, -1} }, + { {0x28, -1}, {0xa8, -1} }, { {0x29, -1}, {0xa9, -1} }, { {0x2a, -1}, {0xaa, -1} }, { {0x47, -1}, {0xc7, -1} }, + { {0x2c, -1}, {0xac, -1} }, { {0x2d, -1}, {0xad, -1} }, { {0x2e, -1}, {0xae, -1} }, { {0x2f, -1}, {0xaf, -1} }, + { {0x30, -1}, {0xb0, -1} }, { {0x31, -1}, {0xb1, -1} }, { {0x32, -1}, {0xb2, -1} }, { {0x33, -1}, {0xb3, -1} }, + { {0x34, -1}, {0xb4, -1} }, { {0x35, -1}, {0xb5, -1} }, { {0x36, -1}, {0xb6, -1} }, { {0x37, -1}, {0xb7, -1} }, + { {0x38, -1}, {0xb8, -1} }, { {0x39, -1}, {0xb9, -1} }, { {0x3a, -1}, {0xba, -1} }, { {0x3b, -1}, {0xbb, -1} }, + { {0x3c, -1}, {0xbc, -1} }, { {0x3d, -1}, {0xbd, -1} }, { {0x3e, -1}, {0xbe, -1} }, { {0x3f, -1}, {0xbf, -1} }, + { {0x40, -1}, {0xc0, -1} }, { {0x41, -1}, {0xc1, -1} }, { {0x42, -1}, {0xc2, -1} }, { {0x43, -1}, {0xc3, -1} }, + { {0x44, -1}, {0xc4, -1} }, { {0x45, -1}, {0xc5, -1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} }, + { {0x48, -1}, {0xc8, -1} }, { {0x49, -1}, {0xc9, -1} }, { {0x4a, -1}, {0xca, -1} }, { {0x4b, -1}, {0xcb, -1} }, + { {0x4c, -1}, {0xcc, -1} }, { {0x4d, -1}, {0xcd, -1} }, { {0x4e, -1}, {0xce, -1} }, { {0x4f, -1}, {0xcf, -1} }, + { {0x50, -1}, {0xd0, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x56, -1}, {0xd6, -1} }, + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*54*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*58*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*5c*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*60*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*64*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*68*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*6c*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*70*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*74*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*78*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*7c*/ + + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*80*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*84*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*88*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*8c*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*90*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*94*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*98*/ + { {0x57, -1}, {0xd7, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*9c*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*a4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {0xaa, -1}, {0x2a, -1} }, { {-1}, {-1} }, /*a8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*ac*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*b0*/ + { {-1}, {-1} }, { {0x35, -1}, {0xb5, -1} }, { {0xb6, -1}, {0x36, -1} }, { {0x37, -1}, {0xb7, -1} }, /*b4*/ + { {0x38, -1}, {0xb8, -1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*b8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*bc*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*c0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {0x46, -1}, {0xc6, -1} }, { {0x47, -1}, {0xc7, -1} }, /*c4*/ + { {0x29, -1}, {0xa9, -1} }, { {0x49, -1}, {0xc9, -1} }, { {-1}, {-1} }, { {0x2b, -1}, {0xab, -1} }, /*c8*/ + { {-1}, {-1} }, { {0x4e, -1}, {0xce, -1} }, { {-1}, {-1} }, { {0x4f, -1}, {0xcf, -1} }, /*cc*/ + { {0x4a, -1}, {0xca, -1} }, { {0x51, -1}, {0xd1, -1} }, { {0x52, -1}, {0xd2, -1} }, { {0x53, -1}, {0xd3, -1} }, /*d0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*d4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*d8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*dc*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*e8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*ec*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f0*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f4*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*f8*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*fc*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*100*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*104*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*108*/ + { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, { {-1}, {-1} }, /*10c*/ +}; +static int oldkey[272]; +static int keydelay[272]; + +/* This array acts an intermediary so scan codes are processed in the correct order (ALT-CTRL-SHIFT-RSHIFT first, then all others). */ +static int scorder[272] = {0x38, 0xB8, 0x1D, 0x9D, 0xFF, 0x2A, 0x36,0x103, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, + 0x29, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x37, 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, + 0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, + 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, + 0x7C, 0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, + 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, + 0x9C, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, + 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, + 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, + 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, + 0xDE, 0xDF, 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, + 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, + 0xFE,0x100,0x101,0x102,0x104,0x105,0x106,0x107,0x108,0x109,0x10A,0x10B,0x10C,0x10D,0x10E,0x10F}; + +/* bit 0 = repeat, bit 1 = makes break code? */ +int set3_flags[272]; +uint8_t set3_all_repeat = 0; +uint8_t set3_all_break = 0; + +void (*keyboard_send)(uint8_t val); +void (*keyboard_poll)(); +int keyboard_scan = 1; + +void keyboard_process() +{ + int c; + int d; + scancode *scancodes; + + if (AT) + { + switch (mode & 3) + { + case 1: + default: + scancodes = scancode_set1; + break; + case 2: + scancodes = scancode_set2; + break; + case 3: + scancodes = scancode_set3; + break; + } + if (mode & 0x20) scancodes = scancode_set1; + } + else + { + scancodes = scancode_xt; + } + + if (!keyboard_scan) return; + if (TANDY) scancodes = scancode_tandy; + + for (c = 0; c < 272; c++) + { + if (pcem_key[scorder[c]]) + keydelay[scorder[c]]++; + else + keydelay[scorder[c]] = 0; + } + + for (c = 0; c < 272; c++) + { + if (pcem_key[scorder[c]] != oldkey[scorder[c]]) + { + oldkey[scorder[c]] = pcem_key[scorder[c]]; + if ( pcem_key[scorder[c]] && scancodes[scorder[c]].scancodes_make[0] == -1) + continue; + if (!pcem_key[scorder[c]] && scancodes[scorder[c]].scancodes_break[0] == -1) + continue; + if (AT && ((mode & 3) == 3)) + { + if (!set3_all_break && !pcem_key[scorder[c]] && !(set3_flags[scancodes[scorder[c]].scancodes_make[0]] & 2)) + continue; + } +// pclog("Key %02X start\n", scorder[c]); + d = 0; + if (pcem_key[scorder[c]]) + { + while (scancodes[scorder[c]].scancodes_make[d] != -1) + keyboard_send(scancodes[scorder[c]].scancodes_make[d++]); + } + else + { + while (scancodes[scorder[c]].scancodes_break[d] != -1) + keyboard_send(scancodes[scorder[c]].scancodes_break[d++]); + } + } + } + + for (c = 0; c < 272; c++) + { + if (AT && ((mode & 3) == 3)) + { + if (scancodes[scorder[c]].scancodes_make[0] == -1) + continue; + if (!set3_all_repeat && !pcem_key[scorder[c]] && !(set3_flags[scancodes[scorder[c]].scancodes_make[0]] & 1)) + continue; + } + if (keydelay[scorder[c]] >= 30) + { + keydelay[scorder[c]] -= 10; + if (scancodes[scorder[c]].scancodes_make[0] == -1) + continue; + + d = 0; + + while (scancodes[scorder[c]].scancodes_make[d] != -1) + keyboard_send(scancodes[scorder[c]].scancodes_make[d++]); + } + } +} diff --git a/src/keyboard.h b/src/keyboard.h new file mode 100644 index 000000000..d1445b763 --- /dev/null +++ b/src/keyboard.h @@ -0,0 +1,11 @@ +extern void (*keyboard_send)(uint8_t val); +extern void (*keyboard_poll)(); +extern int keyboard_scan; + +extern int pcem_key[272]; +extern uint8_t mode; +void keyboard_process(); + +extern int set3_flags[272]; +extern uint8_t set3_all_repeat; +extern uint8_t set3_all_break; diff --git a/src/keyboard_amstrad.c b/src/keyboard_amstrad.c new file mode 100644 index 000000000..4c779ae9e --- /dev/null +++ b/src/keyboard_amstrad.c @@ -0,0 +1,178 @@ +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "pic.h" +#include "pit.h" +#include "sound.h" +#include "sound_speaker.h" +#include "timer.h" + +#include "keyboard.h" +#include "keyboard_amstrad.h" + +#define STAT_PARITY 0x80 +#define STAT_RTIMEOUT 0x40 +#define STAT_TTIMEOUT 0x20 +#define STAT_LOCK 0x10 +#define STAT_CD 0x08 +#define STAT_SYSFLAG 0x04 +#define STAT_IFULL 0x02 +#define STAT_OFULL 0x01 + +struct +{ + int wantirq; + + uint8_t key_waiting; + uint8_t pa; + uint8_t pb; +} keyboard_amstrad; + +static uint8_t key_queue[16]; +static int key_queue_start = 0, key_queue_end = 0; + +static uint8_t amstrad_systemstat_1, amstrad_systemstat_2; + +void keyboard_amstrad_poll() +{ + keybsenddelay += (1000 * TIMER_USEC); + if (keyboard_amstrad.wantirq) + { + keyboard_amstrad.wantirq = 0; + keyboard_amstrad.pa = keyboard_amstrad.key_waiting; + picint(2); + pclog("keyboard_amstrad : take IRQ\n"); + } + if (key_queue_start != key_queue_end && !keyboard_amstrad.pa) + { + keyboard_amstrad.key_waiting = key_queue[key_queue_start]; + pclog("Reading %02X from the key queue at %i\n", keyboard_amstrad.key_waiting, key_queue_start); + key_queue_start = (key_queue_start + 1) & 0xf; + keyboard_amstrad.wantirq = 1; + } +} + +void keyboard_amstrad_adddata(uint8_t val) +{ + key_queue[key_queue_end] = val; + pclog("keyboard_amstrad : %02X added to key queue at %i\n", val, key_queue_end); + key_queue_end = (key_queue_end + 1) & 0xf; + return; +} + +void keyboard_amstrad_write(uint16_t port, uint8_t val, void *priv) +{ + pclog("keyboard_amstrad : write %04X %02X %02X\n", port, val, keyboard_amstrad.pb); + + switch (port) + { + case 0x61: + pclog("keyboard_amstrad : pb write %02X %02X %i %02X %i\n", val, keyboard_amstrad.pb, !(keyboard_amstrad.pb & 0x40), keyboard_amstrad.pb & 0x40, (val & 0x40)); + if (!(keyboard_amstrad.pb & 0x40) && (val & 0x40)) /*Reset keyboard*/ + { + pclog("keyboard_amstrad : reset keyboard\n"); + keyboard_amstrad_adddata(0xaa); + } + keyboard_amstrad.pb = val; + ppi.pb = val; + + timer_process(); + timer_update_outstanding(); + + speaker_update(); + speaker_gated = val & 1; + speaker_enable = val & 2; + if (speaker_enable) + was_speaker_enable = 1; + pit_set_gate(2, val & 1); + + if (val & 0x80) + keyboard_amstrad.pa = 0; + break; + + case 0x63: + break; + + case 0x64: + amstrad_systemstat_1 = val; + break; + + case 0x65: + amstrad_systemstat_2 = val; + break; + + default: + pclog("\nBad XT keyboard write %04X %02X\n", port, val); +// dumpregs(); +// exit(-1); + } +} + +uint8_t keyboard_amstrad_read(uint16_t port, void *priv) +{ + uint8_t temp; +// pclog("keyboard_amstrad : read %04X ", port); + switch (port) + { + case 0x60: + if (keyboard_amstrad.pb & 0x80) + { + temp = (amstrad_systemstat_1 | 0xd) & 0x7f; + } + else + { + temp = keyboard_amstrad.pa; + if (key_queue_start == key_queue_end) + { + keyboard_amstrad.wantirq = 0; + } + else + { + keyboard_amstrad.key_waiting = key_queue[key_queue_start]; + key_queue_start = (key_queue_start + 1) & 0xf; + keyboard_amstrad.wantirq = 1; + } + } + break; + + case 0x61: + temp = keyboard_amstrad.pb; + break; + + case 0x62: + if (keyboard_amstrad.pb & 0x04) + temp = amstrad_systemstat_2 & 0xf; + else + temp = amstrad_systemstat_2 >> 4; + temp |= (ppispeakon ? 0x20 : 0); + if (nmi) + temp |= 0x40; + break; + + default: + pclog("\nBad XT keyboard read %04X\n", port); +// dumpregs(); +// exit(-1); + } +// pclog("%02X %04X:%04X\n", temp, CS, pc); + return temp; +} + +void keyboard_amstrad_reset() +{ + keyboard_amstrad.wantirq = 0; + + keyboard_scan = 1; +} + +void keyboard_amstrad_init() +{ + //return; + pclog("keyboard_amstrad_init\n"); + io_sethandler(0x0060, 0x0006, keyboard_amstrad_read, NULL, NULL, keyboard_amstrad_write, NULL, NULL, NULL); + keyboard_amstrad_reset(); + keyboard_send = keyboard_amstrad_adddata; + keyboard_poll = keyboard_amstrad_poll; + + timer_add(keyboard_amstrad_poll, &keybsenddelay, TIMER_ALWAYS_ENABLED, NULL); +} diff --git a/src/keyboard_amstrad.h b/src/keyboard_amstrad.h new file mode 100644 index 000000000..9d4cd15f5 --- /dev/null +++ b/src/keyboard_amstrad.h @@ -0,0 +1,3 @@ +void keyboard_amstrad_init(); +void keyboard_amstrad_reset(); +void keyboard_amstrad_poll(); diff --git a/src/keyboard_at.c b/src/keyboard_at.c new file mode 100644 index 000000000..6fd843ce4 --- /dev/null +++ b/src/keyboard_at.c @@ -0,0 +1,648 @@ +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "pic.h" +#include "pit.h" +#include "sound.h" +#include "sound_speaker.h" +#include "timer.h" + +#include "keyboard.h" +#include "keyboard_at.h" + +#define STAT_PARITY 0x80 +#define STAT_RTIMEOUT 0x40 +#define STAT_TTIMEOUT 0x20 +#define STAT_MFULL 0x20 +#define STAT_LOCK 0x10 +#define STAT_CD 0x08 +#define STAT_SYSFLAG 0x04 +#define STAT_IFULL 0x02 +#define STAT_OFULL 0x01 + +struct +{ + int initialised; + int want60; + int wantirq, wantirq12; + uint8_t command; + uint8_t status; + uint8_t mem[0x20]; + uint8_t out; + int out_new; + + uint8_t input_port; + uint8_t output_port; + + uint8_t key_command; + int key_wantdata; + + int last_irq; +} keyboard_at; + +static uint8_t key_ctrl_queue[16]; +static int key_ctrl_queue_start = 0, key_ctrl_queue_end = 0; + +static uint8_t key_queue[16]; +static int key_queue_start = 0, key_queue_end = 0; + +static uint8_t mouse_queue[16]; +int mouse_queue_start = 0, mouse_queue_end = 0; + +int first_write = 1; +int dtrans = 0; + +/* Bits 0 - 1 = scan code set, bit 6 = translate or not. */ +uint8_t mode = 0x42; + +#if 0 +/* Translated to non-translated scan codes. */ + /* Assuming we get XSET1, SET1/XSET2/XSET3 = T_TO_NONT(XSET1), and then we go through + T_TO_NONT again to get SET2/SET3. */ +/* static uint8_t t_to_nont[256] = { 0xFF, 0x76, 0x16, 0x1E, 0x26, 0x25, 0x2E, 0x36, 0x3D, 0x3E, 0x46, 0x45, 0x4E, 0x55, 0x66, 0x0D, + 0x15, 0x1D, 0x24, 0x2D, 0x2C, 0x35, 0x3C, 0x43, 0x44, 0x4D, 0x54, 0x5B, 0x5A, 0x14, 0x1C, 0x1B, + 0x23, 0x2B, 0x34, 0x33, 0x3B, 0x42, 0x4B, 0x4C, 0x52, 0x0E, 0x12, 0x5D, 0x1A, 0x22, 0x21, 0x2A, + 0x32, 0x31, 0x3A, 0x41, 0x49, 0x4A, 0x59, 0x7C, 0x11, 0x29, 0x58, 0x05, 0x06, 0x04, 0x0C, 0x03, + 0x0B, 0x02, 0x0A, 0x01, 0x09, 0x77, 0x7E, 0x6C, 0x75, 0x7D, 0x7B, 0x6B, 0x73, 0x74, 0x79, 0x69, + 0x72, 0x7A, 0x70, 0x71, 0x7F, 0x60, 0x61, 0x78, 0x07, 0x0F, 0x17, 0x1F, 0x27, 0x2F, 0x37, 0x3F, + 0x47, 0x4F, 0x56, 0x5E, 0x08, 0x10, 0x18, 0x20, 0x28, 0x30, 0x38, 0x40, 0x48, 0x50, 0x57, 0x6F, + 0x13, 0x19, 0x39, 0x51, 0x53, 0x5C, 0x5F, 0x62, 0x63, 0x64, 0x65, 0x67, 0x68, 0x6A, 0x6D, 0x6E, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF }; */ +#endif + +/* Non-translated to translated scan codes. */ +static uint8_t nont_to_t[256] = { 0xFF, 0x43, 0x41, 0x3F, 0x3D, 0x3B, 0x3C, 0x58, 0x64, 0x44, 0x42, 0x40, 0x3E, 0x0F, 0x29, 0x59, + 0x65, 0x38, 0x2A, 0x70, 0x1D, 0x10, 0x02, 0x5A, 0x66, 0x71, 0x2C, 0x1F, 0x1E, 0x11, 0x03, 0x5B, + 0x67, 0x2E, 0x2D, 0x20, 0x12, 0x05, 0x04, 0x5C, 0x68, 0x39, 0x2F, 0x21, 0x14, 0x13, 0x06, 0x5D, + 0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5E, 0x6A, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5F, + 0x6B, 0x33, 0x25, 0x17, 0x18, 0x0B, 0x0A, 0x60, 0x6C, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0C, 0x61, + 0x6D, 0x73, 0x28, 0x74, 0x1A, 0x0D, 0x62, 0x6E, 0x3A, 0x36, 0x1C, 0x1B, 0x75, 0x2B, 0x63, 0x76, + 0x55, 0x56, 0x77, 0x78, 0x79, 0x7A, 0x0E, 0x7B, 0x7C, 0x4F, 0x7D, 0x4B, 0x47, 0x7E, 0x7F, 0x6F, + 0x52, 0x53, 0x50, 0x4C, 0x4D, 0x48, 0x01, 0x45, 0x57, 0x4E, 0x51, 0x4A, 0x37, 0x49, 0x46, 0x54, + 0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, + 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, + 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, + 0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF }; + +void keyboard_at_poll() +{ + keybsenddelay += (1000 * TIMER_USEC); + + if (keyboard_at.out_new != -1 && !keyboard_at.last_irq) + { + keyboard_at.wantirq = 0; + if (keyboard_at.out_new & 0x100) + { + if (keyboard_at.mem[0] & 0x02) + picint(0x1000); + keyboard_at.out = keyboard_at.out_new & 0xff; + keyboard_at.out_new = -1; + keyboard_at.status |= STAT_OFULL; + keyboard_at.status &= ~STAT_IFULL; + keyboard_at.status |= STAT_MFULL; +// pclog("keyboard_at : take IRQ12\n"); + keyboard_at.last_irq = 0x1000; + } + else + { + if (keyboard_at.mem[0] & 0x01) + picint(2); + keyboard_at.out = keyboard_at.out_new; + keyboard_at.out_new = -1; + keyboard_at.status |= STAT_OFULL; + keyboard_at.status &= ~STAT_IFULL; + keyboard_at.status &= ~STAT_MFULL; +// pclog("keyboard_at : take IRQ1\n"); + keyboard_at.last_irq = 2; + } + } + + if (!(keyboard_at.status & STAT_OFULL) && keyboard_at.out_new == -1 && /*!(keyboard_at.mem[0] & 0x20) &&*/ + mouse_queue_start != mouse_queue_end) + { + keyboard_at.out_new = mouse_queue[mouse_queue_start] | 0x100; + mouse_queue_start = (mouse_queue_start + 1) & 0xf; + } + else if (!(keyboard_at.status & STAT_OFULL) && keyboard_at.out_new == -1 && + !(keyboard_at.mem[0] & 0x10) && key_queue_start != key_queue_end) + { + keyboard_at.out_new = key_queue[key_queue_start]; + key_queue_start = (key_queue_start + 1) & 0xf; + } + else if (keyboard_at.out_new == -1 && !(keyboard_at.status & STAT_OFULL) && + key_ctrl_queue_start != key_ctrl_queue_end) + { + keyboard_at.out_new = key_ctrl_queue[key_ctrl_queue_start]; + key_ctrl_queue_start = (key_ctrl_queue_start + 1) & 0xf; + } +} + +void keyboard_at_adddata(uint8_t val) +{ +// if (keyboard_at.status & STAT_OFULL) +// { + key_ctrl_queue[key_ctrl_queue_end] = val; + key_ctrl_queue_end = (key_ctrl_queue_end + 1) & 0xf; +// pclog("keyboard_at : %02X added to queue\n", val); +/* return; + } + keyboard_at.out = val; + keyboard_at.status |= STAT_OFULL; + keyboard_at.status &= ~STAT_IFULL; + if (keyboard_at.mem[0] & 0x01) + keyboard_at.wantirq = 1; + pclog("keyboard_at : output %02X (IRQ %i)\n", val, keyboard_at.wantirq);*/ +} + +uint8_t sc_or = 0; + +void keyboard_at_adddata_keyboard(uint8_t val) +{ + /* Modification by OBattler: Allow for scan code translation. */ + if ((mode & 0x40) && (val == 0xf0) && !(mode & 0x20)) + { + sc_or = 0x80; + return; + } + /* Skip break code if translated make code has bit 7 set. */ + if ((mode & 0x40) && (sc_or == 0x80) && (nont_to_t[val] & 0x80) && !(mode & 0x20)) + { + sc_or = 0; + return; + } + key_queue[key_queue_end] = (((mode & 0x40) && !(mode & 0x20)) ? (nont_to_t[val] | sc_or) : val); + key_queue_end = (key_queue_end + 1) & 0xf; + if (sc_or == 0x80) sc_or = 0; + return; +} + +void keyboard_at_adddata_keyboard_raw(uint8_t val) +{ + key_queue[key_queue_end] = val; + key_queue_end = (key_queue_end + 1) & 0xf; + return; +} + +void keyboard_at_adddata_mouse(uint8_t val) +{ + mouse_queue[mouse_queue_end] = val; + mouse_queue_end = (mouse_queue_end + 1) & 0xf; +// pclog("keyboard_at : %02X added to mouse queue\n", val); + return; +} + +void keyboard_at_write(uint16_t port, uint8_t val, void *priv) +{ +// pclog("keyboard_at : write %04X %02X %i %02X\n", port, val, keyboard_at.key_wantdata, ram[8]); +/* if (ram[8] == 0xc3) + { + output = 3; + }*/ + switch (port) + { + case 0x60: + if (keyboard_at.want60) + { + /*Write to controller*/ + keyboard_at.want60 = 0; + switch (keyboard_at.command) + { + case 0x40 ... 0x5f: /* 0x40 - 0x5F are aliases for 0x60-0x7F */ + keyboard_at.command |= 0x20; + case 0x60: case 0x61: case 0x62: case 0x63: + case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + case 0x70: case 0x71: case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: + case 0x7c: case 0x7d: case 0x7e: case 0x7f: + keyboard_at.mem[keyboard_at.command & 0x1f] = val; + if (keyboard_at.command == 0x60) + { + if ((val & 1) && (keyboard_at.status & STAT_OFULL)) + keyboard_at.wantirq = 1; + if (!(val & 1) && keyboard_at.wantirq) + keyboard_at.wantirq = 0; + mouse_scan = !(val & 0x20); + + /* Addition by OBattler: Scan code translate ON/OFF. */ + // pclog("KEYBOARD_AT: Writing %02X to system register\n", val); + mode &= 0x93; + mode |= (val & 0x6C); + if (first_write) + { + /* A bit of a hack, but it will make the keyboard behave correctly, regardless + of what the BIOS sets here. */ + mode &= 0xFC; + dtrans = mode & 0x60; + if ((mode & 0x60) == 0x40) + { + /* Bit 6 on, bit 5 off, the only case in which translation is on, + therefore, set to set 2. */ + mode |= 2; + } + first_write = 0; + // pclog("Keyboard set to scan code set %i, mode & 0x60 = 0x%02X\n", mode & 3, mode & 0x60); + /* No else because in all other cases, translation is off, so we need to keep it + set to set 0 which the mode &= 0xFC above will set it. */ + } + } + break; + + case 0xcb: /*AMI - set keyboard mode*/ + break; + + case 0xcf: /*??? - sent by MegaPC BIOS*/ + /* To make sure the keyboard works correctly on the MegaPC. */ + mode &= 0xFC; + mode |= 2; + break; + + case 0xd1: /*Write output port*/ +// pclog("Write output port - %02X %02X %04X:%04X\n", keyboard_at.output_port, val, CS, pc); + if ((keyboard_at.output_port ^ val) & 0x02) /*A20 enable change*/ + { + mem_a20_key = val & 0x02; + mem_a20_recalc(); +// pclog("Rammask change to %08X %02X\n", rammask, val & 0x02); + flushmmucache(); + } + keyboard_at.output_port = val; + break; + + case 0xd3: /*Write to mouse output buffer*/ + keyboard_at_adddata_mouse(val); + break; + + case 0xd4: /*Write to mouse*/ + if (mouse_write) + mouse_write(val); + break; + + default: + pclog("Bad AT keyboard controller 0060 write %02X command %02X\n", val, keyboard_at.command); +// dumpregs(); +// exit(-1); + } + } + else + { + /*Write to keyboard*/ + keyboard_at.mem[0] &= ~0x10; + if (keyboard_at.key_wantdata) + { + keyboard_at.key_wantdata = 0; + switch (keyboard_at.key_command) + { + case 0xed: /*Set/reset LEDs*/ + keyboard_at_adddata_keyboard(0xfa); + break; + + case 0xf0: /*Get/set scancode set*/ + // pclog("KEYBOARD_AT: Get/set scan code set: %i\n", val); + if (val == 0) + { + keyboard_at_adddata_keyboard(mode & 3); + } + else + { + if (val <= 3) + { + mode &= 0xFC; + mode |= (val & 3); + } + keyboard_at_adddata_keyboard(0xfa); + } + break; + + case 0xf3: /*Set typematic rate/delay*/ + keyboard_at_adddata_keyboard(0xfa); + break; + + default: + pclog("Bad AT keyboard 0060 write %02X command %02X\n", val, keyboard_at.key_command); +// dumpregs(); +// exit(-1); + } + } + else + { + keyboard_at.key_command = val; + switch (val) + { + case 0x00: + keyboard_at_adddata_keyboard(0xfa); + break; + + case 0x05: /*??? - sent by NT 4.0*/ + keyboard_at_adddata_keyboard(0xfe); + break; + + case 0xed: /*Set/reset LEDs*/ + keyboard_at.key_wantdata = 1; + keyboard_at_adddata_keyboard(0xfa); + break; + + case 0xf0: /*Get/set scan code set*/ + keyboard_at.key_wantdata = 1; + keyboard_at_adddata_keyboard(0xfa); + break; + + case 0xf2: /*Read ID*/ + /* Fixed as translation will be done in keyboard_at_adddata_keyboard(). */ + keyboard_at_adddata_keyboard(0xfa); + keyboard_at_adddata_keyboard(0xab); + keyboard_at_adddata_keyboard(0x83); + break; + + case 0xf3: /*Set typematic rate/delay*/ + keyboard_at.key_wantdata = 1; + keyboard_at_adddata_keyboard(0xfa); + break; + + case 0xf4: /*Enable keyboard*/ + keyboard_scan = 1; + keyboard_at_adddata_keyboard(0xfa); + break; + case 0xf5: /*Disable keyboard*/ + keyboard_scan = 0; + keyboard_at_adddata_keyboard(0xfa); + break; + + case 0xf6: /*Set defaults*/ + // pclog("KEYBOARD_AT: Set defaults\n"); + set3_all_break = 0; + set3_all_repeat = 0; + memset(set3_flags, 0, 272); + mode = (mode & 0xFC) | 2; + keyboard_at_adddata_keyboard(0xfa); + break; + + case 0xf7: /*Set all keys to repeat*/ + set3_all_break = 1; + keyboard_at_adddata_keyboard(0xfa); + break; + + case 0xf8: /*Set all keys to give make/break codes*/ + set3_all_break = 1; + keyboard_at_adddata_keyboard(0xfa); + break; + + case 0xf9: /*Set all keys to give make codes only*/ + set3_all_break = 0; + keyboard_at_adddata_keyboard(0xfa); + break; + + case 0xfa: /*Set all keys to repeat and give make/break codes*/ + set3_all_repeat = 1; + set3_all_break = 1; + keyboard_at_adddata_keyboard(0xfa); + break; + + case 0xff: /*Reset*/ + // pclog("KEYBOARD_AT: Set defaults\n"); + key_queue_start = key_queue_end = 0; /*Clear key queue*/ + keyboard_at_adddata_keyboard(0xfa); + keyboard_at_adddata_keyboard(0xaa); + /* Set system flag to 1 and scan code set to 2. */ + mode &= 0xFC; + mode |= 2; + break; + + default: + pclog("Bad AT keyboard command %02X\n", val); + keyboard_at_adddata_keyboard(0xfe); +// dumpregs(); +// exit(-1); + } + } + } + break; + + case 0x61: + ppi.pb = val; + + timer_process(); + timer_update_outstanding(); + + speaker_update(); + speaker_gated = val & 1; + speaker_enable = val & 2; + if (speaker_enable) + was_speaker_enable = 1; + pit_set_gate(2, val & 1); + break; + + case 0x64: + keyboard_at.want60 = 0; + keyboard_at.command = val; + /*New controller command*/ + switch (val) + { + case 0x00 ... 0x1f: + val |= 0x20; /* 0x00-0x1f are aliases for 0x20-0x3f */ + + case 0x20: case 0x21: case 0x22: case 0x23: + case 0x24: case 0x25: case 0x26: case 0x27: + case 0x28: case 0x29: case 0x2a: case 0x2b: + case 0x2c: case 0x2d: case 0x2e: case 0x2f: + case 0x30: case 0x31: case 0x32: case 0x33: + case 0x34: case 0x35: case 0x36: case 0x37: + case 0x38: case 0x39: case 0x3a: case 0x3b: + case 0x3c: case 0x3d: case 0x3e: case 0x3f: + keyboard_at_adddata(keyboard_at.mem[val & 0x1f]); + break; + + case 0x60: case 0x61: case 0x62: case 0x63: + case 0x64: case 0x65: case 0x66: case 0x67: + case 0x68: case 0x69: case 0x6a: case 0x6b: + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + case 0x70: case 0x71: case 0x72: case 0x73: + case 0x74: case 0x75: case 0x76: case 0x77: + case 0x78: case 0x79: case 0x7a: case 0x7b: + case 0x7c: case 0x7d: case 0x7e: case 0x7f: + keyboard_at.want60 = 1; + break; + + case 0xa1: /*AMI - get controlled version*/ + break; + + case 0xa7: /*Disable mouse port*/ + mouse_scan = 0; + break; + + case 0xa8: /*Enable mouse port*/ + mouse_scan = 1; + break; + + case 0xa9: /*Test mouse port*/ + keyboard_at_adddata(0x00); /*no error*/ + break; + + case 0xaa: /*Self-test*/ + if (!keyboard_at.initialised) + { + keyboard_at.initialised = 1; + key_ctrl_queue_start = key_ctrl_queue_end = 0; + keyboard_at.status &= ~STAT_OFULL; + } + keyboard_at.status |= STAT_SYSFLAG; + keyboard_at.mem[0] |= 0x04; + keyboard_at_adddata(0x55); + /*Self-test also resets the output port, enabling A20*/ + if (!(keyboard_at.output_port & 0x02)) + { + mem_a20_key = 2; + mem_a20_recalc(); +// pclog("Rammask change to %08X %02X\n", rammask, val & 0x02); + flushmmucache(); + } + keyboard_at.output_port = 0xcf; + break; + + case 0xab: /*Interface test*/ + keyboard_at_adddata(0x00); /*no error*/ + break; + + case 0xad: /*Disable keyboard*/ + keyboard_at.mem[0] |= 0x10; + break; + + case 0xae: /*Enable keyboard*/ + keyboard_at.mem[0] &= ~0x10; + break; + + case 0xc0: /*Read input port*/ + keyboard_at_adddata(keyboard_at.input_port | 4); + keyboard_at.input_port = ((keyboard_at.input_port + 1) & 3) | (keyboard_at.input_port & 0xfc); + break; + + case 0xc9: /*AMI - block P22 and P23 ??? */ + break; + + case 0xca: /*AMI - read keyboard mode*/ + keyboard_at_adddata(0x00); /*ISA mode*/ + break; + + case 0xcb: /*AMI - set keyboard mode*/ + keyboard_at.want60 = 1; + break; + + case 0xcf: /*??? - sent by MegaPC BIOS*/ + keyboard_at.want60 = 1; + break; + + case 0xd0: /*Read output port*/ + keyboard_at_adddata(keyboard_at.output_port); + break; + + case 0xd1: /*Write output port*/ + keyboard_at.want60 = 1; + break; + + case 0xd3: /*Write mouse output buffer*/ + keyboard_at.want60 = 1; + break; + + case 0xd4: /*Write to mouse*/ + keyboard_at.want60 = 1; + break; + + case 0xe0: /*Read test inputs*/ + keyboard_at_adddata(0x00); + break; + + case 0xef: /*??? - sent by AMI486*/ + break; + + case 0xfe: /*Pulse output port - pin 0 selected - x86 reset*/ + softresetx86(); /*Pulse reset!*/ + break; + + case 0xff: /*Pulse output port - but no pins selected - sent by MegaPC BIOS*/ + break; + + default: + pclog("Bad AT keyboard controller command %02X\n", val); +// dumpregs(); +// exit(-1); + } + } +} + +uint8_t keyboard_at_read(uint16_t port, void *priv) +{ + uint8_t temp = 0xff; + cycles -= 4; +// if (port != 0x61) pclog("keyboard_at : read %04X ", port); + switch (port) + { + case 0x60: + temp = keyboard_at.out; + keyboard_at.status &= ~(STAT_OFULL/* | STAT_MFULL*/); + picintc(keyboard_at.last_irq); + keyboard_at.last_irq = 0; + break; + + case 0x61: + if (ppispeakon) return (ppi.pb&~0xC0)|0x20; + return ppi.pb&~0xe0; + + case 0x64: + temp = keyboard_at.status; + temp &= 0xEB; + temp |= (mode & 4); + if (mode & 8) temp |= STAT_LOCK; + keyboard_at.status &= ~(STAT_RTIMEOUT/* | STAT_TTIMEOUT*/); + break; + } +// if (port != 0x61) pclog("%02X %08X\n", temp, rammask); + return temp; +} + +void keyboard_at_reset() +{ + keyboard_at.initialised = 0; + keyboard_at.status = STAT_LOCK | STAT_CD; + keyboard_at.mem[0] = 0x11; + mode = 0x02 | dtrans; + first_write = 1; + keyboard_at.wantirq = 0; + keyboard_at.output_port = 0xcf; + keyboard_at.input_port = 0xb0; + keyboard_at.out_new = -1; + keyboard_at.last_irq = 0; + + keyboard_at.key_wantdata = 0; + + keyboard_scan = 1; + + sc_or = 0; + + memset(set3_flags, 0, 272); +} + +void keyboard_at_init() +{ + //return; + io_sethandler(0x0060, 0x0005, keyboard_at_read, NULL, NULL, keyboard_at_write, NULL, NULL, NULL); + keyboard_at_reset(); + keyboard_send = keyboard_at_adddata_keyboard; + keyboard_poll = keyboard_at_poll; + mouse_write = NULL; + dtrans = 0; + + timer_add(keyboard_at_poll, &keybsenddelay, TIMER_ALWAYS_ENABLED, NULL); +} diff --git a/src/keyboard_at.h b/src/keyboard_at.h new file mode 100644 index 000000000..2493e8187 --- /dev/null +++ b/src/keyboard_at.h @@ -0,0 +1,8 @@ +void keyboard_at_init(); +void keyboard_at_reset(); +void keyboard_at_poll(); +void keyboard_at_adddata_keyboard_raw(uint8_t val); + +void (*mouse_write)(uint8_t val); +extern int mouse_queue_start, mouse_queue_end; +extern int mouse_scan; diff --git a/src/keyboard_olim24.c b/src/keyboard_olim24.c new file mode 100644 index 000000000..f20a63912 --- /dev/null +++ b/src/keyboard_olim24.c @@ -0,0 +1,309 @@ +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "mouse.h" +#include "pic.h" +#include "sound.h" +#include "sound_speaker.h" +#include "timer.h" + +#include "keyboard.h" +#include "keyboard_olim24.h" + +#define STAT_PARITY 0x80 +#define STAT_RTIMEOUT 0x40 +#define STAT_TTIMEOUT 0x20 +#define STAT_LOCK 0x10 +#define STAT_CD 0x08 +#define STAT_SYSFLAG 0x04 +#define STAT_IFULL 0x02 +#define STAT_OFULL 0x01 + +struct +{ + int wantirq; + uint8_t command; + uint8_t status; + uint8_t out; + + uint8_t output_port; + + int param, param_total; + uint8_t params[16]; + + int mouse_mode; +} keyboard_olim24; + +static uint8_t key_queue[16]; +static int key_queue_start = 0, key_queue_end = 0; + +static uint8_t mouse_scancodes[7]; + +void keyboard_olim24_poll() +{ + keybsenddelay += (1000 * TIMER_USEC); + //pclog("poll %i\n", keyboard_olim24.wantirq); + if (keyboard_olim24.wantirq) + { + keyboard_olim24.wantirq = 0; + picint(2); + pclog("keyboard_olim24 : take IRQ\n"); + } + if (!(keyboard_olim24.status & STAT_OFULL) && key_queue_start != key_queue_end) + { + pclog("Reading %02X from the key queue at %i\n", keyboard_olim24.out, key_queue_start); + keyboard_olim24.out = key_queue[key_queue_start]; + key_queue_start = (key_queue_start + 1) & 0xf; + keyboard_olim24.status |= STAT_OFULL; + keyboard_olim24.status &= ~STAT_IFULL; + keyboard_olim24.wantirq = 1; + } +} + +void keyboard_olim24_adddata(uint8_t val) +{ + key_queue[key_queue_end] = val; + key_queue_end = (key_queue_end + 1) & 0xf; + pclog("keyboard_olim24 : %02X added to key queue %02X\n", val, keyboard_olim24.status); + return; +} + +void keyboard_olim24_write(uint16_t port, uint8_t val, void *priv) +{ + pclog("keyboard_olim24 : write %04X %02X\n", port, val); +/* if (ram[8] == 0xc3) + { + output = 3; + }*/ + switch (port) + { + case 0x60: + if (keyboard_olim24.param != keyboard_olim24.param_total) + { + keyboard_olim24.params[keyboard_olim24.param++] = val; + if (keyboard_olim24.param == keyboard_olim24.param_total) + { + switch (keyboard_olim24.command) + { + case 0x11: + keyboard_olim24.mouse_mode = 0; + mouse_scancodes[0] = keyboard_olim24.params[0]; + mouse_scancodes[1] = keyboard_olim24.params[1]; + mouse_scancodes[2] = keyboard_olim24.params[2]; + mouse_scancodes[3] = keyboard_olim24.params[3]; + mouse_scancodes[4] = keyboard_olim24.params[4]; + mouse_scancodes[5] = keyboard_olim24.params[5]; + mouse_scancodes[6] = keyboard_olim24.params[6]; + break; + + case 0x12: + keyboard_olim24.mouse_mode = 1; + mouse_scancodes[0] = keyboard_olim24.params[0]; + mouse_scancodes[1] = keyboard_olim24.params[1]; + mouse_scancodes[2] = keyboard_olim24.params[2]; + break; + + default: + pclog("Bad keyboard command complete %02X\n", keyboard_olim24.command); +// dumpregs(); +// exit(-1); + } + } + } + else + { + keyboard_olim24.command = val; + switch (val) + { + case 0x01: /*Self-test*/ + break; + + case 0x05: /*Read ID*/ + keyboard_olim24_adddata(0x00); + break; + + case 0x11: + keyboard_olim24.param = 0; + keyboard_olim24.param_total = 9; + break; + + case 0x12: + keyboard_olim24.param = 0; + keyboard_olim24.param_total = 4; + break; + + default: + pclog("Bad keyboard command %02X\n", val); +// dumpregs(); +// exit(-1); + } + } + + break; + + case 0x61: + ppi.pb = val; + + timer_process(); + timer_update_outstanding(); + + speaker_update(); + speaker_gated = val & 1; + speaker_enable = val & 2; + if (speaker_enable) + was_speaker_enable = 1; + pit_set_gate(2, val & 1); + break; + } +} + +uint8_t keyboard_olim24_read(uint16_t port, void *priv) +{ + uint8_t temp; +// pclog("keyboard_olim24 : read %04X ", port); + switch (port) + { + case 0x60: + temp = keyboard_olim24.out; + if (key_queue_start == key_queue_end) + { + keyboard_olim24.status &= ~STAT_OFULL; + keyboard_olim24.wantirq = 0; + } + else + { + keyboard_olim24.out = key_queue[key_queue_start]; + key_queue_start = (key_queue_start + 1) & 0xf; + keyboard_olim24.status |= STAT_OFULL; + keyboard_olim24.status &= ~STAT_IFULL; + keyboard_olim24.wantirq = 1; + } + break; + + case 0x61: + return ppi.pb; + + case 0x64: + temp = keyboard_olim24.status; + keyboard_olim24.status &= ~(STAT_RTIMEOUT | STAT_TTIMEOUT); + break; + + default: + pclog("\nBad olim24 keyboard read %04X\n", port); +// dumpregs(); +// exit(-1); + } +// pclog("%02X\n", temp); + return temp; +} + +void keyboard_olim24_reset() +{ + keyboard_olim24.status = STAT_LOCK | STAT_CD; + keyboard_olim24.wantirq = 0; + + keyboard_scan = 1; + + keyboard_olim24.param = keyboard_olim24.param_total = 0; + + keyboard_olim24.mouse_mode = 0; + mouse_scancodes[0] = 0x1c; + mouse_scancodes[1] = 0x53; + mouse_scancodes[2] = 0x01; + mouse_scancodes[3] = 0x4b; + mouse_scancodes[4] = 0x4d; + mouse_scancodes[5] = 0x48; + mouse_scancodes[6] = 0x50; +} + +static int mouse_x = 0, mouse_y = 0, mouse_b = 0; +void mouse_olim24_poll(int x, int y, int b) +{ + mouse_x += x; + mouse_y += y; + + pclog("mouse_poll - %i, %i %i, %i\n", x, y, mouse_x, mouse_y); + + if (((key_queue_end - key_queue_start) & 0xf) > 14) return; + if ((b & 1) && !(mouse_b & 1)) + keyboard_olim24_adddata(mouse_scancodes[0]); + if (!(b & 1) && (mouse_b & 1)) + keyboard_olim24_adddata(mouse_scancodes[0] | 0x80); + mouse_b = (mouse_b & ~1) | (b & 1); + + if (((key_queue_end - key_queue_start) & 0xf) > 14) return; + if ((b & 2) && !(mouse_b & 2)) + keyboard_olim24_adddata(mouse_scancodes[2]); + if (!(b & 2) && (mouse_b & 2)) + keyboard_olim24_adddata(mouse_scancodes[2] | 0x80); + mouse_b = (mouse_b & ~2) | (b & 2); + + if (((key_queue_end - key_queue_start) & 0xf) > 14) return; + if ((b & 4) && !(mouse_b & 4)) + keyboard_olim24_adddata(mouse_scancodes[1]); + if (!(b & 4) && (mouse_b & 4)) + keyboard_olim24_adddata(mouse_scancodes[1] | 0x80); + mouse_b = (mouse_b & ~4) | (b & 4); + + if (keyboard_olim24.mouse_mode) + { + if (((key_queue_end - key_queue_start) & 0xf) > 12) return; + if (!mouse_x && !mouse_y) return; + + mouse_y = -mouse_y; + + if (mouse_x < -127) mouse_x = -127; + if (mouse_x > 127) mouse_x = 127; + if (mouse_x < -127) mouse_x = 0x80 | ((-mouse_x) & 0x7f); + + if (mouse_y < -127) mouse_y = -127; + if (mouse_y > 127) mouse_y = 127; + if (mouse_y < -127) mouse_y = 0x80 | ((-mouse_y) & 0x7f); + + keyboard_olim24_adddata(0xfe); + keyboard_olim24_adddata(mouse_x); + keyboard_olim24_adddata(mouse_y); + + mouse_x = mouse_y = 0; + } + else + { + while (mouse_x < -4) + { + if (((key_queue_end - key_queue_start) & 0xf) > 14) return; + mouse_x+=4; + keyboard_olim24_adddata(mouse_scancodes[3]); + } + while (mouse_x > 4) + { + if (((key_queue_end - key_queue_start) & 0xf) > 14) return; + mouse_x-=4; + keyboard_olim24_adddata(mouse_scancodes[4]); + } + while (mouse_y < -4) + { + if (((key_queue_end - key_queue_start) & 0xf) > 14) return; + mouse_y+=4; + keyboard_olim24_adddata(mouse_scancodes[5]); + } + while (mouse_y > 4) + { + if (((key_queue_end - key_queue_start) & 0xf) > 14) return; + mouse_y-=4; + keyboard_olim24_adddata(mouse_scancodes[6]); + } + } +} + +void keyboard_olim24_init() +{ + //return; + io_sethandler(0x0060, 0x0002, keyboard_olim24_read, NULL, NULL, keyboard_olim24_write, NULL, NULL, NULL); + io_sethandler(0x0064, 0x0001, keyboard_olim24_read, NULL, NULL, keyboard_olim24_write, NULL, NULL, NULL); + keyboard_olim24_reset(); + keyboard_send = keyboard_olim24_adddata; + keyboard_poll = keyboard_olim24_poll; + mouse_poll = mouse_olim24_poll; + + timer_add(keyboard_olim24_poll, &keybsenddelay, TIMER_ALWAYS_ENABLED, NULL); +} diff --git a/src/keyboard_olim24.h b/src/keyboard_olim24.h new file mode 100644 index 000000000..305a3e245 --- /dev/null +++ b/src/keyboard_olim24.h @@ -0,0 +1,3 @@ +void keyboard_olim24_init(); +void keyboard_olim24_reset(); +void keyboard_olim24_poll(); diff --git a/src/keyboard_pcjr.c b/src/keyboard_pcjr.c new file mode 100644 index 000000000..b041a5b06 --- /dev/null +++ b/src/keyboard_pcjr.c @@ -0,0 +1,208 @@ +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "nmi.h" +#include "pic.h" +#include "sound.h" +#include "sound_sn76489.h" +#include "sound_speaker.h" +#include "timer.h" + +#include "keyboard.h" +#include "keyboard_pcjr.h" + +#define STAT_PARITY 0x80 +#define STAT_RTIMEOUT 0x40 +#define STAT_TTIMEOUT 0x20 +#define STAT_LOCK 0x10 +#define STAT_CD 0x08 +#define STAT_SYSFLAG 0x04 +#define STAT_IFULL 0x02 +#define STAT_OFULL 0x01 + +struct +{ + int latched; + int data; + + int serial_data[44]; + int serial_pos; + + uint8_t pa; + uint8_t pb; +} keyboard_pcjr; + +static uint8_t key_queue[16]; +static int key_queue_start = 0, key_queue_end = 0; + +void keyboard_pcjr_poll() +{ + keybsenddelay += (220 * TIMER_USEC); + + + if (key_queue_start != key_queue_end && !keyboard_pcjr.serial_pos && !keyboard_pcjr.latched) + { + int c; + int p = 0; + uint8_t key = key_queue[key_queue_start]; + +// pclog("Reading %02X from the key queue at %i\n", key, key_queue_start); + key_queue_start = (key_queue_start + 1) & 0xf; + + keyboard_pcjr.latched = 1; + + keyboard_pcjr.serial_data[0] = 1; /*Start bit*/ + keyboard_pcjr.serial_data[1] = 0; + + for (c = 0; c < 8; c++) + { + if (key & (1 << c)) + { + keyboard_pcjr.serial_data[(c + 1) * 2] = 1; + keyboard_pcjr.serial_data[(c + 1) * 2 + 1] = 0; + p++; + } + else + { + keyboard_pcjr.serial_data[(c + 1) * 2] = 0; + keyboard_pcjr.serial_data[(c + 1) * 2 + 1] = 1; + } + } + + if (p & 1) /*Parity*/ + { + keyboard_pcjr.serial_data[9 * 2] = 1; + keyboard_pcjr.serial_data[9 * 2 + 1] = 0; + } + else + { + keyboard_pcjr.serial_data[9 * 2] = 0; + keyboard_pcjr.serial_data[9 * 2 + 1] = 1; + } + + for (c = 0; c < 11; c++) /*11 stop bits*/ + { + keyboard_pcjr.serial_data[(c + 10) * 2] = 0; + keyboard_pcjr.serial_data[(c + 10) * 2 + 1] = 0; + } + + keyboard_pcjr.serial_pos++; + } + + if (keyboard_pcjr.serial_pos) + { + keyboard_pcjr.data = keyboard_pcjr.serial_data[keyboard_pcjr.serial_pos - 1]; + nmi = keyboard_pcjr.data; + keyboard_pcjr.serial_pos++; + if (keyboard_pcjr.serial_pos == 42+1) + keyboard_pcjr.serial_pos = 0; +// pclog("Keyboard poll %i %i\n", keyboard_pcjr.data, keyboard_pcjr.serial_pos); + } +} + +void keyboard_pcjr_adddata(uint8_t val) +{ + key_queue[key_queue_end] = val; +// pclog("keyboard_pcjr : %02X added to key queue at %i\n", val, key_queue_end); + key_queue_end = (key_queue_end + 1) & 0xf; + return; +} + +void keyboard_pcjr_write(uint16_t port, uint8_t val, void *priv) +{ +// pclog("keyboard_pcjr : write %04X %02X %02X\n", port, val, keyboard_pcjr.pb); +/* if (ram[8] == 0xc3) + { + output = 3; + }*/ + switch (port) + { + case 0x60: + keyboard_pcjr.pa = val; + break; + + case 0x61: + keyboard_pcjr.pb = val; + + timer_process(); + timer_update_outstanding(); + + speaker_update(); + speaker_gated = val & 1; + speaker_enable = val & 2; + if (speaker_enable) + was_speaker_enable = 1; + pit_set_gate(2, val & 1); + sn76489_mute = speaker_mute = 1; + switch (val & 0x60) + { + case 0x00: + speaker_mute = 0; + break; + case 0x60: + sn76489_mute = 0; + break; + } + break; + + case 0xa0: + nmi_mask = val & 0x80; + pit_set_using_timer(1, !(val & 0x20)); + break; + } +} + +uint8_t keyboard_pcjr_read(uint16_t port, void *priv) +{ + uint8_t temp; +// pclog("keyboard_pcjr : read %04X ", port); + switch (port) + { + case 0x60: + temp = keyboard_pcjr.pa; + break; + + case 0x61: + temp = keyboard_pcjr.pb; + break; + + case 0x62: + temp = (keyboard_pcjr.latched ? 1 : 0); + temp |= 0x02; /*Modem card not installed*/ + temp |= (ppispeakon ? 0x10 : 0); + temp |= (ppispeakon ? 0x20 : 0); + temp |= (keyboard_pcjr.data ? 0x40: 0); +// temp |= 0x04; + if (keyboard_pcjr.data) + temp |= 0x40; + break; + + case 0xa0: + keyboard_pcjr.latched = 0; + break; + + default: + pclog("\nBad XT keyboard read %04X\n", port); + //dumpregs(); + //exit(-1); + } +// pclog("%02X\n", temp); + return temp; +} + +void keyboard_pcjr_reset() +{ +} + +void keyboard_pcjr_init() +{ + //return; + io_sethandler(0x0060, 0x0004, keyboard_pcjr_read, NULL, NULL, keyboard_pcjr_write, NULL, NULL, NULL); + io_sethandler(0x00a0, 0x0008, keyboard_pcjr_read, NULL, NULL, keyboard_pcjr_write, NULL, NULL, NULL); + keyboard_pcjr_reset(); + keyboard_send = keyboard_pcjr_adddata; + keyboard_poll = keyboard_pcjr_poll; + + timer_add(keyboard_pcjr_poll, &keybsenddelay, TIMER_ALWAYS_ENABLED, NULL); +} diff --git a/src/keyboard_pcjr.h b/src/keyboard_pcjr.h new file mode 100644 index 000000000..ef585ecfa --- /dev/null +++ b/src/keyboard_pcjr.h @@ -0,0 +1,3 @@ +void keyboard_pcjr_init(); +void keyboard_pcjr_reset(); +void keyboard_pcjr_poll(); diff --git a/src/keyboard_xt.c b/src/keyboard_xt.c new file mode 100644 index 000000000..96f731c56 --- /dev/null +++ b/src/keyboard_xt.c @@ -0,0 +1,184 @@ +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "pic.h" +#include "sound.h" +#include "sound_speaker.h" +#include "timer.h" + +#include "keyboard.h" +#include "keyboard_xt.h" + +#define STAT_PARITY 0x80 +#define STAT_RTIMEOUT 0x40 +#define STAT_TTIMEOUT 0x20 +#define STAT_LOCK 0x10 +#define STAT_CD 0x08 +#define STAT_SYSFLAG 0x04 +#define STAT_IFULL 0x02 +#define STAT_OFULL 0x01 + +struct +{ + int blocked; + + uint8_t pa; + uint8_t pb; + + int tandy; +} keyboard_xt; + +static uint8_t key_queue[16]; +static int key_queue_start = 0, key_queue_end = 0; + +void keyboard_xt_poll() +{ + keybsenddelay += (1000 * TIMER_USEC); + if (key_queue_start != key_queue_end && !keyboard_xt.blocked) + { + keyboard_xt.pa = key_queue[key_queue_start]; + picint(2); + pclog("Reading %02X from the key queue at %i\n", keyboard_xt.pa, key_queue_start); + key_queue_start = (key_queue_start + 1) & 0xf; + keyboard_xt.blocked = 1; + } +} + +void keyboard_xt_adddata(uint8_t val) +{ + key_queue[key_queue_end] = val; + pclog("keyboard_xt : %02X added to key queue at %i\n", val, key_queue_end); + key_queue_end = (key_queue_end + 1) & 0xf; + return; +} + +void keyboard_xt_write(uint16_t port, uint8_t val, void *priv) +{ +// pclog("keyboard_xt : write %04X %02X %02X\n", port, val, keyboard_xt.pb); +/* if (ram[8] == 0xc3) + { + output = 3; + }*/ + switch (port) + { + case 0x61: +// pclog("keyboard_xt : pb write %02X %02X %i %02X %i\n", val, keyboard_xt.pb, !(keyboard_xt.pb & 0x40), keyboard_xt.pb & 0x40, (val & 0x40)); + if (!(keyboard_xt.pb & 0x40) && (val & 0x40)) /*Reset keyboard*/ + { + pclog("keyboard_xt : reset keyboard\n"); + key_queue_end = key_queue_start; + keyboard_xt_adddata(0xaa); + } + if ((keyboard_xt.pb & 0x80)==0 && (val & 0x80)!=0) + { + keyboard_xt.pa = 0; + keyboard_xt.blocked = 0; + picintc(2); + } + keyboard_xt.pb = val; + ppi.pb = val; + + timer_process(); + timer_update_outstanding(); + + speaker_update(); + speaker_gated = val & 1; + speaker_enable = val & 2; + if (speaker_enable) + was_speaker_enable = 1; + pit_set_gate(2, val & 1); + + break; + } +} + +uint8_t keyboard_xt_read(uint16_t port, void *priv) +{ + uint8_t temp; +// pclog("keyboard_xt : read %04X ", port); + switch (port) + { + case 0x60: + if ((romset == ROM_IBMPC) && (keyboard_xt.pb & 0x80)) + { + if (VGA || gfxcard == GFX_EGA) + temp = 0x4D; + else if (MDA) + temp = 0x7D; + else + temp = 0x6D; + } + else + temp = keyboard_xt.pa; + break; + + case 0x61: + temp = keyboard_xt.pb; + break; + + case 0x62: + if (romset == ROM_IBMPC) + { + if (keyboard_xt.pb & 0x04) + temp = 0x02; + else + temp = 0x01; + } + else + { + if (keyboard_xt.pb & 0x08) + { + if (VGA || gfxcard == GFX_EGA) + temp = 4; + else if (MDA) + temp = 7; + else + temp = 6; + } + else + temp = 0xD; + } + temp |= (ppispeakon ? 0x20 : 0); + if (keyboard_xt.tandy) + temp |= (tandy_eeprom_read() ? 0x10 : 0); + break; + + default: + pclog("\nBad XT keyboard read %04X\n", port); + //dumpregs(); + //exit(-1); + } +// pclog("%02X\n", temp); + return temp; +} + +void keyboard_xt_reset() +{ + keyboard_xt.blocked = 0; + + keyboard_scan = 1; +} + +void keyboard_xt_init() +{ + //return; + io_sethandler(0x0060, 0x0004, keyboard_xt_read, NULL, NULL, keyboard_xt_write, NULL, NULL, NULL); + keyboard_xt_reset(); + keyboard_send = keyboard_xt_adddata; + keyboard_poll = keyboard_xt_poll; + keyboard_xt.tandy = 0; + + timer_add(keyboard_xt_poll, &keybsenddelay, TIMER_ALWAYS_ENABLED, NULL); +} + +void keyboard_tandy_init() +{ + //return; + io_sethandler(0x0060, 0x0004, keyboard_xt_read, NULL, NULL, keyboard_xt_write, NULL, NULL, NULL); + keyboard_xt_reset(); + keyboard_send = keyboard_xt_adddata; + keyboard_poll = keyboard_xt_poll; + keyboard_xt.tandy = (romset != ROM_TANDY) ? 1 : 0; + + timer_add(keyboard_xt_poll, &keybsenddelay, TIMER_ALWAYS_ENABLED, NULL); +} diff --git a/src/keyboard_xt.h b/src/keyboard_xt.h new file mode 100644 index 000000000..edbc82945 --- /dev/null +++ b/src/keyboard_xt.h @@ -0,0 +1,4 @@ +void keyboard_xt_init(); +void keyboard_tandy_init(); +void keyboard_xt_reset(); +void keyboard_xt_poll(); diff --git a/src/linux-time.c b/src/linux-time.c new file mode 100644 index 000000000..8b7511d84 --- /dev/null +++ b/src/linux-time.c @@ -0,0 +1,48 @@ +#include +#include +#include "ibm.h" +#include "nvr.h" + +void time_get(char *nvrram) +{ + int c,d; + uint8_t baknvr[10]; + time_t cur_time; + struct tm cur_time_tm; + + memcpy(baknvr,nvrram,10); + + cur_time = time(NULL); + localtime_r(&cur_time, &cur_time_tm); + + d = cur_time_tm.tm_sec % 10; + c = cur_time_tm.tm_sec / 10; + nvrram[0] = d | (c << 4); + d = cur_time_tm.tm_min % 10; + c = cur_time_tm.tm_min / 10; + nvrram[2] = d | (c << 4); + d = cur_time_tm.tm_hour % 10; + c = cur_time_tm.tm_hour / 10; + nvrram[4] = d | (c << 4); + d = cur_time_tm.tm_wday % 10; + c = cur_time_tm.tm_wday / 10; + nvrram[6] = d | (c << 4); + d = cur_time_tm.tm_mday % 10; + c = cur_time_tm.tm_mday / 10; + nvrram[7] = d | (c << 4); + d = cur_time_tm.tm_mon % 10; + c = cur_time_tm.tm_mon / 10; + nvrram[8] = d | (c << 4); + d = cur_time_tm.tm_year % 10; + c = (cur_time_tm.tm_year / 10) % 10; + nvrram[9] = d | (c << 4); + if (baknvr[0] != nvrram[0] || + baknvr[2] != nvrram[2] || + baknvr[4] != nvrram[4] || + baknvr[6] != nvrram[6] || + baknvr[7] != nvrram[7] || + baknvr[8] != nvrram[8] || + baknvr[9] != nvrram[9]) + nvrram[0xA] |= 0x80; +} + diff --git a/src/lpt.c b/src/lpt.c new file mode 100644 index 000000000..407dae254 --- /dev/null +++ b/src/lpt.c @@ -0,0 +1,95 @@ +#include "ibm.h" +#include "io.h" + +#include "lpt.h" + +static uint8_t lpt1_dat, lpt2_dat; +static uint8_t lpt1_ctrl, lpt2_ctrl; + +void lpt1_write(uint16_t port, uint8_t val, void *priv) +{ + switch (port & 3) + { + case 0: + writedac(val); + lpt1_dat = val; + break; + case 2: + writedacctrl(val); + lpt1_ctrl = val; + break; + } +} +uint8_t lpt1_read(uint16_t port, void *priv) +{ + switch (port & 3) + { + case 0: + return lpt1_dat; + case 1: + return readdacfifo(); + case 2: + return lpt1_ctrl; + } + return 0xff; +} + +void lpt2_write(uint16_t port, uint8_t val, void *priv) +{ + switch (port & 3) + { + case 0: + writedac(val); + lpt2_dat = val; + break; + case 2: + writedacctrl(val); + lpt2_ctrl = val; + break; + } +} +uint8_t lpt2_read(uint16_t port, void *priv) +{ + switch (port & 3) + { + case 0: + return lpt2_dat; + case 1: + return readdacfifo(); + case 2: + return lpt2_ctrl; + } + return 0xff; +} + +void lpt_init() +{ + io_sethandler(0x0378, 0x0003, lpt1_read, NULL, NULL, lpt1_write, NULL, NULL, NULL); + io_sethandler(0x0278, 0x0003, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL, NULL); +} + +void lpt1_init(uint16_t port) +{ + io_sethandler(port, 0x0003, lpt1_read, NULL, NULL, lpt1_write, NULL, NULL, NULL); +} +void lpt1_remove() +{ + io_removehandler(0x0278, 0x0003, lpt1_read, NULL, NULL, lpt1_write, NULL, NULL, NULL); + io_removehandler(0x0378, 0x0003, lpt1_read, NULL, NULL, lpt1_write, NULL, NULL, NULL); + io_removehandler(0x03bc, 0x0003, lpt1_read, NULL, NULL, lpt1_write, NULL, NULL, NULL); +} +void lpt2_init(uint16_t port) +{ + io_sethandler(port, 0x0003, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL, NULL); +} +void lpt2_remove() +{ + io_removehandler(0x0278, 0x0003, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL, NULL); + io_removehandler(0x0378, 0x0003, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL, NULL); + io_removehandler(0x03bc, 0x0003, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL, NULL); +} + +void lpt2_remove_ams() +{ + io_removehandler(0x0379, 0x0002, lpt2_read, NULL, NULL, lpt2_write, NULL, NULL, NULL); +} diff --git a/src/lpt.h b/src/lpt.h new file mode 100644 index 000000000..0df90a7e7 --- /dev/null +++ b/src/lpt.h @@ -0,0 +1,6 @@ +extern void lpt_init(); +extern void lpt1_init(uint16_t port); +extern void lpt1_remove(); +extern void lpt2_init(uint16_t port); +extern void lpt2_remove(); +extern void lpt2_remove_ams(); diff --git a/src/mcr.c b/src/mcr.c new file mode 100644 index 000000000..32f67fd63 --- /dev/null +++ b/src/mcr.c @@ -0,0 +1,37 @@ +/*INTEL 82355 MCR emulation + This chip was used as part of many 386 chipsets + It controls memory addressing and shadowing*/ +#include "ibm.h" + +int nextreg6; +uint8_t mcr22; +int mcrlock,mcrfirst; +void resetmcr() +{ + mcrlock=0; + mcrfirst=1; + shadowbios=0; +} + +void writemcr(uint16_t addr, uint8_t val) +{ + printf("Write MCR %04X %02X %04X:%04X\n",addr,val,CS,cpu_state.pc); + switch (addr) + { + case 0x22: + if (val==6 && mcr22==6) nextreg6=1; + else nextreg6=0; +// if ((val&1) && (mcr22&1)) shadowbios=1; +// if (!(val&1) && !(mcr22&1)) shadowbios=0; +// if (!mcrfirst) shadowbios=val&1; +// mcrfirst=0; +// dumpregs(); +// exit(-1); + break; + case 0x23: + if (nextreg6) shadowbios=!val; + break; + } + mcr22=val; +} + diff --git a/src/mem.c b/src/mem.c new file mode 100644 index 000000000..9a4fb8da7 --- /dev/null +++ b/src/mem.c @@ -0,0 +1,2090 @@ +/*MESS ROM notes : + + - pc2386 BIOS is corrupt (JMP at F000:FFF0 points to RAM) + - pc2386 video BIOS is underdumped (16k instead of 24k) + - c386sx16 BIOS fails checksum +*/ + +#include +#include +#include "ibm.h" + +#include "config.h" +#include "mem.h" +#include "video.h" +#include "x86.h" +#include "cpu.h" +#include "rom.h" +#include "x86_ops.h" +#include "codegen.h" + +page_t *pages; +page_t **page_lookup; + +static uint8_t (*_mem_read_b[0x40000])(uint32_t addr, void *priv); +static uint16_t (*_mem_read_w[0x40000])(uint32_t addr, void *priv); +static uint32_t (*_mem_read_l[0x40000])(uint32_t addr, void *priv); +static void (*_mem_write_b[0x40000])(uint32_t addr, uint8_t val, void *priv); +static void (*_mem_write_w[0x40000])(uint32_t addr, uint16_t val, void *priv); +static void (*_mem_write_l[0x40000])(uint32_t addr, uint32_t val, void *priv); +static uint8_t *_mem_exec[0x40000]; +static void *_mem_priv_r[0x40000]; +static void *_mem_priv_w[0x40000]; +static mem_mapping_t *_mem_mapping_r[0x40000]; +static mem_mapping_t *_mem_mapping_w[0x40000]; +static int _mem_state[0x40000]; + +static mem_mapping_t base_mapping; +mem_mapping_t ram_low_mapping; +static mem_mapping_t ram_high_mapping; +static mem_mapping_t ram_mid_mapping; +static mem_mapping_t ram_remapped_mapping; +mem_mapping_t bios_mapping[8]; +mem_mapping_t bios_high_mapping[8]; +static mem_mapping_t romext_mapping; + +int shadowbios,shadowbios_write; + +static unsigned char isram[0x10000]; + +static uint8_t ff_array[0x1000]; + +int mem_size; +int cache=4; +uint32_t biosmask; +int readlnum=0,writelnum=0; +int cachesize=256; + +uint8_t *ram,*rom,*vram; +uint8_t romext[32768]; + +static void mem_load_xtide_bios() +{ + FILE *f; + f=romfopen("roms/ide_xt.bin","rb"); + +// is486=0; + if (f) + { + fread(romext,16384,1,f); + mem_mapping_enable(&romext_mapping); + fclose(f); + } +} + +static void mem_load_atide_bios() +{ + FILE *f; + f=romfopen("roms/ide_at.bin","rb"); + +// is486=0; + if (f) + { + fread(romext,16384,1,f); + mem_mapping_enable(&romext_mapping); + fclose(f); + } +} + +static void mem_load_atide115_bios() +{ + FILE *f; + f=romfopen("roms/ide_at_1_1_5.bin","rb"); + +// is486=0; + if (f) + { + fread(romext,16384,1,f); + mem_mapping_enable(&romext_mapping); + fclose(f); + } +} + +int loadbios() +{ + FILE *f=NULL,*ff=NULL; + int c; + + loadfont("roms/mda.rom", 0); + + biosmask = 0xffff; + + memset(romext,0xff,0x8000); + memset(rom, 0xff, 0x20000); + + pclog("Starting with romset %i\n", romset); + + mem_mapping_disable(&romext_mapping); + + switch (romset) + { + case ROM_PC1512: + f=romfopen("roms/pc1512/40043.v1","rb"); + ff=romfopen("roms/pc1512/40044.v1","rb"); + if (!f || !ff) break; + for (c=0xC000;c<0x10000;c+=2) + { + rom[c]=getc(f); + rom[c+1]=getc(ff); + } + fclose(ff); + fclose(f); + mem_load_xtide_bios(); + loadfont("roms/pc1512/40078.ic127", 2); + return 1; + case ROM_PC1640: + f=romfopen("roms/pc1640/40044.v3","rb"); + ff=romfopen("roms/pc1640/40043.v3","rb"); + if (!f || !ff) break; + for (c=0xC000;c<0x10000;c+=2) + { + rom[c]=getc(f); + rom[c+1]=getc(ff); + } + fclose(ff); + fclose(f); + f=romfopen("roms/pc1640/40100","rb"); + if (!f) break; + fclose(f); + mem_load_xtide_bios(); + return 1; + case ROM_PC200: + f=romfopen("roms/pc200/pc20v2.1","rb"); + ff=romfopen("roms/pc200/pc20v2.0","rb"); + if (!f || !ff) break; + for (c=0xC000;c<0x10000;c+=2) + { + rom[c]=getc(f); + rom[c+1]=getc(ff); + } + fclose(ff); + fclose(f); + mem_load_xtide_bios(); + loadfont("roms/pc200/40109.bin", 1); + return 1; + case ROM_TANDY: + f=romfopen("roms/tandy/tandy1t1.020","rb"); + if (!f) break; + fread(rom,65536,1,f); + fclose(f); + mem_load_xtide_bios(); + return 1; + case ROM_TANDY1000HX: + f = romfopen("roms/tandy1000hx/v020000.u12", "rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + mem_load_xtide_bios(); + return 1; + case ROM_TANDY1000SL2: + f = romfopen("roms/tandy1000sl2/8079047.hu1" ,"rb"); + ff = romfopen("roms/tandy1000sl2/8079048.hu2","rb"); + if (!f || !ff) break; + fseek(f, 0x30000/2, SEEK_SET); + fseek(ff, 0x30000/2, SEEK_SET); + for (c = 0x0000; c < 0x10000; c += 2) + { + rom[c] = getc(f); + rom[c + 1] = getc(ff); + } + fclose(ff); + fclose(f); + mem_load_xtide_bios(); + return 1; +/* case ROM_IBMPCJR: + f=fopen("pcjr/bios.rom","rb"); + fread(rom+0xE000,8192,1,f); + fclose(f); + f=fopen("pcjr/basic.rom","rb"); + fread(rom+0x6000,32768,1,f); + fclose(f); + break;*/ + case ROM_IBMXT: + f=romfopen("roms/ibmxt/xt.rom","rb"); + if (!f) + { + f = romfopen("roms/ibmxt/5000027.u19", "rb"); + ff = romfopen("roms/ibmxt/1501512.u18","rb"); + if (!f || !ff) break; + fread(rom, 0x8000, 1, f); + fread(rom + 0x8000, 0x8000, 1, ff); + fclose(ff); + fclose(f); + mem_load_xtide_bios(); + return 1; + } + else + { + fread(rom,65536,1,f); + fclose(f); + mem_load_xtide_bios(); + return 1; + } + break; + + case ROM_IBMPCJR: + f = romfopen("roms/ibmpcjr/bios.rom","rb"); + if (!f) break; + fread(rom, 0x10000, 1, f); + fclose(f); + return 1; + + case ROM_GENXT: + f=romfopen("roms/genxt/pcxt.rom","rb"); + if (!f) break; + fread(rom+0xE000,8192,1,f); + fclose(f); + mem_load_xtide_bios(); + return 1; + case ROM_DTKXT: + f=romfopen("roms/dtk/DTK_ERSO_2.42_2764.bin","rb"); + if (!f) break; + fread(rom+0xE000,8192,1,f); + fclose(f); + mem_load_xtide_bios(); + return 1; + case ROM_OLIM24: + f = romfopen("roms/olivetti_m24/olivetti_m24_version_1.43_low.bin" ,"rb"); + ff = romfopen("roms/olivetti_m24/olivetti_m24_version_1.43_high.bin","rb"); + if (!f || !ff) break; + for (c = 0x0000; c < 0x4000; c += 2) + { + rom[c + 0xc000] = getc(f); + rom[c + 0xc001] = getc(ff); + } + fclose(ff); + fclose(f); + mem_load_xtide_bios(); + return 1; + + case ROM_PC2086: + f = romfopen("roms/pc2086/40179.ic129" ,"rb"); + ff = romfopen("roms/pc2086/40180.ic132","rb"); + if (!f || !ff) break; + pclog("Loading BIOS\n"); + for (c = 0x0000; c < 0x4000; c += 2) + { + rom[c + 0x0000] = getc(f); + rom[c + 0x0001] = getc(ff); + } + pclog("%02X %02X %02X\n", rom[0xfff0], rom[0xfff1], rom[0xfff2]); + fclose(ff); + fclose(f); + f = romfopen("roms/pc2086/40186.ic171", "rb"); + if (!f) break; + fclose(f); + mem_load_xtide_bios(); + biosmask = 0x3fff; + return 1; + + case ROM_PC3086: + f = romfopen("roms/pc3086/fc00.bin" ,"rb"); + if (!f) break; + fread(rom, 0x4000, 1, f); + fclose(f); + f = romfopen("roms/pc3086/c000.bin", "rb"); + if (!f) break; + fclose(f); + mem_load_xtide_bios(); + biosmask = 0x3fff; + return 1; + + case ROM_IBMAT: +/* f=romfopen("roms/AMIC206.BIN","rb"); + if (!f) break; + fread(rom,65536,1,f); + fclose(f); + return 1;*/ + case ROM_IBMAT386: + f = romfopen("roms/ibmat/62x0820.u27", "rb"); + ff =romfopen("roms/ibmat/62x0821.u47", "rb"); + if (!f || !ff) break; + for (c=0x0000;c<0x10000;c+=2) + { + rom[c]=getc(f); + rom[c+1]=getc(ff); + } + fclose(ff); + fclose(f); + mem_load_atide_bios(); + return 1; + case ROM_CMDPC30: + f = romfopen("roms/cmdpc30/commodore pc 30 iii even.bin", "rb"); + ff = romfopen("roms/cmdpc30/commodore pc 30 iii odd.bin", "rb"); + if (!f || !ff) break; + for (c = 0x0000; c < 0x8000; c += 2) + { + rom[c] = getc(f); + rom[c + 1] = getc(ff); + } + fclose(ff); + fclose(f); + biosmask = 0x7fff; + mem_load_atide_bios(); + return 1; + case ROM_DELL200: + f=romfopen("roms/dells200/dell0.bin","rb"); + ff=romfopen("roms/dells200/dell1.bin","rb"); + if (!f || !ff) break; + for (c=0x0000;c<0x10000;c+=2) + { + rom[c]=getc(f); + rom[c+1]=getc(ff); + } + fclose(ff); + fclose(f); + return 1; +/* case ROM_IBMAT386: + f=romfopen("roms/at386/at386.bin","rb"); + if (!f) break; + fread(rom,65536,1,f); + fclose(f); + return 1;*/ + case ROM_AMI386: /*This uses the OPTi 82C495 chipset*/ +// f=romfopen("roms/at386/at386.bin","rb"); + f=romfopen("roms/ami386/ami386.bin","rb"); + if (!f) break; + fread(rom,65536,1,f); + fclose(f); + return 1; + + + case ROM_ACER386: + f=romfopen("roms/acer386/acer386.bin","rb"); + if (!f) break; + fread(rom,65536,1,f); + fclose(f); + rom[0xB0]=0xB0-0x51; + rom[0x40d4]=0x51; /*PUSH CX*/ + f=romfopen("roms/acer386/oti067.bin","rb"); + if (!f) break; + fclose(f); + return 1; + + case ROM_AMI286: + f=romfopen("roms/ami286/amic206.bin","rb"); + if (!f) break; + fread(rom,65536,1,f); + fclose(f); +// memset(romext,0x63,0x8000); + return 1; + + case ROM_AWARD286: + f=romfopen("roms/award286/award.bin","rb"); + if (!f) break; + fread(rom,65536,1,f); + fclose(f); + return 1; + + case ROM_EUROPC: +// return 0; + f=romfopen("roms/europc/50145","rb"); + if (!f) break; + fread(rom+0x8000,32768,1,f); + fclose(f); +// memset(romext,0x63,0x8000); + return 1; + + case ROM_IBMPC: + f=romfopen("roms/ibmpc/pc102782.bin","rb"); + if (!f) break; +// f=fopen("pc081682.bin","rb"); + fread(rom+0xE000,8192,1,f); + fclose(f); + f=romfopen("roms/ibmpc/basicc11.f6","rb"); + if (!f) return 1; /*I don't really care if BASIC is there or not*/ + fread(rom+0x6000,8192,1,f); + fclose(f); + f=romfopen("roms/ibmpc/basicc11.f8","rb"); + if (!f) break; /*But if some of it is there, then all of it must be*/ + fread(rom+0x8000,8192,1,f); + fclose(f); + f=romfopen("roms/ibmpc/basicc11.fa","rb"); + if (!f) break; + fread(rom+0xA000,8192,1,f); + fclose(f); + f=romfopen("roms/ibmpc/basicc11.fc","rb"); + if (!f) break; + fread(rom+0xC000,8192,1,f); + fclose(f); + mem_load_xtide_bios(); + return 1; + + case ROM_MEGAPC: + f = romfopen("roms/megapc/41651-bios lo.u18", "rb"); + ff = romfopen("roms/megapc/211253-bios hi.u19", "rb"); + if (!f || !ff) break; + fseek(f, 0x8000, SEEK_SET); + fseek(ff, 0x8000, SEEK_SET); + for (c = 0x0000; c < 0x10000; c+=2) + { + rom[c]=getc(f); + rom[c+1]=getc(ff); + } + fclose(ff); + fclose(f); + return 1; + + case ROM_AMI486: + f=romfopen("roms/ami486/ami486.BIN","rb"); + if (!f) break; + fread(rom,65536,1,f); + fclose(f); + //is486=1; + return 1; + + case ROM_WIN486: +// f=romfopen("roms/win486/win486.bin","rb"); + f=romfopen("roms/win486/ALI1429G.AMW","rb"); + if (!f) break; + fread(rom,65536,1,f); + fclose(f); + //is486=1; + return 1; + + case ROM_PCI486: + f=romfopen("roms/hot-433/hot-433.ami","rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + //is486=1; + return 1; + + case ROM_SIS496: + f = romfopen("roms/sis496/SIS496-1.AWA", "rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + pclog("Load SIS496 %x %x\n", rom[0x1fff0], rom[0xfff0]); + return 1; + + case ROM_430VX: +// f = romfopen("roms/430vx/Ga586atv.bin", "rb"); +// f = fopen("roms/430vx/vx29.BIN", "rb"); + f = romfopen("roms/430vx/55XWUQ0E.BIN", "rb"); +// f=romfopen("roms/430vx/430vx","rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + //is486=1; + return 1; + + case ROM_REVENGE: + f = romfopen("roms/revenge/1009AF2_.BIO", "rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + fread(rom + 0x10000, 0x10000, 1, f); + fclose(f); + f = romfopen("roms/revenge/1009AF2_.BI1", "rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + fread(rom, 0xc000, 1, f); + fclose(f); + biosmask = 0x1ffff; + //is486=1; + return 1; + case ROM_ENDEAVOR: + f = romfopen("roms/endeavor/1006CB0_.BIO", "rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + fread(rom + 0x10000, 0x10000, 1, f); + fclose(f); + f = romfopen("roms/endeavor/1006CB0_.BI1", "rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + fread(rom, 0xd000, 1, f); + fclose(f); + biosmask = 0x1ffff; + //is486=1; + return 1; + + case ROM_IBMPS1_2011: +#if 0 + f=romfopen("roms/ibmps1es/ibm_1057757_24-05-90.bin","rb"); + ff=romfopen("roms/ibmps1es/ibm_1057757_29-15-90.bin","rb"); + fseek(f, 0x10000, SEEK_SET); + fseek(ff, 0x10000, SEEK_SET); + if (!f || !ff) break; + for (c = 0x0000; c < 0x20000; c += 2) + { + rom[c] = getc(f); + rom[c+1] = getc(ff); + } + fclose(ff); + fclose(f); +#endif +//#if 0 + f = romfopen("roms/ibmps1es/f80000.bin", "rb"); + if (!f) break; + fseek(f, 0x60000, SEEK_SET); + fread(rom, 0x20000, 1, f); + fclose(f); +//#endif + biosmask = 0x1ffff; + mem_load_atide115_bios(); + return 1; + + case ROM_IBMPS1_2121: + f = romfopen("roms/ibmps1_2121/fc0000.bin", "rb"); + if (!f) break; + fseek(f, 0x20000, SEEK_SET); + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_DESKPRO_386: + f=romfopen("roms/deskpro386/109592-005.U11.bin","rb"); + ff=romfopen("roms/deskpro386/109591-005.U13.bin","rb"); + if (!f || !ff) break; + for (c = 0x0000; c < 0x8000; c += 2) + { + rom[c] = getc(f); + rom[c+1] = getc(ff); + } + fclose(ff); + fclose(f); + biosmask = 0x7fff; + mem_load_atide_bios(); + return 1; + + case ROM_AMIXT: + f = romfopen("roms/amixt/AMI_8088_BIOS_31JAN89.BIN", "rb"); + if (!f) break; + fread(rom + 0xE000, 8192, 1, f); + fclose(f); + mem_load_xtide_bios(); + return 1; + + case ROM_LTXT: + f = romfopen("roms/ltxt/27C64.bin", "rb"); + if (!f) break; + fread(rom + 0xE000, 8192, 1, f); + fclose(f); + mem_load_xtide_bios(); + return 1; + + case ROM_LXT3: + f = romfopen("roms/lxt3/27C64D.bin", "rb"); + if (!f) break; + fread(rom + 0xE000, 8192, 1, f); + fclose(f); + mem_load_xtide_bios(); + return 1; + + case ROM_PX386: /*Phoenix 80386 BIOS*/ + f=romfopen("roms/px386/3iip001l.bin","rb"); + ff=romfopen("roms/px386/3iip001h.bin","rb"); + if (!f || !ff) break; + for (c = 0x0000; c < 0x10000; c += 2) + { + rom[c] = getc(f); + rom[c+1] = getc(ff); + } + fclose(ff); + fclose(f); + mem_load_atide_bios(); + return 1; + + case ROM_DTK386: /*Uses NEAT chipset*/ + f = romfopen("roms/dtk386/3cto001.bin", "rb"); + if (!f) break; + fread(rom, 65536, 1, f); + fclose(f); + mem_load_atide_bios(); + return 1; + + case ROM_PXXT: + f = romfopen("roms/pxxt/000p001.bin", "rb"); + if (!f) break; + fread(rom + 0xE000, 8192, 1, f); + fclose(f); + mem_load_xtide_bios(); + return 1; + + case ROM_JUKOPC: + f = romfopen("roms/jukopc/000o001.bin", "rb"); + if (!f) break; + fread(rom + 0xE000, 8192, 1, f); + fclose(f); + mem_load_xtide_bios(); + return 1; + + case ROM_DTK486: + f = romfopen("roms/dtk486/4siw005.bin", "rb"); + if (!f) break; + fread(rom, 0x10000, 1, f); + fclose(f); + return 1; + + case ROM_R418: + f = romfopen("roms/r418/r418i.bin", "rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + pclog("Load R418 %x %x\n", rom[0x1fff0], rom[0xfff0]); + return 1; + + case ROM_586MC1: + f = romfopen("roms/586mc1/IS.34", "rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_PLATO: + f = romfopen("roms/plato/1016AX1_.BIO", "rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + fread(rom + 0x10000, 0x10000, 1, f); + fclose(f); + f = romfopen("roms/plato/1016AX1_.BI1", "rb"); + if (!f) break; + fseek(f, 0x80, SEEK_SET); + fread(rom, 0xd000, 1, f); + fclose(f); + biosmask = 0x1ffff; + //is486=1; + return 1; + + case ROM_MB500N: + f = romfopen("roms/mb500n/031396S.BIN", "rb"); /* Works */ + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_P54TP4XE: + f = romfopen("roms/p54tp4xe/T15I0302.AWD", "rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_ACERM3A: + f = romfopen("roms/acerm3a/r01-b3.bin", "rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_ACERV35N: + f = romfopen("roms/acerv35n/V35ND1S1.BIN", "rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_P55T2P4: + f = romfopen("roms/p55t2p4/0207_J2.BIN", "rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_P55TVP4: + f = romfopen("roms/p55tvp4/tv5i0201.awd", "rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_P55VA: + f = romfopen("roms/p55va/VA021297.BIN", "rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_440FX: + f = romfopen("roms/440fx/NTMAW501.BIN", "rb"); /* Working Tyan BIOS. */ + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + + case ROM_KN97: + f = romfopen("roms/kn97/NAKI0116.AWD", "rb"); + if (!f) break; + fread(rom, 0x20000, 1, f); + fclose(f); + biosmask = 0x1ffff; + return 1; + } + printf("Failed to load ROM!\n"); + if (f) fclose(f); + if (ff) fclose(ff); + return 0; +} + + + +int abrt=0; + +void resetreadlookup() +{ + int c; +// /*if (output) */pclog("resetreadlookup\n"); + memset(readlookup2,0xFF,1024*1024*sizeof(uintptr_t)); + for (c=0;c<256;c++) readlookup[c]=0xFFFFFFFF; + readlnext=0; + memset(writelookup2,0xFF,1024*1024*sizeof(uintptr_t)); + memset(page_lookup, 0, (1 << 20) * sizeof(page_t *)); + for (c=0;c<256;c++) writelookup[c]=0xFFFFFFFF; + writelnext=0; + pccache=0xFFFFFFFF; +// readlnum=writelnum=0; + +} + +int mmuflush=0; +int mmu_perm=4; + +void flushmmucache() +{ + int c; +// /*if (output) */pclog("flushmmucache\n"); +/* for (c=0;c<16;c++) + { + if ( readlookup2[0xE0+c]!=0xFFFFFFFF) pclog("RL2 %02X = %08X\n",0xE0+c, readlookup2[0xE0+c]); + if (writelookup2[0xE0+c]!=0xFFFFFFFF) pclog("WL2 %02X = %08X\n",0xE0+c,writelookup2[0xE0+c]); + }*/ + for (c=0;c<256;c++) + { + if (readlookup[c]!=0xFFFFFFFF) + { + readlookup2[readlookup[c]] = -1; + readlookup[c]=0xFFFFFFFF; + } + if (writelookup[c] != 0xFFFFFFFF) + { + page_lookup[writelookup[c]] = NULL; + writelookup2[writelookup[c]] = -1; + writelookup[c] = 0xFFFFFFFF; + } + } + mmuflush++; +// readlnum=writelnum=0; + pccache=(uint32_t)0xFFFFFFFF; + pccache2=(uint8_t *)0xFFFFFFFF; + +// memset(readlookup,0xFF,sizeof(readlookup)); +// memset(readlookup2,0xFF,1024*1024*4); +// memset(writelookup,0xFF,sizeof(writelookup)); +// memset(writelookup2,0xFF,1024*1024*4); +/* if (!(cr0>>31)) return;*/ + +/* for (c = 0; c < 1024*1024; c++) + { + if (readlookup2[c] != 0xFFFFFFFF) + { + pclog("Readlookup inconsistency - %05X %08X\n", c, readlookup2[c]); + dumpregs(); + exit(-1); + } + if (writelookup2[c] != 0xFFFFFFFF) + { + pclog("Readlookup inconsistency - %05X %08X\n", c, readlookup2[c]); + dumpregs(); + exit(-1); + } + }*/ + codegen_flush(); +} + +void flushmmucache_nopc() +{ + int c; + for (c=0;c<256;c++) + { + if (readlookup[c]!=0xFFFFFFFF) + { + readlookup2[readlookup[c]] = -1; + readlookup[c]=0xFFFFFFFF; + } + if (writelookup[c] != 0xFFFFFFFF) + { + page_lookup[writelookup[c]] = NULL; + writelookup2[writelookup[c]] = -1; + writelookup[c] = 0xFFFFFFFF; + } + } +} + +void flushmmucache_cr3() +{ + int c; +// /*if (output) */pclog("flushmmucache_cr3\n"); + for (c=0;c<256;c++) + { + if (readlookup[c]!=0xFFFFFFFF)// && !readlookupp[c]) + { + readlookup2[readlookup[c]] = -1; + readlookup[c]=0xFFFFFFFF; + } + if (writelookup[c] != 0xFFFFFFFF)// && !writelookupp[c]) + { + page_lookup[writelookup[c]] = NULL; + writelookup2[writelookup[c]] = -1; + writelookup[c] = 0xFFFFFFFF; + } + } +/* for (c = 0; c < 1024*1024; c++) + { + if (readlookup2[c] != 0xFFFFFFFF) + { + pclog("Readlookup inconsistency - %05X %08X\n", c, readlookup2[c]); + dumpregs(); + exit(-1); + } + if (writelookup2[c] != 0xFFFFFFFF) + { + pclog("Readlookup inconsistency - %05X %08X\n", c, readlookup2[c]); + dumpregs(); + exit(-1); + } + }*/ +} + +void mem_flush_write_page(uint32_t addr, uint32_t virt) +{ + int c; + page_t *page_target = &pages[addr >> 12]; +// pclog("mem_flush_write_page %08x %08x\n", virt, addr); + + for (c = 0; c < 256; c++) + { + if (writelookup[c] != 0xffffffff) + { + uintptr_t target = (uintptr_t)&ram[(uintptr_t)(addr & ~0xfff) - (virt & ~0xfff)]; + +// if ((virt & ~0xfff) == 0xc022e000) +// pclog(" Checking %02x %p %p\n", (void *)writelookup2[writelookup[c]], (void *)target); + if (writelookup2[writelookup[c]] == target || page_lookup[writelookup[c]] == page_target) + { +// pclog(" throw out %02x %p %p\n", writelookup[c], (void *)page_lookup[writelookup[c]], (void *)writelookup2[writelookup[c]]); + writelookup2[writelookup[c]] = -1; + page_lookup[writelookup[c]] = NULL; + writelookup[c] = 0xffffffff; + } + } + } +} + +extern int output; + +#define mmutranslate_read(addr) mmutranslatereal(addr,0) +#define mmutranslate_write(addr) mmutranslatereal(addr,1) + +int pctrans=0; + +extern uint32_t testr[9]; + +uint32_t mmutranslatereal(uint32_t addr, int rw) +{ + uint32_t addr2; + uint32_t temp,temp2,temp3; + + if (abrt) + { +// pclog("Translate recursive abort\n"); + return -1; + } +/* if ((addr&~0xFFFFF)==0x77f00000) pclog("Do translate %08X %i %08X %08X\n",addr,rw,EAX,cpu_state.pc); + if (addr==0x77f61000) output = 3; + if (addr==0x77f62000) { dumpregs(); exit(-1); } + if (addr==0x77f9a000) { dumpregs(); exit(-1); }*/ + addr2 = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc)); + temp=temp2=((uint32_t *)ram)[addr2>>2]; +// if (output == 3) pclog("Do translate %08X %i %08X\n", addr, rw, temp); + if (!(temp&1))// || (CPL==3 && !(temp&4) && !cpl_override) || (rw && !(temp&2) && (CPL==3 || cr0&WP_FLAG))) + { +// if (!nopageerrors) pclog("Section not present! %08X %08X %02X %04X:%08X %i %i\n",addr,temp,opcode,CS,cpu_state.pc,CPL,rw); + + cr2=addr; + temp&=1; + if (CPL==3) temp|=4; + if (rw) temp|=2; + abrt = ABRT_PF; + abrt_error = temp; +/* if (addr == 0x70046D) + { + dumpregs(); + exit(-1); + }*/ + return -1; + } + temp=((uint32_t *)ram)[((temp&~0xFFF)+((addr>>10)&0xFFC))>>2]; + temp3=temp&temp2; +// if (output == 3) pclog("Do translate %08X %08X\n", temp, temp3); + if (!(temp&1) || (CPL==3 && !(temp3&4) && !cpl_override) || (rw && !(temp3&2) && (CPL==3 || cr0&WP_FLAG))) + { +// if (!nopageerrors) pclog("Page not present! %08X %08X %02X %02X %i %08X %04X:%08X %04X:%08X %i %i %i\n",addr,temp,opcode,opcode2,frame,rmdat32, CS,cpu_state.pc,SS,ESP,ins,CPL,rw); + +// dumpregs(); +// exit(-1); +// if (addr == 0x815F6E90) output = 3; +/* if (addr == 0x10ADE020) output = 3;*/ +/* if (addr == 0x10150010 && !nopageerrors) + { + dumpregs(); + exit(-1); + }*/ + + cr2=addr; + temp&=1; + if (CPL==3) temp|=4; + if (rw) temp|=2; + abrt = ABRT_PF; + abrt_error = temp; +// pclog("%04X\n",abrt); + return -1; + } + mmu_perm=temp&4; + ((uint32_t *)ram)[addr2>>2]|=0x20; + ((uint32_t *)ram)[((temp2&~0xFFF)+((addr>>10)&0xFFC))>>2]|=(rw?0x60:0x20); +// /*if (output) */pclog("Translate %08X %08X %08X %08X:%08X %08X\n",addr,(temp&~0xFFF)+(addr&0xFFF),temp,cs,cpu_state.pc,EDI); + + return (temp&~0xFFF)+(addr&0xFFF); +} + +uint32_t mmutranslate_noabrt(uint32_t addr, int rw) +{ + uint32_t addr2; + uint32_t temp,temp2,temp3; + + if (abrt) + return -1; + + addr2 = ((cr3 & ~0xfff) + ((addr >> 20) & 0xffc)); + temp=temp2=((uint32_t *)ram)[addr2>>2]; + + if (!(temp&1)) + return -1; + + temp=((uint32_t *)ram)[((temp&~0xFFF)+((addr>>10)&0xFFC))>>2]; + temp3=temp&temp2; + + if (!(temp&1) || (CPL==3 && !(temp3&4) && !cpl_override) || (rw && !(temp3&2) && (CPL==3 || cr0&WP_FLAG))) + return -1; + + return (temp&~0xFFF)+(addr&0xFFF); +} + +void mmu_invalidate(uint32_t addr) +{ +// readlookup2[addr >> 12] = writelookup2[addr >> 12] = 0xFFFFFFFF; + flushmmucache_cr3(); +} + +int memspeed[11]={256,320,384,512,640,768,1024,1152,1280,1536,1920}; +int memwaitstate; + +static int cachelookup[256]; +static uint8_t *cachelookup2; +static int cachelnext; + +void addreadlookup(uint32_t virt, uint32_t phys) +{ +// return; +// printf("Addreadlookup %08X %08X %08X %08X %08X %08X %02X %08X\n",virt,phys,cs,ds,es,ss,opcode,cpu_state.pc); + if (virt == 0xffffffff) + return; + + if (readlookup2[virt>>12] != -1) + { +/* if (readlookup2[virt>>12] != phys&~0xfff) + { + pclog("addreadlookup mismatch - %05X000 %05X000\n", readlookup[readlnext], virt >> 12); + dumpregs(); + exit(-1); + }*/ + return; + } + + + if (!cachelookup2[phys >> 12]) + { + readlnum++; + cycles-=memwaitstate; + if (cachelookup[cachelnext] != 0xffffffff) + cachelookup2[cachelookup[cachelnext]] = 0; + cachelookup[cachelnext] = phys >> 12; + cachelookup2[phys >> 12] = 1; + cachelnext = (cachelnext + 1) & (cachesize - 1); + } + + if (readlookup[readlnext]!=0xFFFFFFFF) + { + readlookup2[readlookup[readlnext]] = -1; +// readlnum--; + } + readlookup2[virt>>12] = (uintptr_t)&ram[(uintptr_t)(phys & ~0xFFF) - (uintptr_t)(virt & ~0xfff)]; + readlookupp[readlnext]=mmu_perm; + readlookup[readlnext++]=virt>>12; + readlnext&=(cachesize-1); + + cycles -= 9; +} + +void addwritelookup(uint32_t virt, uint32_t phys) +{ +// return; +// printf("Addwritelookup %08X %08X\n",virt,phys); + if (virt == 0xffffffff) + return; + + if (page_lookup[virt >> 12]) + { +/* if (writelookup2[virt>>12] != phys&~0xfff) + { + pclog("addwritelookup mismatch - %05X000 %05X000\n", readlookup[readlnext], virt >> 12); + dumpregs(); + exit(-1); + }*/ + return; + } + + if (!cachelookup2[phys >> 12]) + { + writelnum++; + cycles-=memwaitstate; + if (cachelookup[cachelnext] != 0xffffffff) + cachelookup2[cachelookup[cachelnext]] = 0; + cachelookup[cachelnext] = phys >> 12; + cachelookup2[phys >> 12] = 1; + cachelnext = (cachelnext + 1) & (cachesize - 1); + } + + cycles-=memwaitstate; + if (writelookup[writelnext] != -1) + { + page_lookup[writelookup[writelnext]] = NULL; + writelookup2[writelookup[writelnext]] = -1; +// writelnum--; + } +// if (page_lookup[virt >> 12] && (writelookup2[virt>>12] != 0xffffffff)) +// fatal("Bad write mapping\n"); + + if (pages[phys >> 12].block || (phys & ~0xfff) == recomp_page) + page_lookup[virt >> 12] = &pages[phys >> 12];//(uintptr_t)&ram[(uintptr_t)(phys & ~0xFFF) - (uintptr_t)(virt & ~0xfff)]; + else + writelookup2[virt>>12] = (uintptr_t)&ram[(uintptr_t)(phys & ~0xFFF) - (uintptr_t)(virt & ~0xfff)]; +// pclog("addwritelookup %08x %08x %p %p %016llx %p\n", virt, phys, (void *)page_lookup[virt >> 12], (void *)writelookup2[virt >> 12], pages[phys >> 12].dirty_mask, (void *)&pages[phys >> 12]); + writelookupp[writelnext] = mmu_perm; + writelookup[writelnext++] = virt >> 12; + writelnext &= (cachesize - 1); + + cycles -= 9; +} + +#undef printf +uint8_t *getpccache(uint32_t a) +{ + uint32_t a2=a; + + if (cr0>>31) + { + pctrans=1; + a = mmutranslate_read(a); + pctrans=0; + + if (a==0xFFFFFFFF) return ram; + } + a&=rammask; + + if (isram[a>>16]) + { + if ((a >> 16) != 0xF || shadowbios) + addreadlookup(a2, a); + return &ram[(uintptr_t)(a & 0xFFFFF000) - (uintptr_t)(a2 & ~0xFFF)]; + } + + if (_mem_exec[a >> 14]) + { + return &_mem_exec[a >> 14][(uintptr_t)(a & 0x3000) - (uintptr_t)(a2 & ~0xFFF)]; + } + + pclog("Bad getpccache %08X\n", a); + return &ff_array[0-(uintptr_t)(a2 & ~0xFFF)]; +} +#define printf pclog + +uint32_t mem_logical_addr; +uint8_t readmembl(uint32_t addr) +{ + mem_logical_addr = addr; + if (cr0 >> 31) + { + addr = mmutranslate_read(addr); + if (addr == 0xFFFFFFFF) return 0xFF; + } + addr &= rammask; + + if (_mem_read_b[addr >> 14]) return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]); +// pclog("Bad readmembl %08X %04X:%08X\n", addr, CS, pc); + return 0xFF; +} + +void writemembl(uint32_t addr, uint8_t val) +{ + mem_logical_addr = addr; + + if (page_lookup[addr>>12]) + { + page_lookup[addr>>12]->write_b(addr, val, page_lookup[addr>>12]); + return; + } + if (cr0 >> 31) + { + addr = mmutranslate_write(addr); + if (addr == 0xFFFFFFFF) return; + } + addr &= rammask; + + if (_mem_write_b[addr >> 14]) _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); +// else pclog("Bad writemembl %08X %02X %04X:%08X\n", addr, val, CS, pc); +} + +uint8_t readmemb386l(uint32_t seg, uint32_t addr) +{ + if (seg==-1) + { + x86gpf("NULL segment", 0); + printf("NULL segment! rb %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr); + return -1; + } + mem_logical_addr = addr = addr + seg; +/* if (readlookup2[mem_logical_addr >> 12] != 0xFFFFFFFF) + { + return ram[readlookup2[mem_logical_addr >> 12] + (mem_logical_addr & 0xFFF)]; + }*/ + + if (cr0 >> 31) + { + addr = mmutranslate_read(addr); + if (addr == 0xFFFFFFFF) return 0xFF; + } + + addr &= rammask; + + if (_mem_read_b[addr >> 14]) return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]); +// pclog("Bad readmemb386l %08X %04X:%08X\n", addr, CS, pc); + return 0xFF; +} + +void writememb386l(uint32_t seg, uint32_t addr, uint8_t val) +{ + if (seg==-1) + { + x86gpf("NULL segment", 0); + printf("NULL segment! wb %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr); + return; + } + + mem_logical_addr = addr = addr + seg; + if (page_lookup[addr>>12]) + { + page_lookup[addr>>12]->write_b(addr, val, page_lookup[addr>>12]); + return; + } + if (cr0 >> 31) + { + addr = mmutranslate_write(addr); + if (addr == 0xFFFFFFFF) return; + } + + addr &= rammask; + +/* if (addr >= 0xa0000 && addr < 0xc0000) + pclog("writemembl %08X %02X\n", addr, val);*/ + + if (_mem_write_b[addr >> 14]) _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); +// else pclog("Bad writememb386l %08X %02X %04X:%08X\n", addr, val, CS, pc); +} + +uint16_t readmemwl(uint32_t seg, uint32_t addr) +{ + uint32_t addr2 = mem_logical_addr = seg + addr; + if ((addr2&0xFFF)>0xFFE) + { + if (cr0>>31) + { + if (mmutranslate_read(addr2) == 0xffffffff) return 0xffff; + if (mmutranslate_read(addr2+1) == 0xffffffff) return 0xffff; + } + if (is386) return readmemb386l(seg,addr)|(readmemb386l(seg,addr+1)<<8); + else return readmembl(seg+addr)|(readmembl(seg+addr+1)<<8); + } + if (seg==-1) + { + x86gpf("NULL segment", 0); + printf("NULL segment! rw %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr); + return -1; + } + if (cr0>>31) + { + addr2 = mmutranslate_read(addr2); + if (addr2==0xFFFFFFFF) return 0xFFFF; + } + + addr2 &= rammask; + + if (_mem_read_w[addr2 >> 14]) return _mem_read_w[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]); + + if (_mem_read_b[addr2 >> 14]) + { + if (AT) return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | (_mem_read_b[(addr2 + 1) >> 14](addr2 + 1, _mem_priv_r[addr2 >> 14]) << 8); + else return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | (_mem_read_b[(seg + ((addr + 1) & 0xffff)) >> 14](seg + ((addr + 1) & 0xffff), _mem_priv_r[addr2 >> 14]) << 8); + } +// pclog("Bad readmemwl %08X\n", addr2); + return 0xffff; +} + +void writememwl(uint32_t seg, uint32_t addr, uint16_t val) +{ + uint32_t addr2 = mem_logical_addr = seg + addr; + if ((addr2&0xFFF)>0xFFE) + { + if (cr0>>31) + { + if (mmutranslate_write(addr2) == 0xffffffff) return; + if (mmutranslate_write(addr2+1) == 0xffffffff) return; + } + if (is386) + { + writememb386l(seg,addr,val); + writememb386l(seg,addr+1,val>>8); + } + else + { + writemembl(seg+addr,val); + writemembl(seg+addr+1,val>>8); + } + return; + } + + if (seg==-1) + { + x86gpf("NULL segment", 0); + printf("NULL segment! ww %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr); + return; + } + if (page_lookup[addr2>>12]) + { + page_lookup[addr2>>12]->write_w(addr2, val, page_lookup[addr2>>12]); + return; + } + if (cr0>>31) + { + addr2 = mmutranslate_write(addr2); + if (addr2==0xFFFFFFFF) return; + } + + addr2 &= rammask; + +/* if (addr2 >= 0xa0000 && addr2 < 0xc0000) + pclog("writememwl %08X %02X\n", addr2, val);*/ + + if (_mem_write_w[addr2 >> 14]) + { + _mem_write_w[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + return; + } + + if (_mem_write_b[addr2 >> 14]) + { + _mem_write_b[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + _mem_write_b[(addr2 + 1) >> 14](addr2 + 1, val >> 8, _mem_priv_w[addr2 >> 14]); + return; + } +// pclog("Bad writememwl %08X %04X\n", addr2, val); +} + +uint32_t readmemll(uint32_t seg, uint32_t addr) +{ + uint32_t addr2 = mem_logical_addr = seg + addr; + if ((addr2&0xFFF)>0xFFC) + { + if (cr0>>31) + { + if (mmutranslate_read(addr2) == 0xffffffff) return 0xffffffff; + if (mmutranslate_read(addr2+3) == 0xffffffff) return 0xffffffff; + } + return readmemwl(seg,addr)|(readmemwl(seg,addr+2)<<16); + } + + if (seg==-1) + { + x86gpf("NULL segment", 0); + printf("NULL segment! rl %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr); + return -1; + } + + if (cr0>>31) + { + addr2 = mmutranslate_read(addr2); + if (addr2==0xFFFFFFFF) return 0xFFFFFFFF; + } + + addr2&=rammask; + + if (_mem_read_l[addr2 >> 14]) return _mem_read_l[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]); + + if (_mem_read_w[addr2 >> 14]) return _mem_read_w[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | (_mem_read_w[addr2 >> 14](addr2 + 2, _mem_priv_r[addr2 >> 14]) << 16); + + if (_mem_read_b[addr2 >> 14]) return _mem_read_b[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | (_mem_read_b[addr2 >> 14](addr2 + 1, _mem_priv_r[addr2 >> 14]) << 8) | (_mem_read_b[addr2 >> 14](addr2 + 2, _mem_priv_r[addr2 >> 14]) << 16) | (_mem_read_b[addr2 >> 14](addr2 + 3, _mem_priv_r[addr2 >> 14]) << 24); + +// pclog("Bad readmemll %08X\n", addr2); + return 0xffffffff; +} + +void writememll(uint32_t seg, uint32_t addr, uint32_t val) +{ + uint32_t addr2 = mem_logical_addr = seg + addr; + + if ((addr2&0xFFF)>0xFFC) + { + if (cr0>>31) + { + if (mmutranslate_write(addr2) == 0xffffffff) return; + if (mmutranslate_write(addr2+3) == 0xffffffff) return; + } + writememwl(seg,addr,val); + writememwl(seg,addr+2,val>>16); + return; + } + if (seg==-1) + { + x86gpf("NULL segment", 0); + printf("NULL segment! wl %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr); + return; + } + if (page_lookup[addr2>>12]) + { + page_lookup[addr2>>12]->write_l(addr2, val, page_lookup[addr2>>12]); + return; + } + if (cr0>>31) + { + addr2 = mmutranslate_write(addr2); + if (addr2==0xFFFFFFFF) return; + } + + addr2&=rammask; + +/* if (addr >= 0xa0000 && addr < 0xc0000) + pclog("writememll %08X %08X\n", addr, val);*/ + + if (_mem_write_l[addr2 >> 14]) + { + _mem_write_l[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + return; + } + if (_mem_write_w[addr2 >> 14]) + { + _mem_write_w[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + _mem_write_w[addr2 >> 14](addr2 + 2, val >> 16, _mem_priv_w[addr2 >> 14]); + return; + } + if (_mem_write_b[addr2 >> 14]) + { + _mem_write_b[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 1, val >> 8, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 2, val >> 16, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 3, val >> 24, _mem_priv_w[addr2 >> 14]); + return; + } +// pclog("Bad writememll %08X %08X\n", addr2, val); +} + +uint64_t readmemql(uint32_t seg, uint32_t addr) +{ + uint32_t addr2 = mem_logical_addr = seg + addr; + if ((addr2&0xFFF)>0xFF8) + { + if (cr0>>31) + { + if (mmutranslate_read(addr2) == 0xffffffff) return 0xffffffff; + if (mmutranslate_read(addr2+7) == 0xffffffff) return 0xffffffff; + } + return readmemll(seg,addr)|((uint64_t)readmemll(seg,addr+4)<<32); + } + + if (seg==-1) + { + x86gpf("NULL segment", 0); + printf("NULL segment! rl %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr); + return -1; + } + + if (cr0>>31) + { + addr2 = mmutranslate_read(addr2); + if (addr2==0xFFFFFFFF) return 0xFFFFFFFF; + } + + addr2&=rammask; + + if (_mem_read_l[addr2 >> 14]) + return _mem_read_l[addr2 >> 14](addr2, _mem_priv_r[addr2 >> 14]) | + ((uint64_t)_mem_read_l[addr2 >> 14](addr2 + 4, _mem_priv_r[addr2 >> 14]) << 32); + + return readmemll(seg,addr) | ((uint64_t)readmemll(seg,addr+4)<<32); +} + +void writememql(uint32_t seg, uint32_t addr, uint64_t val) +{ + uint32_t addr2 = mem_logical_addr = seg + addr; + + if ((addr2 & 0xFFF) > 0xFF8) + { + if (cr0>>31) + { + if (mmutranslate_write(addr2) == 0xffffffff) return; + if (mmutranslate_write(addr2+7) == 0xffffffff) return; + } + writememll(seg, addr, val); + writememll(seg, addr+4, val >> 32); + return; + } + if (seg==-1) + { + x86gpf("NULL segment", 0); + printf("NULL segment! wl %04X(%08X):%08X %02X %08X\n",CS,cs,cpu_state.pc,opcode,addr); + return; + } + if (page_lookup[addr2>>12]) + { + page_lookup[addr2>>12]->write_l(addr2, val, page_lookup[addr2>>12]); + page_lookup[addr2>>12]->write_l(addr2 + 4, val >> 32, page_lookup[addr2>>12]); + return; + } + if (cr0>>31) + { + addr2 = mmutranslate_write(addr2); + if (addr2==0xFFFFFFFF) return; + } + + addr2&=rammask; + + if (_mem_write_l[addr2 >> 14]) + { + _mem_write_l[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + _mem_write_l[addr2 >> 14](addr2+4, val >> 32, _mem_priv_w[addr2 >> 14]); + return; + } + if (_mem_write_w[addr2 >> 14]) + { + _mem_write_w[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + _mem_write_w[addr2 >> 14](addr2 + 2, val >> 16, _mem_priv_w[addr2 >> 14]); + _mem_write_w[addr2 >> 14](addr2 + 4, val >> 32, _mem_priv_w[addr2 >> 14]); + _mem_write_w[addr2 >> 14](addr2 + 6, val >> 48, _mem_priv_w[addr2 >> 14]); + return; + } + if (_mem_write_b[addr2 >> 14]) + { + _mem_write_b[addr2 >> 14](addr2, val, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 1, val >> 8, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 2, val >> 16, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 3, val >> 24, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 4, val >> 32, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 5, val >> 40, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 6, val >> 48, _mem_priv_w[addr2 >> 14]); + _mem_write_b[addr2 >> 14](addr2 + 7, val >> 56, _mem_priv_w[addr2 >> 14]); + return; + } +// pclog("Bad writememql %08X %08X\n", addr2, val); +} + +uint8_t mem_readb_phys(uint32_t addr) +{ + mem_logical_addr = 0xffffffff; + + if (_mem_read_b[addr >> 14]) + return _mem_read_b[addr >> 14](addr, _mem_priv_r[addr >> 14]); + + return 0xff; +} + +void mem_writeb_phys(uint32_t addr, uint8_t val) +{ + mem_logical_addr = 0xffffffff; + + if (_mem_write_b[addr >> 14]) + _mem_write_b[addr >> 14](addr, val, _mem_priv_w[addr >> 14]); +} + +uint8_t mem_read_ram(uint32_t addr, void *priv) +{ +// if (addr >= 0xc0000 && addr < 0x0c8000) pclog("Read RAMb %08X\n", addr); + addreadlookup(mem_logical_addr, addr); + return ram[addr]; +} +uint16_t mem_read_ramw(uint32_t addr, void *priv) +{ +// if (addr >= 0xc0000 && addr < 0x0c8000) pclog("Read RAMw %08X\n", addr); + addreadlookup(mem_logical_addr, addr); + return *(uint16_t *)&ram[addr]; +} +uint32_t mem_read_raml(uint32_t addr, void *priv) +{ +// if (addr >= 0xc0000 && addr < 0x0c8000) pclog("Read RAMl %08X\n", addr); + addreadlookup(mem_logical_addr, addr); + return *(uint32_t *)&ram[addr]; +} + +void mem_write_ramb_page(uint32_t addr, uint8_t val, page_t *p) +{ + if (val != p->mem[addr & 0xfff] || codegen_in_recompile) + { + uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); +// pclog("mem_write_ramb_page: %08x %02x %08x %llx %llx\n", addr, val, cs+pc, p->dirty_mask, mask); + p->dirty_mask |= mask; + p->mem[addr & 0xfff] = val; + } +} +void mem_write_ramw_page(uint32_t addr, uint16_t val, page_t *p) +{ + if (val != *(uint16_t *)&p->mem[addr & 0xfff] || codegen_in_recompile) + { + uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); + if ((addr & 0x3f) == 0x3f) + mask |= (mask << 1); +// pclog("mem_write_ramw_page: %08x %04x %08x\n", addr, val, cs+pc); + p->dirty_mask |= mask; + *(uint16_t *)&p->mem[addr & 0xfff] = val; + } +} +void mem_write_raml_page(uint32_t addr, uint32_t val, page_t *p) +{ + if (val != *(uint32_t *)&p->mem[addr & 0xfff] || codegen_in_recompile) + { + uint64_t mask = (uint64_t)1 << ((addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); + if ((addr & 0x3f) >= 0x3d) + mask |= (mask << 1); +// pclog("mem_write_raml_page: %08x %08x %08x\n", addr, val, cs+pc); + p->dirty_mask |= mask; + *(uint32_t *)&p->mem[addr & 0xfff] = val; + } +} + +void mem_write_ram(uint32_t addr, uint8_t val, void *priv) +{ + addwritelookup(mem_logical_addr, addr); + mem_write_ramb_page(addr, val, &pages[addr >> 12]); +} +void mem_write_ramw(uint32_t addr, uint16_t val, void *priv) +{ + addwritelookup(mem_logical_addr, addr); + mem_write_ramw_page(addr, val, &pages[addr >> 12]); +} +void mem_write_raml(uint32_t addr, uint32_t val, void *priv) +{ + addwritelookup(mem_logical_addr, addr); + mem_write_raml_page(addr, val, &pages[addr >> 12]); +} + +uint8_t mem_read_bios(uint32_t addr, void *priv) +{ + if (AMIBIOS && (addr&0xFFFFF)==0xF8281) /*This is read constantly during AMIBIOS POST, but is never written to. It's clearly a status register of some kind, but for what?*/ + { +// pclog("Read magic addr %04X(%06X):%04X\n",CS,cs,cpu_state.pc); +// if (pc==0x547D) output=3; + return 0x40; + } +// pclog("Read BIOS %08X %02X %04X:%04X\n", addr, rom[addr & biosmask], CS, pc); + return rom[addr & biosmask]; +} +uint16_t mem_read_biosw(uint32_t addr, void *priv) +{ +// pclog("Read BIOS %08X %04X %04X:%04X\n", addr, *(uint16_t *)&rom[addr & biosmask], CS, pc); + return *(uint16_t *)&rom[addr & biosmask]; +} +uint32_t mem_read_biosl(uint32_t addr, void *priv) +{ +// pclog("Read BIOS %08X %02X %04X:%04X\n", addr, *(uint32_t *)&rom[addr & biosmask], CS, pc); + return *(uint32_t *)&rom[addr & biosmask]; +} + +uint8_t mem_read_romext(uint32_t addr, void *priv) +{ + return romext[addr & 0x7fff]; +} +uint16_t mem_read_romextw(uint32_t addr, void *priv) +{ + return *(uint16_t *)&romext[addr & 0x7fff]; +} +uint32_t mem_read_romextl(uint32_t addr, void *priv) +{ + return *(uint32_t *)&romext[addr & 0x7fff]; +} + +void mem_write_null(uint32_t addr, uint8_t val, void *p) +{ +} +void mem_write_nullw(uint32_t addr, uint16_t val, void *p) +{ +} +void mem_write_nulll(uint32_t addr, uint32_t val, void *p) +{ +} + +void mem_updatecache() +{ + flushmmucache(); + if (!is386) + { + cachesize=256; + memwaitstate=0; + return; + } + if (cpu_16bitbus) + memwaitstate = 512 * ((cpu_multi >= 2) ? 2 : cpu_multi); + else + memwaitstate = 384 * ((cpu_multi >= 2) ? 2 : cpu_multi); //memspeed[cpuspeed]; + switch (cache) + { + case 0: cachesize=32; break; + case 1: cachesize=64; break; + case 2: cachesize=128; break; + case 3: cachesize=256; break; + case 4: cachesize=256; memwaitstate=0; break; + } +} + +void mem_invalidate_range(uint32_t start_addr, uint32_t end_addr) +{ + start_addr &= ~PAGE_MASK_MASK; + end_addr = (end_addr + PAGE_MASK_MASK) & ~PAGE_MASK_MASK; + + for (; start_addr <= end_addr; start_addr += (1 << PAGE_MASK_SHIFT)) + { + uint64_t mask = (uint64_t)1 << ((start_addr >> PAGE_MASK_SHIFT) & PAGE_MASK_MASK); + + pages[start_addr >> 12].dirty_mask |= mask; + } +} + +static inline int mem_mapping_read_allowed(uint32_t flags, int state) +{ +// pclog("mem_mapping_read_allowed: flags=%x state=%x\n", flags, state); + switch (state & MEM_READ_MASK) + { + case MEM_READ_ANY: + return 1; + case MEM_READ_EXTERNAL: + return !(flags & MEM_MAPPING_INTERNAL); + case MEM_READ_INTERNAL: + return !(flags & MEM_MAPPING_EXTERNAL); + default: + fatal("mem_mapping_read_allowed : bad state %x\n", state); + } +} + +static inline int mem_mapping_write_allowed(uint32_t flags, int state) +{ + switch (state & MEM_WRITE_MASK) + { + case MEM_WRITE_DISABLED: + return 0; + case MEM_WRITE_ANY: + return 1; + case MEM_WRITE_EXTERNAL: + return !(flags & MEM_MAPPING_INTERNAL); + case MEM_WRITE_INTERNAL: + return !(flags & MEM_MAPPING_EXTERNAL); + default: + fatal("mem_mapping_write_allowed : bad state %x\n", state); + } +} + +static void mem_mapping_recalc(uint64_t base, uint64_t size) +{ + uint64_t c; + mem_mapping_t *mapping = base_mapping.next; + + if (!size) + return; + /*Clear out old mappings*/ + for (c = base; c < base + size; c += 0x4000) + { + _mem_read_b[c >> 14] = NULL; + _mem_read_w[c >> 14] = NULL; + _mem_read_l[c >> 14] = NULL; + _mem_priv_r[c >> 14] = NULL; + _mem_mapping_r[c >> 14] = NULL; + _mem_write_b[c >> 14] = NULL; + _mem_write_w[c >> 14] = NULL; + _mem_write_l[c >> 14] = NULL; + _mem_priv_w[c >> 14] = NULL; + _mem_mapping_w[c >> 14] = NULL; + } + + /*Walk mapping list*/ + while (mapping != NULL) + { + /*In range?*/ + if (mapping->enable && (uint64_t)mapping->base < ((uint64_t)base + (uint64_t)size) && ((uint64_t)mapping->base + (uint64_t)mapping->size) > (uint64_t)base) + { + uint64_t start = (mapping->base < base) ? mapping->base : base; + uint64_t end = (((uint64_t)mapping->base + (uint64_t)mapping->size) < (base + size)) ? ((uint64_t)mapping->base + (uint64_t)mapping->size) : (base + size); + if (start < mapping->base) + start = mapping->base; + + for (c = start; c < end; c += 0x4000) + { + if ((mapping->read_b || mapping->read_w || mapping->read_l) && + mem_mapping_read_allowed(mapping->flags, _mem_state[c >> 14])) + { + _mem_read_b[c >> 14] = mapping->read_b; + _mem_read_w[c >> 14] = mapping->read_w; + _mem_read_l[c >> 14] = mapping->read_l; + if (mapping->exec) + _mem_exec[c >> 14] = mapping->exec + (c - mapping->base); + else + _mem_exec[c >> 14] = NULL; + _mem_priv_r[c >> 14] = mapping->p; + _mem_mapping_r[c >> 14] = mapping; + } + if ((mapping->write_b || mapping->write_w || mapping->write_l) && + mem_mapping_write_allowed(mapping->flags, _mem_state[c >> 14])) + { + _mem_write_b[c >> 14] = mapping->write_b; + _mem_write_w[c >> 14] = mapping->write_w; + _mem_write_l[c >> 14] = mapping->write_l; + _mem_priv_w[c >> 14] = mapping->p; + _mem_mapping_w[c >> 14] = mapping; + } + } + } + mapping = mapping->next; + } + flushmmucache_cr3(); +} + +void mem_mapping_add(mem_mapping_t *mapping, + uint32_t base, + uint32_t size, + uint8_t (*read_b)(uint32_t addr, void *p), + uint16_t (*read_w)(uint32_t addr, void *p), + uint32_t (*read_l)(uint32_t addr, void *p), + void (*write_b)(uint32_t addr, uint8_t val, void *p), + void (*write_w)(uint32_t addr, uint16_t val, void *p), + void (*write_l)(uint32_t addr, uint32_t val, void *p), + uint8_t *exec, + uint32_t flags, + void *p) +{ + mem_mapping_t *dest = &base_mapping; + + /*Add mapping to the end of the list*/ + while (dest->next) + dest = dest->next; + dest->next = mapping; + + if (size) + mapping->enable = 1; + else + mapping->enable = 0; + mapping->base = base; + mapping->size = size; + mapping->read_b = read_b; + mapping->read_w = read_w; + mapping->read_l = read_l; + mapping->write_b = write_b; + mapping->write_w = write_w; + mapping->write_l = write_l; + mapping->exec = exec; + mapping->flags = flags; + mapping->p = p; + mapping->next = NULL; + + mem_mapping_recalc(mapping->base, mapping->size); +} + +void mem_mapping_set_handler(mem_mapping_t *mapping, + uint8_t (*read_b)(uint32_t addr, void *p), + uint16_t (*read_w)(uint32_t addr, void *p), + uint32_t (*read_l)(uint32_t addr, void *p), + void (*write_b)(uint32_t addr, uint8_t val, void *p), + void (*write_w)(uint32_t addr, uint16_t val, void *p), + void (*write_l)(uint32_t addr, uint32_t val, void *p)) +{ + mapping->read_b = read_b; + mapping->read_w = read_w; + mapping->read_l = read_l; + mapping->write_b = write_b; + mapping->write_w = write_w; + mapping->write_l = write_l; + + mem_mapping_recalc(mapping->base, mapping->size); +} + +void mem_mapping_set_addr(mem_mapping_t *mapping, uint32_t base, uint32_t size) +{ + /*Remove old mapping*/ + mapping->enable = 0; + mem_mapping_recalc(mapping->base, mapping->size); + + /*Set new mapping*/ + mapping->enable = 1; + mapping->base = base; + mapping->size = size; + + mem_mapping_recalc(mapping->base, mapping->size); +} + +void mem_mapping_set_exec(mem_mapping_t *mapping, uint8_t *exec) +{ + mapping->exec = exec; + + mem_mapping_recalc(mapping->base, mapping->size); +} + +void mem_mapping_set_p(mem_mapping_t *mapping, void *p) +{ + mapping->p = p; +} + +void mem_mapping_disable(mem_mapping_t *mapping) +{ + mapping->enable = 0; + + mem_mapping_recalc(mapping->base, mapping->size); +} + +void mem_mapping_enable(mem_mapping_t *mapping) +{ + mapping->enable = 1; + + mem_mapping_recalc(mapping->base, mapping->size); +} + +void mem_set_mem_state(uint32_t base, uint32_t size, int state) +{ + uint32_t c; + +// pclog("mem_set_pci_enable: base=%08x size=%08x\n", base, size); + for (c = 0; c < size; c += 0x4000) + _mem_state[(c + base) >> 14] = state; + + mem_mapping_recalc(base, size); +} + +void mem_add_bios() +{ + if (AT) + { + mem_mapping_add(&bios_mapping[0], 0xe0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom, MEM_MAPPING_EXTERNAL, 0); + mem_mapping_add(&bios_mapping[1], 0xe4000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x4000 & biosmask), MEM_MAPPING_EXTERNAL, 0); + mem_mapping_add(&bios_mapping[2], 0xe8000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x8000 & biosmask), MEM_MAPPING_EXTERNAL, 0); + mem_mapping_add(&bios_mapping[3], 0xec000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0xc000 & biosmask), MEM_MAPPING_EXTERNAL, 0); + } + mem_mapping_add(&bios_mapping[4], 0xf0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x10000 & biosmask), MEM_MAPPING_EXTERNAL, 0); + mem_mapping_add(&bios_mapping[5], 0xf4000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x14000 & biosmask), MEM_MAPPING_EXTERNAL, 0); + mem_mapping_add(&bios_mapping[6], 0xf8000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x18000 & biosmask), MEM_MAPPING_EXTERNAL, 0); + mem_mapping_add(&bios_mapping[7], 0xfc000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x1c000 & biosmask), MEM_MAPPING_EXTERNAL, 0); + + mem_mapping_add(&bios_high_mapping[0], 0xfffe0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom, 0, 0); + mem_mapping_add(&bios_high_mapping[1], 0xfffe4000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x4000 & biosmask), 0, 0); + mem_mapping_add(&bios_high_mapping[2], 0xfffe8000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x8000 & biosmask), 0, 0); + mem_mapping_add(&bios_high_mapping[3], 0xfffec000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0xc000 & biosmask), 0, 0); + mem_mapping_add(&bios_high_mapping[4], 0xffff0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x10000 & biosmask), 0, 0); + mem_mapping_add(&bios_high_mapping[5], 0xffff4000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x14000 & biosmask), 0, 0); + mem_mapping_add(&bios_high_mapping[6], 0xffff8000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x18000 & biosmask), 0, 0); + mem_mapping_add(&bios_high_mapping[7], 0xffffc000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (0x1c000 & biosmask), 0, 0); +} + +int mem_a20_key = 0, mem_a20_alt = 0; +static int mem_a20_state = 1; + +void mem_init() +{ + int c; + + ram = malloc((mem_size + 384) * 1024); + rom = malloc(0x20000); + vram = malloc(0x800000); + readlookup2 = malloc(1024 * 1024 * sizeof(uintptr_t)); + writelookup2 = malloc(1024 * 1024 * sizeof(uintptr_t)); + cachelookup2 = malloc(1024 * 1024); + biosmask = 0xffff; + pages = malloc((((mem_size + 384) * 1024) >> 12) * sizeof(page_t)); + page_lookup = malloc((1 << 20) * sizeof(page_t *)); + + memset(ram, 0, (mem_size + 384) * 1024); + memset(pages, 0, (((mem_size + 384) * 1024) >> 12) * sizeof(page_t)); + + memset(page_lookup, 0, (1 << 20) * sizeof(page_t *)); + + for (c = 0; c < (((mem_size + 384) * 1024) >> 12); c++) + { + pages[c].mem = &ram[c << 12]; + pages[c].write_b = mem_write_ramb_page; + pages[c].write_w = mem_write_ramw_page; + pages[c].write_l = mem_write_raml_page; + } + + memset(isram, 0, sizeof(isram)); + for (c = 0; c < (mem_size / 256); c++) + { + isram[c] = 1; + if (c >= 0xa && c <= 0xf) + isram[c] = 0; + } + + memset(_mem_read_b, 0, sizeof(_mem_read_b)); + memset(_mem_read_w, 0, sizeof(_mem_read_w)); + memset(_mem_read_l, 0, sizeof(_mem_read_l)); + memset(_mem_write_b, 0, sizeof(_mem_write_b)); + memset(_mem_write_w, 0, sizeof(_mem_write_w)); + memset(_mem_write_l, 0, sizeof(_mem_write_l)); + memset(_mem_exec, 0, sizeof(_mem_exec)); + + memset(ff_array, 0xff, sizeof(ff_array)); + + memset(&base_mapping, 0, sizeof(base_mapping)); + + memset(_mem_state, 0, sizeof(_mem_state)); + + mem_set_mem_state(0x000000, (mem_size > 640) ? 0xa0000 : mem_size * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_set_mem_state(0x0c0000, 0x40000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + mem_set_mem_state(0x100000, (mem_size - 1024) * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + + mem_mapping_add(&ram_low_mapping, 0x00000, (mem_size > 640) ? 0xa0000 : mem_size * 1024, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml, ram, MEM_MAPPING_INTERNAL, NULL); + if (mem_size > 1024) + mem_mapping_add(&ram_high_mapping, 0x100000, ((mem_size - 1024) * 1024), mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml, ram + 0x100000, MEM_MAPPING_INTERNAL, NULL); + if (mem_size > 768) + mem_mapping_add(&ram_mid_mapping, 0xc0000, 0x40000, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml, ram + 0xc0000, MEM_MAPPING_INTERNAL, NULL); + + mem_mapping_add(&romext_mapping, 0xc8000, 0x08000, mem_read_romext, mem_read_romextw, mem_read_romextl, NULL, NULL, NULL, romext, 0, NULL); +// pclog("Mem resize %i %i\n",mem_size,c); +} + +void mem_remap_top_384k() +{ + int c; + + for (c = ((mem_size * 1024) >> 12); c < (((mem_size + 384) * 1024) >> 12); c++) + { + pages[c].mem = &ram[c << 12]; + pages[c].write_b = mem_write_ramb_page; + pages[c].write_w = mem_write_ramw_page; + pages[c].write_l = mem_write_raml_page; + } + + for (c = (mem_size / 256); c < ((mem_size + 384) / 256); c++) + { + isram[c] = 1; + if (c >= 0xa && c <= 0xf) + isram[c] = 0; + } + + mem_set_mem_state(mem_size * 1024, 384 * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_mapping_add(&ram_remapped_mapping, mem_size * 1024, 384 * 1024, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml, ram + (mem_size * 1024), MEM_MAPPING_INTERNAL, NULL); +} + +void mem_resize() +{ + int c; + + free(ram); + ram = malloc((mem_size + 384) * 1024); + memset(ram, 0, (mem_size + 384) * 1024); + + free(pages); + pages = malloc((((mem_size + 384) * 1024) >> 12) * sizeof(page_t)); + memset(pages, 0, (((mem_size + 384) * 1024) >> 12) * sizeof(page_t)); + for (c = 0; c < (((mem_size + 384) * 1024) >> 12); c++) + { + pages[c].mem = &ram[c << 12]; + pages[c].write_b = mem_write_ramb_page; + pages[c].write_w = mem_write_ramw_page; + pages[c].write_l = mem_write_raml_page; + } + + memset(isram, 0, sizeof(isram)); + for (c = 0; c < (mem_size / 256); c++) + { + isram[c] = 1; + if (c >= 0xa && c <= 0xf) + isram[c] = 0; + } + + memset(_mem_read_b, 0, sizeof(_mem_read_b)); + memset(_mem_read_w, 0, sizeof(_mem_read_w)); + memset(_mem_read_l, 0, sizeof(_mem_read_l)); + memset(_mem_write_b, 0, sizeof(_mem_write_b)); + memset(_mem_write_w, 0, sizeof(_mem_write_w)); + memset(_mem_write_l, 0, sizeof(_mem_write_l)); + memset(_mem_exec, 0, sizeof(_mem_exec)); + + memset(&base_mapping, 0, sizeof(base_mapping)); + + memset(_mem_state, 0, sizeof(_mem_state)); + + mem_set_mem_state(0x000000, (mem_size > 640) ? 0xa0000 : mem_size * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + mem_set_mem_state(0x0c0000, 0x40000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + mem_set_mem_state(0x100000, (mem_size - 1024) * 1024, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + + mem_mapping_add(&ram_low_mapping, 0x00000, (mem_size > 640) ? 0xa0000 : mem_size * 1024, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml, ram, MEM_MAPPING_INTERNAL, NULL); + if (mem_size > 1024) + mem_mapping_add(&ram_high_mapping, 0x100000, (mem_size - 1024) * 1024, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml, ram + 0x100000, MEM_MAPPING_INTERNAL, NULL); + if (mem_size > 768) + mem_mapping_add(&ram_mid_mapping, 0xc0000, 0x40000, mem_read_ram, mem_read_ramw, mem_read_raml, mem_write_ram, mem_write_ramw, mem_write_raml, ram + 0xc0000, MEM_MAPPING_INTERNAL, NULL); + + mem_mapping_add(&romext_mapping, 0xc8000, 0x08000, mem_read_romext, mem_read_romextw, mem_read_romextl, NULL, NULL, NULL, romext, 0, NULL); + +// pclog("Mem resize %i %i\n",mem_size,c); + mem_a20_key = 2; + mem_a20_recalc(); +} + +void mem_reset_page_blocks() +{ + int c; + + for (c = 0; c < ((mem_size * 1024) >> 12); c++) + { + pages[c].write_b = mem_write_ramb_page; + pages[c].write_w = mem_write_ramw_page; + pages[c].write_l = mem_write_raml_page; + pages[c].block = NULL; + pages[c].block_2 = NULL; + } +} + +void mem_a20_recalc() +{ + int state = mem_a20_key | mem_a20_alt; +// pclog("A20 recalc %i %i\n", state, mem_a20_state); + if (state && !mem_a20_state) + { + rammask = 0xffffffff; + flushmmucache(); + } + else if (!state && mem_a20_state) + { + rammask = 0xffefffff; + flushmmucache(); + } +// pclog("rammask now %08X\n", rammask); + mem_a20_state = state; +} + +uint32_t get_phys_virt,get_phys_phys; diff --git a/src/mem.h b/src/mem.h new file mode 100644 index 000000000..1f927e44a --- /dev/null +++ b/src/mem.h @@ -0,0 +1,170 @@ +#ifndef _MEM_H_ +#define _MEM_H_ + +typedef struct mem_mapping_t +{ + struct mem_mapping_t *prev, *next; + + int enable; + + uint32_t base; + uint32_t size; + + uint8_t (*read_b)(uint32_t addr, void *priv); + uint16_t (*read_w)(uint32_t addr, void *priv); + uint32_t (*read_l)(uint32_t addr, void *priv); + void (*write_b)(uint32_t addr, uint8_t val, void *priv); + void (*write_w)(uint32_t addr, uint16_t val, void *priv); + void (*write_l)(uint32_t addr, uint32_t val, void *priv); + + uint8_t *exec; + + uint32_t flags; + + void *p; +} mem_mapping_t; + +/*Only present on external bus (ISA/PCI)*/ +#define MEM_MAPPING_EXTERNAL 1 +/*Only present on internal bus (RAM)*/ +#define MEM_MAPPING_INTERNAL 2 + +extern uint8_t *ram,*rom; +extern uint8_t romext[32768]; +extern int readlnum,writelnum; +extern int memspeed[11]; +extern int nopageerrors; +extern int cache; +extern int memwaitstate; + +void mem_mapping_add(mem_mapping_t *mapping, + uint32_t base, + uint32_t size, + uint8_t (*read_b)(uint32_t addr, void *p), + uint16_t (*read_w)(uint32_t addr, void *p), + uint32_t (*read_l)(uint32_t addr, void *p), + void (*write_b)(uint32_t addr, uint8_t val, void *p), + void (*write_w)(uint32_t addr, uint16_t val, void *p), + void (*write_l)(uint32_t addr, uint32_t val, void *p), + uint8_t *exec, + uint32_t flags, + void *p); +void mem_mapping_set_handler(mem_mapping_t *mapping, + uint8_t (*read_b)(uint32_t addr, void *p), + uint16_t (*read_w)(uint32_t addr, void *p), + uint32_t (*read_l)(uint32_t addr, void *p), + void (*write_b)(uint32_t addr, uint8_t val, void *p), + void (*write_w)(uint32_t addr, uint16_t val, void *p), + void (*write_l)(uint32_t addr, uint32_t val, void *p)); +void mem_mapping_set_p(mem_mapping_t *mapping, void *p); +void mem_mapping_set_addr(mem_mapping_t *mapping, uint32_t base, uint32_t size); +void mem_mapping_set_exec(mem_mapping_t *mapping, uint8_t *exec); +void mem_mapping_disable(mem_mapping_t *mapping); +void mem_mapping_enable(mem_mapping_t *mapping); + +void mem_set_mem_state(uint32_t base, uint32_t size, int state); + +#define MEM_READ_ANY 0x00 +#define MEM_READ_INTERNAL 0x10 +#define MEM_READ_EXTERNAL 0x20 +#define MEM_READ_MASK 0xf0 + +#define MEM_WRITE_ANY 0x00 +#define MEM_WRITE_INTERNAL 0x01 +#define MEM_WRITE_EXTERNAL 0x02 +#define MEM_WRITE_DISABLED 0x03 +#define MEM_WRITE_MASK 0x0f + +extern int mem_a20_alt; +extern int mem_a20_key; +void mem_a20_recalc(); + +uint8_t mem_readb_phys(uint32_t addr); +void mem_writeb_phys(uint32_t addr, uint8_t val); + +uint8_t mem_read_ram(uint32_t addr, void *priv); +uint16_t mem_read_ramw(uint32_t addr, void *priv); +uint32_t mem_read_raml(uint32_t addr, void *priv); + +void mem_write_ram(uint32_t addr, uint8_t val, void *priv); +void mem_write_ramw(uint32_t addr, uint16_t val, void *priv); +void mem_write_raml(uint32_t addr, uint32_t val, void *priv); + +uint8_t mem_read_bios(uint32_t addr, void *priv); +uint16_t mem_read_biosw(uint32_t addr, void *priv); +uint32_t mem_read_biosl(uint32_t addr, void *priv); + +void mem_write_null(uint32_t addr, uint8_t val, void *p); +void mem_write_nullw(uint32_t addr, uint16_t val, void *p); +void mem_write_nulll(uint32_t addr, uint32_t val, void *p); + +FILE *romfopen(char *fn, char *mode); + +mem_mapping_t bios_mapping[8]; +mem_mapping_t bios_high_mapping[8]; + + +typedef struct page_t +{ + void (*write_b)(uint32_t addr, uint8_t val, struct page_t *p); + void (*write_w)(uint32_t addr, uint16_t val, struct page_t *p); + void (*write_l)(uint32_t addr, uint32_t val, struct page_t *p); + + uint8_t *mem; + + struct codeblock_t *block, *block_2; + + /*Head of codeblock tree associated with this page*/ + struct codeblock_t *head; + + uint64_t code_present_mask, dirty_mask; +} page_t; + +extern page_t *pages; + +extern page_t **page_lookup; + +uint32_t mmutranslate_noabrt(uint32_t addr, int rw); + +extern uint32_t get_phys_virt,get_phys_phys; +static inline uint32_t get_phys(uint32_t addr) +{ + if (!((addr ^ get_phys_virt) & ~0xfff)) + return get_phys_phys | (addr & 0xfff); + + get_phys_virt = addr; + + if (!(cr0 >> 31)) + { + get_phys_phys = (addr & rammask) & ~0xfff; + return addr & rammask; + } + + get_phys_phys = (mmutranslatereal(addr, 0) & rammask) & ~0xfff; + return get_phys_phys | (addr & 0xfff); +// return mmutranslatereal(addr, 0) & rammask; +} + +static inline uint32_t get_phys_noabrt(uint32_t addr) +{ + if (!(cr0 >> 31)) + return addr & rammask; + + return mmutranslate_noabrt(addr, 0) & rammask; +} + +void mem_invalidate_range(uint32_t start_addr, uint32_t end_addr); + +extern uint32_t mem_logical_addr; + +void mem_write_ramb_page(uint32_t addr, uint8_t val, page_t *p); +void mem_write_ramw_page(uint32_t addr, uint16_t val, page_t *p); +void mem_write_raml_page(uint32_t addr, uint32_t val, page_t *p); + +void mem_reset_page_blocks(); + +extern mem_mapping_t ram_low_mapping; + +void mem_remap_top_384k(); + +#endif diff --git a/src/memregs.c b/src/memregs.c new file mode 100644 index 000000000..da3ffd827 --- /dev/null +++ b/src/memregs.c @@ -0,0 +1,30 @@ +/* + 0xE1 and 0xE2 Memory Registers + Used by just about any emulated machine +*/ + +#include "ibm.h" + +#include "io.h" +#include "memregs.h" + +static uint8_t mem_regs[2] = {0xFF, 0xFF}; + +void memregs_write(uint16_t port, uint8_t val, void *priv) +{ + mem_regs[port - 0xE1] = val; +} + +uint8_t memregs_read(uint16_t port, void *priv) +{ + return mem_regs[port - 0xE1]; +} + +void memregs_init() +{ + int i = 0; + + pclog("Memory Registers Init\n"); + + io_sethandler(0x00e1, 0x0002, memregs_read, NULL, NULL, memregs_write, NULL, NULL, NULL); +} diff --git a/src/memregs.h b/src/memregs.h new file mode 100644 index 000000000..1f3baa92a --- /dev/null +++ b/src/memregs.h @@ -0,0 +1 @@ +extern void memregs_init(); diff --git a/src/model.c b/src/model.c new file mode 100644 index 000000000..9124a1981 --- /dev/null +++ b/src/model.c @@ -0,0 +1,618 @@ +#include "ibm.h" +#include "cpu.h" +#include "model.h" +#include "io.h" + +#include "acer386sx.h" +#include "acerm3a.h" +#include "ali1429.h" +#include "amstrad.h" +#include "compaq.h" +#include "device.h" +#include "dma.h" +#include "fdc.h" +#include "fdc37c665.h" +#include "fdc37c932fr.h" +#include "gameport.h" +#include "headland.h" +#include "i430fx.h" +#include "i430hx.h" +#include "i430lx.h" +#include "i430nx.h" +#include "i430vx.h" +#include "i440fx.h" +#include "ide.h" +#include "intel.h" +#include "intel_flash.h" +#include "jim.h" +#include "keyboard_amstrad.h" +#include "keyboard_at.h" +#include "keyboard_olim24.h" +#include "keyboard_pcjr.h" +#include "keyboard_xt.h" +#include "lpt.h" +#include "memregs.h" +#include "mouse_ps2.h" +#include "mouse_serial.h" +#include "neat.h" +#include "nmi.h" +#include "nvr.h" +#include "olivetti_m24.h" +#include "pc87306.h" +#include "pci.h" +#include "pic.h" +#include "piix.h" +#include "pit.h" +#include "ps1.h" +#include "scat.h" +#include "serial.h" +#include "sis496.h" +#include "sis85c471.h" +#include "sio.h" +#include "sound_ps1.h" +#include "sound_pssj.h" +#include "sound_sn76489.h" +#include "tandy_eeprom.h" +#include "tandy_rom.h" +#include "um8669f.h" +// #include "um8881f.h" +#include "w83877f.h" +#include "wd76c10.h" +#include "xtide.h" + +void xt_init(); +void pcjr_init(); +void tandy1k_init(); +void tandy1ksl2_init(); +void ams_init(); +void europc_init(); +void olim24_init(); +void at_init(); +void deskpro386_init(); +void ps1_m2011_init(); +void ps1_m2121_init(); +void at_neat_init(); +void at_scat_init(); +void at_acer386sx_init(); +void at_wd76c10_init(); +void at_ali1429_init(); +void at_headland_init(); +// void at_um8881f_init(); +void at_sis496_init(); +void at_i430vx_init(); +void at_batman_init(); +void at_endeavor_init(); + +void at_dtk486_init(); +void at_r418_init(); +void at_586mc1_init(); +void at_plato_init(); +void at_mb500n_init(); +void at_p54tp4xe_init(); +void at_acerm3a_init(); +void at_acerv35n_init(); +void at_p55t2p4_init(); +void at_p55tvp4_init(); +void at_p55va_init(); +void at_i440fx_init(); +void at_kn97_init(); + +int model; + +int AMSTRAD, AT, PCI, TANDY; + +int mouse_always_serial; + +MODEL models[] = +{ + {"IBM PC", ROM_IBMPC, { "", cpus_8088, "", NULL, "", NULL}, 0, 0, 64, 640, 64, xt_init}, + {"IBM XT", ROM_IBMXT, { "", cpus_8088, "", NULL, "", NULL}, 0, 0, 128, 640, 64, xt_init}, + {"IBM PCjr", ROM_IBMPCJR, { "", cpus_pcjr, "", NULL, "", NULL}, 1, 0, 128, 640, 128, pcjr_init}, + {"Generic XT clone", ROM_GENXT, { "", cpus_8088, "", NULL, "", NULL}, 0, 0, 128, 640, 64, xt_init}, + {"AMI XT clone", ROM_AMIXT, { "", cpus_8088, "", NULL, "", NULL}, 0, 0, 128, 640, 64, xt_init}, + {"DTK XT clone", ROM_DTKXT, { "", cpus_8088, "", NULL, "", NULL}, 0, 0, 128, 640, 64, xt_init}, + {"VTech Laser Turbo XT",ROM_LTXT, { "", cpus_8088, "", NULL, "", NULL}, 0, 0, 128, 640, 64, xt_init}, + {"VTech Laser XT3", ROM_LXT3, { "", cpus_8088, "", NULL, "", NULL}, 0, 0, 128, 640, 64, xt_init}, + {"Phoenix XT clone", ROM_PXXT, { "", cpus_8088, "", NULL, "", NULL}, 0, 0, 128, 640, 64, xt_init}, + {"Juko XT clone", ROM_JUKOPC, { "", cpus_8088, "", NULL, "", NULL}, 0, 0, 128, 640, 64, xt_init}, + {"Tandy 1000", ROM_TANDY, { "", cpus_8088, "", NULL, "", NULL}, 1, 0, 128, 640, 128, tandy1k_init}, + {"Tandy 1000 HX", ROM_TANDY1000HX, { "", cpus_8088, "", NULL, "", NULL}, 1, 0, 256, 640, 128, tandy1k_init}, + {"Tandy 1000 SL/2", ROM_TANDY1000SL2,{ "", cpus_8086, "", NULL, "", NULL}, 1, 0, 512, 768, 128, tandy1ksl2_init}, + {"Amstrad PC1512", ROM_PC1512, { "", cpus_pc1512, "", NULL, "", NULL}, 1, 0, 512, 640, 128, ams_init}, + {"Sinclair PC200", ROM_PC200, { "", cpus_8086, "", NULL, "", NULL}, 1, 0, 512, 640, 128, ams_init}, + {"Euro PC", ROM_EUROPC, { "", cpus_8086, "", NULL, "", NULL}, 0, 0, 512, 640, 128, europc_init}, + {"Olivetti M24", ROM_OLIM24, { "", cpus_8086, "", NULL, "", NULL}, 1, 0, 128, 640, 128, olim24_init}, + {"Amstrad PC1640", ROM_PC1640, { "", cpus_8086, "", NULL, "", NULL}, 1, 0, 640, 640, 0, ams_init}, + {"Amstrad PC2086", ROM_PC2086, { "", cpus_8086, "", NULL, "", NULL}, 1, 0, 640, 640, 0, ams_init}, + {"Amstrad PC3086", ROM_PC3086, { "", cpus_8086, "", NULL, "", NULL}, 1, 0, 640, 640, 0, ams_init}, + {"IBM AT", ROM_IBMAT, { "", cpus_ibmat, "", NULL, "", NULL}, 0, 1, 1, 16, 1, at_init}, + {"Commodore PC 30 III", ROM_CMDPC30, { "", cpus_286, "", NULL, "", NULL}, 0, 1, 1, 16, 1, at_init}, + {"AMI 286 clone", ROM_AMI286, { "", cpus_286, "", NULL, "", NULL}, 0, 1, 1, 16, 1, at_neat_init}, + {"Award 286 clone", ROM_AWARD286, { "", cpus_286, "", NULL, "", NULL}, 0, 1, 1, 16, 1, at_scat_init}, + {"DELL System 200", ROM_DELL200, { "", cpus_286, "", NULL, "", NULL}, 0, 1, 1, 16, 1, at_init}, + {"IBM PS/1 model 2011", ROM_IBMPS1_2011, { "", cpus_ps1_m2011,"", NULL, "", NULL}, 1, 1, 1, 16, 1, ps1_m2011_init}, + {"IBM PS/1 model 2121", ROM_IBMPS1_2121, { "Intel", cpus_i386, "", NULL, "", NULL}, 1, 1, 1, 16, 1, ps1_m2121_init}, + {"Compaq Deskpro 386", ROM_DESKPRO_386, { "Intel", cpus_i386, "AMD", cpus_Am386, "Cyrix", cpus_486SDLC}, 0, 1, 1, 15, 1, deskpro386_init}, + {"Acer 386SX25/N", ROM_ACER386, { "Intel", cpus_acer, "", NULL, "", NULL}, 1, 1, 1, 16, 1, at_acer386sx_init}, + {"DTK 386SX clone", ROM_DTK386, { "Intel", cpus_i386, "AMD", cpus_Am386, "Cyrix", cpus_486SDLC}, 0, 1, 1, 16, 1, at_neat_init}, + {"Phoenix 386 clone", ROM_PX386, { "Intel", cpus_i386, "AMD", cpus_Am386, "Cyrix", cpus_486SDLC}, 0, 1, 1, 16, 1, at_init}, + {"Amstrad MegaPC", ROM_MEGAPC, { "Intel", cpus_i386, "AMD", cpus_Am386, "Cyrix", cpus_486SDLC}, 1, 1, 1, 16, 1, at_wd76c10_init}, + {"AMI 386 clone", ROM_AMI386, { "Intel", cpus_i386, "AMD", cpus_Am386, "Cyrix", cpus_486SDLC}, 0, 1, 1, 256, 1, at_headland_init}, + {"AMI 486 clone", ROM_AMI486, { "Intel", cpus_i486, "AMD", cpus_Am486, "Cyrix", cpus_Cx486}, 0, 1, 1, 256, 1, at_ali1429_init}, + {"AMI WinBIOS 486", ROM_WIN486, { "Intel", cpus_i486, "AMD", cpus_Am486, "Cyrix", cpus_Cx486}, 0, 1, 1, 256, 1, at_ali1429_init}, +/* {"AMI WinBIOS 486 PCI", ROM_PCI486, { "Intel", cpus_i486, "AMD", cpus_Am486, "Cyrix", cpus_Cx486}, 0, 1, 1, 256, 1, at_um8881f_init},*/ + {"DTK PKM-0038S E-2", ROM_DTK486, { "Intel", cpus_i486, "AMD", cpus_Am486, "Cyrix", cpus_Cx486}, 0, 1, 1, 256, 1, at_dtk486_init}, + {"Award SiS 496/497", ROM_SIS496, { "Intel", cpus_i486, "AMD", cpus_Am486, "Cyrix", cpus_Cx486}, 0, 1, 1, 256, 1, at_sis496_init}, + {"Rise Computer R418", ROM_R418, { "Intel", cpus_i486, "AMD", cpus_Am486, "Cyrix", cpus_Cx486}, 0, 1, 1, 256, 1, at_r418_init}, + {"Intel Premiere/PCI", ROM_REVENGE, { "Intel", cpus_Pentium5V, "", NULL, "", NULL}, 0, 1, 1, 128, 1, at_batman_init}, + {"Micro Star 586MC1", ROM_586MC1, { "Intel", cpus_Pentium5V50, "",NULL, "", NULL}, 0, 1, 1, 128, 1, at_586mc1_init}, + {"Intel Premiere/PCI II",ROM_PLATO, { "Intel", cpus_PentiumS5,"IDT", cpus_WinChip, "AMD", cpus_K5, "", NULL}, 0, 1, 1, 128, 1, at_plato_init}, + {"Intel Advanced/EV", ROM_ENDEAVOR, { "Intel", cpus_PentiumS5,"IDT", cpus_WinChip, "AMD", cpus_K5, "", NULL}, 0, 1, 1, 128, 1, at_endeavor_init}, + {"PC Partner MB500N", ROM_MB500N, { "Intel", cpus_PentiumS5,"IDT", cpus_WinChip, "AMD", cpus_K5, "", NULL}, 0, 1, 1, 128, 1, at_mb500n_init}, + {"ASUS P/I-P54TP4XE", ROM_P54TP4XE, { "Intel", cpus_PentiumS5, "IDT", cpus_WinChip, "AMD", cpus_K5, "", NULL}, 0, 1, 1, 512, 1, at_p54tp4xe_init}, + {"Acer M3a", ROM_ACERM3A, { "Intel", cpus_Pentium, "IDT", cpus_WinChip, "Cyrix", cpus_6x86, "AMD", cpus_K56, "", NULL}, 0, 1, 1, 512, 1, at_acerm3a_init}, + {"Acer V35N", ROM_ACERV35N, { "Intel", cpus_Pentium, "IDT", cpus_WinChip, "Cyrix", cpus_6x86, "AMD", cpus_K56, "", NULL}, 0, 1, 1, 512, 1, at_acerv35n_init}, + {"ASUS P/I-P55T2P4", ROM_P55T2P4, { "Intel", cpus_Pentium, "IDT", cpus_WinChip, "Cyrix", cpus_6x86, "AMD", cpus_K56, "", NULL}, 0, 1, 1, 512, 1, at_p55t2p4_init}, + {"Award 430VX PCI", ROM_430VX, { "Intel", cpus_Pentium, "IDT", cpus_WinChip, "Cyrix", cpus_6x86, "AMD", cpus_K56, "", NULL}, 0, 1, 1, 256, 1, at_i430vx_init}, + {"ASUS P/I-P55TVP4", ROM_P55TVP4, { "Intel", cpus_Pentium, "IDT", cpus_WinChip, "Cyrix", cpus_6x86, "AMD", cpus_K56, "", NULL}, 0, 1, 1, 512, 1, at_p55tvp4_init}, + {"Epox P55-VA", ROM_P55VA, { "Intel", cpus_Pentium, "IDT", cpus_WinChip, "Cyrix", cpus_6x86, "AMD", cpus_K56, "", NULL}, 0, 1, 1, 256, 1, at_p55va_init}, + {"Award 440FX PCI", ROM_440FX, { "Intel", cpus_PentiumPro,"Klamath", cpus_Pentium2, "Deschutes", cpus_Pentium2D}, 0, 1, 1, 1024, 1, at_i440fx_init}, + {"Award KN97 (440FX PCI)",ROM_KN97, { "Intel", cpus_PentiumPro,"Klamath", cpus_Pentium2, "Deschutes", cpus_Pentium2D}, 0, 1, 1, 1024, 1, at_kn97_init}, + {"", -1, {"", 0, "", 0, "", 0}, 0,0,0, 0} +}; + +int model_count() +{ + return (sizeof(models) / sizeof(MODEL)) - 1; +} + +int model_getromset() +{ + return models[model].id; +} + +int model_getmodel(int romset) +{ + int c = 0; + + while (models[c].id != -1) + { + if (models[c].id == romset) + return c; + c++; + } + + return 0; +} + +char *model_getname() +{ + return models[model].name; +} + +void common_init() +{ + dma_init(); + fdc_add(); + lpt_init(); + pic_init(); + pit_init(); + serial1_init(0x3f8, 4); + serial2_init(0x2f8, 3); +} + +void xt_init() +{ + common_init(); + mem_add_bios(); + pit_set_out_func(1, pit_refresh_timer_xt); + keyboard_xt_init(); + mouse_serial_init(); + xtide_init(); + nmi_init(); + device_add(&gameport_device); +} + +void pcjr_init() +{ + mem_add_bios(); + fdc_add_pcjr(); + pic_init(); + pit_init(); + pit_set_out_func(0, pit_irq0_timer_pcjr); + serial1_init(0x2f8, 3); + keyboard_pcjr_init(); + device_add(&sn76489_device); + nmi_mask = 0x80; +} + +void tandy1k_init() +{ + TANDY = 1; + common_init(); + mem_add_bios(); + keyboard_tandy_init(); + mouse_serial_init(); + if (romset == ROM_TANDY) + device_add(&sn76489_device); + else + device_add(&ncr8496_device); + xtide_init(); + nmi_init(); + if (romset != ROM_TANDY) + device_add(&tandy_eeprom_device); + device_add(&gameport_device); +} +void tandy1ksl2_init() +{ +// TANDY = 1; + common_init(); + mem_add_bios(); + keyboard_tandy_init(); + mouse_serial_init(); + device_add(&pssj_device); + xtide_init(); + nmi_init(); + device_add(&tandy_rom_device); + device_add(&tandy_eeprom_device); + device_add(&gameport_device); +} + +void ams_init() +{ + AMSTRAD = 1; + common_init(); + mem_add_bios(); + amstrad_init(); + keyboard_amstrad_init(); + nvr_init(); + xtide_init(); + nmi_init(); + fdc_set_dskchg_activelow(); + device_add(&gameport_device); +} + +void europc_init() +{ + common_init(); + mem_add_bios(); + jim_init(); + keyboard_xt_init(); + mouse_serial_init(); + xtide_init(); + nmi_init(); + device_add(&gameport_device); +} + +void olim24_init() +{ + common_init(); + mem_add_bios(); + keyboard_olim24_init(); + nvr_init(); + olivetti_m24_init(); + xtide_init(); + nmi_init(); + device_add(&gameport_device); +} + +void at_init() +{ + AT = 1; + common_init(); + lpt2_remove(); + mem_add_bios(); + pit_set_out_func(1, pit_refresh_timer_at); + dma16_init(); + ide_init(); + keyboard_at_init(); + if (models[model].init == at_init) + mouse_serial_init(); + nvr_init(); + pic2_init(); + device_add(&gameport_device); +} + +void deskpro386_init() +{ + at_init(); + mouse_serial_init(); + compaq_init(); +} + +void ps1_common_init() +{ + AT = 1; + common_init(); + mem_add_bios(); + pit_set_out_func(1, pit_refresh_timer_at); + dma16_init(); + ide_init(); + keyboard_at_init(); + mouse_ps2_init(); + nvr_init(); + pic2_init(); + fdc_set_dskchg_activelow(); + device_add(&ps1_audio_device); + /*PS/1 audio uses ports 200h and 202-207h, so only initialise gameport on 201h*/ + device_add(&gameport_201_device); +} + +void ps1_m2011_init() +{ + ps1_common_init(); + ps1mb_init(); +} + +void ps1_m2121_init() +{ + ps1_common_init(); + ps1mb_m2121_init(); + fdc_set_ps1(); +} + +void at_neat_init() +{ + at_init(); + mouse_serial_init(); + neat_init(); +} + +void at_scat_init() +{ + at_init(); + mouse_serial_init(); + scat_init(); +} + +void at_acer386sx_init() +{ + at_init(); + mouse_ps2_init(); + acer386sx_init(); +} + +void at_wd76c10_init() +{ + at_init(); + mouse_ps2_init(); + wd76c10_init(); +} + +void at_headland_init() +{ + at_init(); + headland_init(); + mouse_serial_init(); +} + +void at_ali1429_init() +{ + at_init(); + ali1429_init(); + mouse_serial_init(); + if (cdrom_channel <= 1) ide_sec_disable(); +} + +/* void at_um8881f_init() +{ + at_init(); + mouse_serial_init(); + pci_init(PCI_CONFIG_TYPE_1, 0, 31); + um8881f_init(); +} */ + +void at_dtk486_init() +{ + at_init(); + memregs_init(); + mouse_serial_init(); + sis85c471_init(); + if (cdrom_channel <= 1) ide_sec_disable(); +} + +void at_sis496_init() +{ + at_init(); + memregs_init(); + mouse_serial_init(); + pci_init(PCI_CONFIG_TYPE_1, 0, 31); + device_add(&sis496_device); + ide_ter_init(); +} + +void at_r418_init() +{ + at_init(); + memregs_init(); + mouse_serial_init(); + pci_init(PCI_CONFIG_TYPE_1, 0, 31); + fdc37c665_init(); + device_add(&sis496_device); + if (cdrom_channel >= 4) ide_ter_init(); +} + +void at_batman_init() +{ + at_init(); + mouse_always_serial ? mouse_serial_init() : mouse_ps2_init(); + pci_init(PCI_CONFIG_TYPE_2, 0xd, 0x10); + i430lx_init(); + sio_init(1); + fdc37c665_init(); + intel_batman_init(); + if (cdrom_channel >= 4) ide_ter_init(); +} + +void at_586mc1_init() +{ + at_init(); + memregs_init(); + mouse_serial_init(); + pci_init(PCI_CONFIG_TYPE_2, 0xd, 0x10); + i430lx_init(); + sio_init(1); + device_add(&intel_flash_bxt_device); + if (cdrom_channel <= 1) ide_sec_disable(); +} + +void at_plato_init() +{ + at_init(); + mouse_always_serial ? mouse_serial_init() : mouse_ps2_init(); + pci_init(PCI_CONFIG_TYPE_2, 0xd, 0x10); + i430nx_init(); + sio_init(1); + fdc37c665_init(); + /* It seems it uses the same interface as Batman. */ + intel_batman_init(); + // device_add(&intel_flash_bxt_ami_device); + if (cdrom_channel >= 4) ide_ter_init(); +} + +void at_endeavor_init() +{ + at_init(); + mouse_always_serial ? mouse_serial_init() : mouse_ps2_init(); + pci_init(PCI_CONFIG_TYPE_1, 0xd, 0x10); + i430fx_init(); + piix_init(7); + pc87306_init(); + intel_endeavor_init(); + device_add(&intel_flash_bxt_ami_device); + if (cdrom_channel >= 4) ide_ter_init(); +} + +void at_mb500n_init() +{ + at_init(); + mouse_serial_init(); + pci_init(PCI_CONFIG_TYPE_1, 0xd, 0x10); + i430fx_init(); + piix_init(7); + fdc37c665_init(); + intel_endeavor_init(); + device_add(&intel_flash_bxt_device); + if (cdrom_channel >= 4) ide_ter_init(); +} + +void at_p54tp4xe_init() +{ + at_init(); + mouse_always_serial ? mouse_serial_init() : mouse_ps2_init(); + pci_init(PCI_CONFIG_TYPE_1, 0xd, 0x10); + i430fx_init(); + piix_init(7); + fdc37c665_init(); + intel_endeavor_init(); + device_add(&intel_flash_bxt_device); + if (cdrom_channel >= 4) ide_ter_init(); +} + +void at_acerm3a_init() +{ + at_init(); + mouse_serial_init(); + pci_init(PCI_CONFIG_TYPE_1, 0xd, 0x10); + i430hx_init(); + piix3_init(7); + fdc37c932fr_init(); + acerm3a_io_init(); + device_add(&intel_flash_bxb_device); + if (cdrom_channel >= 4) ide_ter_init(); +} + +void at_acerv35n_init() +{ + at_init(); + mouse_always_serial ? mouse_serial_init() : mouse_ps2_init(); + pci_init(PCI_CONFIG_TYPE_1, 0xd, 0x10); + i430hx_init(); + piix3_init(7); + fdc37c932fr_init(); + acerm3a_io_init(); + device_add(&intel_flash_bxb_device); + if (cdrom_channel >= 4) ide_ter_init(); +} + +void at_p55t2p4_init() +{ + at_init(); + mouse_always_serial ? mouse_serial_init() : mouse_ps2_init(); + pci_init(PCI_CONFIG_TYPE_1, 0, 31); + i430hx_init(); + piix3_init(7); + w83877f_init(); + device_add(&intel_flash_bxt_device); + if (cdrom_channel >= 4) ide_ter_init(); +} + +void at_i430vx_init() +{ + at_init(); + mouse_serial_init(); + pci_init(PCI_CONFIG_TYPE_1, 0, 31); + i430vx_init(); + piix3_init(7); + um8669f_init(); + device_add(&intel_flash_bxt_device); + if (cdrom_channel >= 4) ide_ter_init(); +} + +void at_p55tvp4_init() +{ + at_init(); + mouse_always_serial ? mouse_serial_init() : mouse_ps2_init(); + pci_init(PCI_CONFIG_TYPE_1, 0, 31); + i430vx_init(); + piix3_init(7); + w83877f_init(); + device_add(&intel_flash_bxt_device); + if (cdrom_channel >= 4) ide_ter_init(); +} + +void at_p55va_init() +{ + at_init(); + mouse_always_serial ? mouse_serial_init() : mouse_ps2_init(); + pci_init(PCI_CONFIG_TYPE_1, 0, 31); + i430vx_init(); + piix3_init(7); + fdc37c932fr_init(); + device_add(&intel_flash_bxt_device); + if (cdrom_channel >= 4) ide_ter_init(); +} + +void at_i440fx_init() +{ + at_init(); + mouse_ps2_init(); + pci_init(PCI_CONFIG_TYPE_1, 0, 31); + i440fx_init(); + piix3_init(7); + fdc37c665_init(); + device_add(&intel_flash_bxt_device); + if (cdrom_channel >= 4) ide_ter_init(); +} + +void at_kn97_init() +{ + at_init(); + mouse_ps2_init(); + pci_init(PCI_CONFIG_TYPE_1, 0, 31); + i440fx_init(); + piix3_init(7); + w83877f_init(); + device_add(&intel_flash_bxt_device); + if (cdrom_channel >= 4) ide_ter_init(); +} + +void model_init() +{ + pclog("Initting as %s\n", model_getname()); + AMSTRAD = AT = PCI = TANDY = 0; + io_init(); + + fdc_update_is_nsc(0); + models[model].init(); +} diff --git a/src/model.h b/src/model.h new file mode 100644 index 000000000..ce5d6a2b8 --- /dev/null +++ b/src/model.h @@ -0,0 +1,25 @@ +typedef struct +{ + char name[24]; + int id; + struct + { + char name[16]; + CPU *cpus; + } cpu[5]; + int fixed_gfxcard; + int is_at; + int min_ram, max_ram; + int ram_granularity; + void (*init)(); +} MODEL; + +extern MODEL models[]; + +extern int model; + +int model_count(); +int model_getromset(); +int model_getmodel(int romset); +char *model_getname(); +void model_init(); diff --git a/src/mouse.c b/src/mouse.c new file mode 100644 index 000000000..32c49ed0b --- /dev/null +++ b/src/mouse.c @@ -0,0 +1,4 @@ +#include "ibm.h" +#include "mouse.h" + +void (*mouse_poll)(int x, int y, int b); diff --git a/src/mouse.h b/src/mouse.h new file mode 100644 index 000000000..04f17a6d7 --- /dev/null +++ b/src/mouse.h @@ -0,0 +1,5 @@ +extern void (*mouse_poll)(int x, int y, int b); + +extern int mousepos; +extern int mousedelay; + diff --git a/src/mouse_ps2.c b/src/mouse_ps2.c new file mode 100644 index 000000000..e5cd3d670 --- /dev/null +++ b/src/mouse_ps2.c @@ -0,0 +1,189 @@ +#include "ibm.h" +#include "keyboard_at.h" +#include "mouse.h" +#include "mouse_ps2.h" +#include "plat-mouse.h" + +int mouse_scan = 0; + +enum +{ + MOUSE_STREAM, + MOUSE_REMOTE, + MOUSE_ECHO +}; + +#define MOUSE_ENABLE 0x20 +#define MOUSE_SCALE 0x10 + +static struct +{ + int mode; + + uint8_t flags; + uint8_t resolution; + uint8_t sample_rate; + uint8_t type; + + uint8_t command; + + int cd; +} mouse_ps2; + +void mouse_ps2_write(uint8_t val) +{ + // pclog("PS/2 Mouse: Write %02X\n", val); + + if (mouse_ps2.cd) + { + mouse_ps2.cd = 0; + switch (mouse_ps2.command) + { + case 0xe8: /*Set mouse resolution*/ + mouse_ps2.resolution = val; + keyboard_at_adddata_mouse(0xfa); + break; + + case 0xf3: /*Set sample rate*/ + mouse_ps2.sample_rate = val; + keyboard_at_adddata_mouse(0xfa); + break; + +// default: +// fatal("mouse_ps2 : Bad data write %02X for command %02X\n", val, mouse_ps2.command); + } + } + else + { + uint8_t temp; + + mouse_ps2.command = val; + switch (mouse_ps2.command) + { + case 0xe6: /*Set scaling to 1:1*/ + mouse_ps2.flags &= ~MOUSE_SCALE; + keyboard_at_adddata_mouse(0xfa); + break; + + case 0xe7: /*Set scaling to 2:1*/ + mouse_ps2.flags |= MOUSE_SCALE; + keyboard_at_adddata_mouse(0xfa); + break; + + case 0xe8: /*Set mouse resolution*/ + mouse_ps2.cd = 1; + keyboard_at_adddata_mouse(0xfa); + break; + + case 0xe9: /*Status request*/ + keyboard_at_adddata_mouse(0xfa); + temp = mouse_ps2.flags; + if (mouse_buttons & 1) + temp |= 1; + if (mouse_buttons & 2) + temp |= 2; + if (mouse_buttons & 4) + temp |= 3; + keyboard_at_adddata_mouse(temp); + keyboard_at_adddata_mouse(mouse_ps2.resolution); + keyboard_at_adddata_mouse(mouse_ps2.sample_rate); + break; + + case 0xf2: /*Read ID*/ + keyboard_at_adddata_mouse(0xfa); + keyboard_at_adddata_mouse(0x00); + break; + + case 0xf3: /*Set sample rate*/ + mouse_ps2.cd = 1; + keyboard_at_adddata_mouse(0xfa); + break; + + case 0xf4: /*Enable*/ + mouse_ps2.flags |= MOUSE_ENABLE; + keyboard_at_adddata_mouse(0xfa); + break; + + case 0xf5: /*Disable*/ + mouse_ps2.flags &= ~MOUSE_ENABLE; + keyboard_at_adddata_mouse(0xfa); + break; + + case 0xff: /*Reset*/ + mouse_ps2.mode = MOUSE_STREAM; + mouse_ps2.flags = 0; + keyboard_at_adddata_mouse(0xfa); + keyboard_at_adddata_mouse(0xaa); + keyboard_at_adddata_mouse(0x00); + break; + +// default: +// fatal("mouse_ps2 : Bad command %02X\n", val, mouse_ps2.command); + } + } +} + +static int ps2_x = 0, ps2_y = 0, ps2_b = 0; +int first_time = 1; +void mouse_ps2_poll(int x, int y, int b) +{ + uint8_t packet[3] = {0x08, 0, 0}; + if (!x && !y && b == ps2_b && !first_time){ + // pclog("PS/2 Mouse: X is 0, Y is 0, and B is PS2_B\n"); + return; + } + + if (first_time) first_time = 0; + + if (!mouse_scan) + { + // pclog("PS/2 Mouse: Not scanning\n"); + return; + } + ps2_x += x; + ps2_y -= y; + if (mouse_ps2.mode == MOUSE_STREAM && (mouse_ps2.flags & MOUSE_ENABLE) && + ((mouse_queue_end - mouse_queue_start) & 0xf) < 13) + { + ps2_b = b; + // pclog("Send packet : %i %i\n", ps2_x, ps2_y); + if (ps2_x > 255) + ps2_x = 255; + if (ps2_x < -256) + ps2_x = -256; + if (ps2_y > 255) + ps2_y = 255; + if (ps2_y < -256) + ps2_y = -256; + if (ps2_x < 0) + packet[0] |= 0x10; + if (ps2_y < 0) + packet[0] |= 0x20; + if (mouse_buttons & 1) + packet[0] |= 1; + if (mouse_buttons & 2) + packet[0] |= 2; + if (mouse_buttons & 4) + packet[0] |= 4; + packet[1] = ps2_x & 0xff; + packet[2] = ps2_y & 0xff; + + ps2_x = ps2_y = 0; + + keyboard_at_adddata_mouse(packet[0]); + keyboard_at_adddata_mouse(packet[1]); + keyboard_at_adddata_mouse(packet[2]); + } + + // pclog("PS/2 Mouse: Poll\n"); +} + + +void mouse_ps2_init() +{ + mouse_poll = mouse_ps2_poll; + mouse_write = mouse_ps2_write; + mouse_ps2.cd = 0; + mouse_ps2.flags = 0; + mouse_ps2.mode = MOUSE_STREAM; +} diff --git a/src/mouse_ps2.h b/src/mouse_ps2.h new file mode 100644 index 000000000..95294df35 --- /dev/null +++ b/src/mouse_ps2.h @@ -0,0 +1 @@ +void mouse_ps2_init(); diff --git a/src/mouse_serial.c b/src/mouse_serial.c new file mode 100644 index 000000000..b5eeb1547 --- /dev/null +++ b/src/mouse_serial.c @@ -0,0 +1,72 @@ +#include "ibm.h" +#include "mouse.h" +#include "pic.h" +#include "serial.h" +#include "timer.h" + +static int oldb=0; + +void mouse_serial_poll(int x, int y, int b) +{ + uint8_t mousedat[3]; + + if (!(serial1.ier & 1)) + return; + if (!x && !y && b==oldb) return; + + oldb=b; + if (x>127) x=127; + if (y>127) y=127; + if (x<-128) x=-128; + if (y<-128) y=-128; + + /*Use Microsoft format*/ + mousedat[0]=0x40; + mousedat[0]|=(((y>>6)&3)<<2); + mousedat[0]|=((x>>6)&3); + if (b&1) mousedat[0]|=0x20; + if (b&2) mousedat[0]|=0x10; + mousedat[1]=x&0x3F; + mousedat[2]=y&0x3F; + + if (!(serial1.mctrl&0x10)) + { + pclog("Serial data %02X %02X %02X\n", mousedat[0], mousedat[1], mousedat[2]); + serial_write_fifo(&serial1, mousedat[0]); + serial_write_fifo(&serial1, mousedat[1]); + serial_write_fifo(&serial1, mousedat[2]); + } +} + +void mouse_serial_rcr(void *p) +{ + mousepos=-1; + mousedelay=5000 * (1 << TIMER_SHIFT); +} + +void mousecallback(void *p) +{ + SERIAL *serial = (SERIAL *)p; + mousedelay = 0; + if (mousepos == -1) + { + mousepos = 0; +/* serial_fifo_read = serial_fifo_write = 0; + serial.lsr &= ~1;*/ + serial_write_fifo(serial, 'M'); + } +/* else if (serial_fifo_read != serial_fifo_write) + { + serial.iir=4; + serial.lsr|=1; + if (serial.mctrl&8) picint(0x10); + }*/ +} + +void mouse_serial_init() +{ + mouse_poll = mouse_serial_poll; + serial1.rcr_callback = mouse_serial_rcr; + timer_add(mousecallback, &mousedelay, &mousedelay, &serial1); +} + diff --git a/src/mouse_serial.h b/src/mouse_serial.h new file mode 100644 index 000000000..22b7f3830 --- /dev/null +++ b/src/mouse_serial.h @@ -0,0 +1 @@ +void mouse_serial_init(); diff --git a/src/ne2000.c b/src/ne2000.c new file mode 100644 index 000000000..24321ae22 --- /dev/null +++ b/src/ne2000.c @@ -0,0 +1,2128 @@ +///////////////////////////////////////////////////////////////////////// +// $Id: ne2k.cc,v 1.56.2.1 2004/02/02 22:37:22 cbothamy Exp $ +///////////////////////////////////////////////////////////////////////// +// +// Copyright (C) 2002 MandrakeSoft S.A. +// +// MandrakeSoft S.A. +// 43, rue d'Aboukir +// 75002 Paris - France +// http://www.linux-mandrake.com/ +// http://www.mandrakesoft.com/ +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +// Peter Grehan (grehan@iprg.nokia.com) coded all of this +// NE2000/ether stuff. +//#include "vl.h" +#include +#include +#include +#include + +#include "slirp/slirp.h" +#include "slirp/queue.h" +#include + +#include "ibm.h" +#include "device.h" + +#include "nethandler.h" + +#include "io.h" +#include "mem.h" +#include "nethandler.h" +#include "rom.h" + +#include "ne2000.h" +#include "pci.h" +#include "pic.h" +#include "timer.h" + +//THIS IS THE DEFAULT MAC ADDRESS .... so it wont place nice with multiple VMs. YET. +uint8_t maclocal[6] = {0xac, 0xde, 0x48, 0x88, 0xbb, 0xaa}; + +#define NETBLOCKING 0 //we won't block our pcap + +static HINSTANCE net_hLib = 0; /* handle to DLL */ +static char* net_lib_name = "wpcap.dll"; +pcap_t *net_pcap; +typedef pcap_t* (__cdecl * PCAP_OPEN_LIVE)(const char *, int, int, int, char *); +typedef int (__cdecl * PCAP_SENDPACKET)(pcap_t* handle, const u_char* msg, int len); +typedef int (__cdecl * PCAP_SETNONBLOCK)(pcap_t *, int, char *); +typedef const u_char*(__cdecl *PCAP_NEXT)(pcap_t *, struct pcap_pkthdr *); +typedef const char*(__cdecl *PCAP_LIB_VERSION)(void); +typedef void (__cdecl *PCAP_CLOSE)(pcap_t *); +typedef int (__cdecl *PCAP_GETNONBLOCK)(pcap_t *p, char *errbuf); +typedef int (__cdecl *PCAP_COMPILE)(pcap_t *p, struct bpf_program *fp, const char *str, int optimize, bpf_u_int32 netmask); +typedef int (__cdecl *PCAP_SETFILTER)(pcap_t *p, struct bpf_program *fp); + +PCAP_LIB_VERSION _pcap_lib_version; +PCAP_OPEN_LIVE _pcap_open_live; +PCAP_SENDPACKET _pcap_sendpacket; +PCAP_SETNONBLOCK _pcap_setnonblock; +PCAP_NEXT _pcap_next; +PCAP_CLOSE _pcap_close; +PCAP_GETNONBLOCK _pcap_getnonblock; +PCAP_COMPILE _pcap_compile; +PCAP_SETFILTER _pcap_setfilter; + +queueADT slirpq; +int net_slirp_inited=0; +int net_is_slirp=1; //by default we go with slirp +int net_is_pcap=0; //and pretend pcap is dead. +int fizz=0; +void slirp_tic(); + +#define BX_RESET_HARDWARE 0 +#define BX_RESET_SOFTWARE 1 + +//Never completely fill the ne2k ring so that we never +// hit the unclear completely full buffer condition. +#define BX_NE2K_NEVER_FULL_RING (1) + +#define BX_NE2K_MEMSIZ (32*1024) +#define BX_NE2K_MEMSTART (16*1024) +#define BX_NE2K_MEMEND (BX_NE2K_MEMSTART + BX_NE2K_MEMSIZ) + +uint8_t rtl8029as_eeprom[128]; + +typedef struct ne2000_t +{ + // + // ne2k register state + + // + // Page 0 + // + // Command Register - 00h read/write + struct CR_t { + int stop; // STP - Software Reset command + int start; // START - start the NIC + int tx_packet; // TXP - initiate packet transmission + uint8_t rdma_cmd; // RD0,RD1,RD2 - Remote DMA command + uint8_t pgsel; // PS0,PS1 - Page select + } CR; + // Interrupt Status Register - 07h read/write + struct ISR_t { + int pkt_rx; // PRX - packet received with no errors + int pkt_tx; // PTX - packet transmitted with no errors + int rx_err; // RXE - packet received with 1 or more errors + int tx_err; // TXE - packet tx'd " " " " " + int overwrite; // OVW - rx buffer resources exhausted + int cnt_oflow; // CNT - network tally counter MSB's set + int rdma_done; // RDC - remote DMA complete + int reset; // RST - reset status + } ISR; + // Interrupt Mask Register - 0fh write + struct IMR_t { + int rx_inte; // PRXE - packet rx interrupt enable + int tx_inte; // PTXE - packet tx interrput enable + int rxerr_inte; // RXEE - rx error interrupt enable + int txerr_inte; // TXEE - tx error interrupt enable + int overw_inte; // OVWE - overwrite warn int enable + int cofl_inte; // CNTE - counter o'flow int enable + int rdma_inte; // RDCE - remote DMA complete int enable + int reserved; // D7 - reserved + } IMR; + // Data Configuration Register - 0eh write + struct DCR_t { + int wdsize; // WTS - 8/16-bit select + int endian; // BOS - byte-order select + int longaddr; // LAS - long-address select + int loop; // LS - loopback select + int auto_rx; // AR - auto-remove rx packets with remote DMA + uint8_t fifo_size; // FT0,FT1 - fifo threshold + } DCR; + // Transmit Configuration Register - 0dh write + struct TCR_t { + int crc_disable; // CRC - inhibit tx CRC + uint8_t loop_cntl; // LB0,LB1 - loopback control + int ext_stoptx; // ATD - allow tx disable by external mcast + int coll_prio; // OFST - backoff algorithm select + uint8_t reserved; // D5,D6,D7 - reserved + } TCR; + // Transmit Status Register - 04h read + struct TSR_t { + int tx_ok; // PTX - tx complete without error + int reserved; // D1 - reserved + int collided; // COL - tx collided >= 1 times + int aborted; // ABT - aborted due to excessive collisions + int no_carrier; // CRS - carrier-sense lost + int fifo_ur; // FU - FIFO underrun + int cd_hbeat; // CDH - no tx cd-heartbeat from transceiver + int ow_coll; // OWC - out-of-window collision + } TSR; + // Receive Configuration Register - 0ch write + struct RCR_t { + int errors_ok; // SEP - accept pkts with rx errors + int runts_ok; // AR - accept < 64-byte runts + int broadcast; // AB - accept eth broadcast address + int multicast; // AM - check mcast hash array + int promisc; // PRO - accept all packets + int monitor; // MON - check pkts, but don't rx + uint8_t reserved; // D6,D7 - reserved + } RCR; + // Receive Status Register - 0ch read + struct RSR_t { + int rx_ok; // PRX - rx complete without error + int bad_crc; // CRC - Bad CRC detected + int bad_falign; // FAE - frame alignment error + int fifo_or; // FO - FIFO overrun + int rx_missed; // MPA - missed packet error + int rx_mbit; // PHY - unicast or mcast/bcast address match + int rx_disabled; // DIS - set when in monitor mode + int deferred; // DFR - collision active + } RSR; + + uint16_t local_dma; // 01,02h read ; current local DMA addr + uint8_t page_start; // 01h write ; page start register + uint8_t page_stop; // 02h write ; page stop register + uint8_t bound_ptr; // 03h read/write ; boundary pointer + uint8_t tx_page_start; // 04h write ; transmit page start register + uint8_t num_coll; // 05h read ; number-of-collisions register + uint16_t tx_bytes; // 05,06h write ; transmit byte-count register + uint8_t fifo; // 06h read ; FIFO + uint16_t remote_dma; // 08,09h read ; current remote DMA addr + uint16_t remote_start; // 08,09h write ; remote start address register + uint16_t remote_bytes; // 0a,0bh write ; remote byte-count register + uint8_t tallycnt_0; // 0dh read ; tally counter 0 (frame align errors) + uint8_t tallycnt_1; // 0eh read ; tally counter 1 (CRC errors) + uint8_t tallycnt_2; // 0fh read ; tally counter 2 (missed pkt errors) + + uint8_t i8029id0; + uint8_t i8029id1; + + // + // Page 1 + // + // Command Register 00h (repeated) + // + uint8_t physaddr[6]; // 01-06h read/write ; MAC address + uint8_t curr_page; // 07h read/write ; current page register + uint8_t mchash[8]; // 08-0fh read/write ; multicast hash array + + // + // Page 2 - diagnostic use only + // + // Command Register 00h (repeated) + // + // Page Start Register 01h read (repeated) + // Page Stop Register 02h read (repeated) + // Current Local DMA Address 01,02h write (repeated) + // Transmit Page start address 04h read (repeated) + // Receive Configuration Register 0ch read (repeated) + // Transmit Configuration Register 0dh read (repeated) + // Data Configuration Register 0eh read (repeated) + // Interrupt Mask Register 0fh read (repeated) + // + uint8_t rempkt_ptr; // 03h read/write ; remote next-packet pointer + uint8_t localpkt_ptr; // 05h read/write ; local next-packet pointer + uint16_t address_cnt; // 06,07h read/write ; address counter + + // + // Page 3 - should never be modified. + // + uint8_t cr; + uint8_t i9346cr; + uint8_t config0; + uint8_t config2; + uint8_t config3; + uint8_t hltclk; + uint8_t i8029asid0; + uint8_t i8029asid1; + + // Novell ASIC state + uint8_t macaddr[32]; // ASIC ROM'd MAC address, even bytes + uint8_t mem[BX_NE2K_MEMSIZ]; // on-chip packet memory + + // ne2k internal state + uint32_t base_address; + int base_irq; + int tx_timer_index; + int tx_timer_active; + + rom_t bios_rom; + +} ne2000_t; + +int disable_netbios = 0; + +static void ne2000_tx_event(int val, void *p); + +void ne2000_rx_frame(void *p, const void *buf, int io_len); + +static void ne2000_setirq(ne2000_t *ne2000, int irq) +{ + ne2000->base_irq = irq; +} +// +// reset - restore state to power-up, cancelling all i/o +// +static void ne2000_reset(int type, void *p) +{ + ne2000_t *ne2000 = (ne2000_t *)p; + + pclog("ne2000 reset\n"); + + int i; + + // Initialise the mac address area by doubling the physical address + ne2000->macaddr[0] = ne2000->physaddr[0]; + ne2000->macaddr[1] = ne2000->physaddr[0]; + ne2000->macaddr[2] = ne2000->physaddr[1]; + ne2000->macaddr[3] = ne2000->physaddr[1]; + ne2000->macaddr[4] = ne2000->physaddr[2]; + ne2000->macaddr[5] = ne2000->physaddr[2]; + ne2000->macaddr[6] = ne2000->physaddr[3]; + ne2000->macaddr[7] = ne2000->physaddr[3]; + ne2000->macaddr[8] = ne2000->physaddr[4]; + ne2000->macaddr[9] = ne2000->physaddr[4]; + ne2000->macaddr[10] = ne2000->physaddr[5]; + ne2000->macaddr[11] = ne2000->physaddr[5]; + + // ne2k signature + for (i = 12; i < 32; i++) + ne2000->macaddr[i] = 0x57; + + // Zero out registers and memory + memset( & ne2000->CR, 0, sizeof(ne2000->CR) ); + memset( & ne2000->ISR, 0, sizeof(ne2000->ISR)); + memset( & ne2000->IMR, 0, sizeof(ne2000->IMR)); + memset( & ne2000->DCR, 0, sizeof(ne2000->DCR)); + memset( & ne2000->TCR, 0, sizeof(ne2000->TCR)); + memset( & ne2000->TSR, 0, sizeof(ne2000->TSR)); + //memset( & ne2000->RCR, 0, sizeof(ne2000->RCR)); + memset( & ne2000->RSR, 0, sizeof(ne2000->RSR)); + ne2000->tx_timer_active = 0; + ne2000->local_dma = 0; + ne2000->page_start = 0; + ne2000->page_stop = 0; + ne2000->bound_ptr = 0; + ne2000->tx_page_start = 0; + ne2000->num_coll = 0; + ne2000->tx_bytes = 0; + ne2000->fifo = 0; + ne2000->remote_dma = 0; + ne2000->remote_start = 0; + ne2000->remote_bytes = 0; + ne2000->tallycnt_0 = 0; + ne2000->tallycnt_1 = 0; + ne2000->tallycnt_2 = 0; + + //memset( & ne2000->physaddr, 0, sizeof(ne2000->physaddr)); + //memset( & ne2000->mchash, 0, sizeof(ne2000->mchash)); + ne2000->curr_page = 0; + + ne2000->rempkt_ptr = 0; + ne2000->localpkt_ptr = 0; + ne2000->address_cnt = 0; + + memset( & ne2000->mem, 0, sizeof(ne2000->mem)); + + // Set power-up conditions + ne2000->CR.stop = 1; + ne2000->CR.rdma_cmd = 4; + ne2000->ISR.reset = 1; + ne2000->DCR.longaddr = 1; + picint(1 << ne2000->base_irq); + picintc(1 << ne2000->base_irq); + //DEV_pic_lower_irq(ne2000->base_irq); +} + +#include "bswap.h" + +// +// chipmem_read/chipmem_write - access the 64K private RAM. +// The ne2000 memory is accessed through the data port of +// the asic (offset 0) after setting up a remote-DMA transfer. +// Both byte and word accesses are allowed. +// The first 16 bytes contains the MAC address at even locations, +// and there is 16K of buffer memory starting at 16K +// +static inline uint8_t ne2000_chipmem_read_b(uint32_t address, ne2000_t *ne2000) +{ + // ROM'd MAC address +if ((address >=0) && (address <= 31)) { + return ne2000->macaddr[address]; + } + + if ((address >= BX_NE2K_MEMSTART) && (address < BX_NE2K_MEMEND)) { + return ne2000->mem[address - BX_NE2K_MEMSTART]; + } else { + return (0xff); + } +} + + +static inline uint16_t ne2000_chipmem_read_w(uint32_t address, ne2000_t *ne2000) +{ + // ROM'd MAC address + if ((address >=0) && (address <= 31)) { + return le16_to_cpu(*(uint16_t *)(ne2000->macaddr + address)); + } + + if ((address >= BX_NE2K_MEMSTART) && (address < BX_NE2K_MEMEND)) { + return le16_to_cpu(*(uint16_t *)(ne2000->mem + (address - BX_NE2K_MEMSTART))); + } else { + return (0xffff); + } +} + +static inline void ne2000_chipmem_write_b(uint32_t address, uint8_t value, ne2000_t *ne2000) +{ + if ((address >= BX_NE2K_MEMSTART) && (address < BX_NE2K_MEMEND)) { + ne2000->mem[address - BX_NE2K_MEMSTART] = value & 0xff; + } +} + + +static inline void ne2000_chipmem_write_w(uint32_t address, uint16_t value, ne2000_t *ne2000) +{ + if ((address >= BX_NE2K_MEMSTART) && (address < BX_NE2K_MEMEND)) { + *(uint16_t *)(ne2000->mem + (address - BX_NE2K_MEMSTART)) = cpu_to_le16(value); + } +} + +// +// asic_read/asic_write - This is the high 16 bytes of i/o space +// (the lower 16 bytes is for the DS8390). Only two locations +// are used: offset 0, which is used for data transfer, and +// offset 0xf, which is used to reset the device. +// The data transfer port is used to as 'external' DMA to the +// DS8390. The chip has to have the DMA registers set up, and +// after that, insw/outsw instructions can be used to move +// the appropriate number of bytes to/from the device. +// +uint16_t ne2000_dma_read(int io_len, void *p) +{ + ne2000_t *ne2000 = (ne2000_t *)p; + + // + // The 8390 bumps the address and decreases the byte count + // by the selected word size after every access, not by + // the amount of data requested by the host (io_len). + // + ne2000->remote_dma += io_len; + if (ne2000->remote_dma == ne2000->page_stop << 8) { + ne2000->remote_dma = ne2000->page_start << 8; + } + // keep s.remote_bytes from underflowing + if (ne2000->remote_bytes > 1) + ne2000->remote_bytes -= io_len; + else + ne2000->remote_bytes = 0; + + // If all bytes have been written, signal remote-DMA complete + if (ne2000->remote_bytes == 0) { + ne2000->ISR.rdma_done = 1; + if (ne2000->IMR.rdma_inte) { + picint(1 << ne2000->base_irq); + picintc(1 << ne2000->base_irq); + //DEV_pic_raise_irq(ne2000->base_irq); + } + } + return (0); +} + +uint16_t ne2000_asic_read_w(uint32_t offset, void *p) +{ + ne2000_t *ne2000 = (ne2000_t *)p; + int retval; + + if (ne2000->DCR.wdsize & 0x01) { + /* 16 bit access */ + retval = ne2000_chipmem_read_w(ne2000->remote_dma, ne2000); + ne2000_dma_read(2, ne2000); + } else { + /* 8 bit access */ + retval = ne2000_chipmem_read_b(ne2000->remote_dma, ne2000); + ne2000_dma_read(1, ne2000); + } + + pclog("asic read val=0x%04x\n", retval); + + return retval; +} + +void ne2000_dma_write(int io_len, void *p) +{ + ne2000_t *ne2000 = (ne2000_t *)p; + + // is this right ??? asic_read uses DCR.wordsize + ne2000->remote_dma += io_len; + if (ne2000->remote_dma == ne2000->page_stop << 8) { + ne2000->remote_dma = ne2000->page_start << 8; + } + + ne2000->remote_bytes -= io_len; + if (ne2000->remote_bytes > BX_NE2K_MEMSIZ) + ne2000->remote_bytes = 0; + + // If all bytes have been written, signal remote-DMA complete + if (ne2000->remote_bytes == 0) { + ne2000->ISR.rdma_done = 1; + if (ne2000->IMR.rdma_inte) { + picint(1 << ne2000->base_irq); + picintc(1 << ne2000->base_irq); + //DEV_pic_raise_irq(ne2000->base_irq); + } + } +} + +void ne2000_asic_write_w(uint32_t offset, uint16_t value, void *p) +{ + ne2000_t *ne2000 = (ne2000_t *)p; + + pclog("asic write val=0x%04x\n", value); + + if (ne2000->remote_bytes == 0) + return; + if (ne2000->DCR.wdsize & 0x01) { + /* 16 bit access */ + ne2000_chipmem_write_w(ne2000->remote_dma, value, ne2000); + ne2000_dma_write(2, ne2000); + } else { + /* 8 bit access */ + ne2000_chipmem_write_b(ne2000->remote_dma, value, ne2000); + ne2000_dma_write(1, ne2000); + } +} + +uint8_t ne2000_asic_read_b(uint32_t offset, void *p) +{ + if (offset & 1) + return ne2000_asic_read_w(offset & ~1, p) >> 1; + return ne2000_asic_read_w(offset, p) & 0xff; +} + +void ne2000_asic_write_b(uint32_t offset, uint8_t value, void *p) +{ + if (offset & 1) + ne2000_asic_write_w(offset & ~1, value << 8, p); + else + ne2000_asic_write_w(offset, value, p); +} + +uint16_t ne2000_reset_read(uint32_t offset, void *p) +{ + ne2000_t *ne2000 = (ne2000_t *)p; + ne2000_reset(BX_RESET_SOFTWARE, ne2000); + return 0; +} + +void ne2000_reset_write(uint32_t offset, uint16_t value, void *p) +{ +} + +// +// read_handler/read - i/o 'catcher' function called from BOCHS +// mainline when the CPU attempts a read in the i/o space registered +// by this ne2000 instance +// +uint16_t ne2000_read(uint32_t address, void *p) +{ + ne2000_t *ne2000 = (ne2000_t *)p; + + pclog("read addr %x\n", address); + int ret; + + address &= 0xf; + + if (address == 0x00) { + ret = + (((ne2000->CR.pgsel & 0x03) << 6) | + ((ne2000->CR.rdma_cmd & 0x07) << 3) | + (ne2000->CR.tx_packet << 2) | + (ne2000->CR.start << 1) | + (ne2000->CR.stop)); + pclog("read CR returns 0x%08x\n", ret); + } else { + switch (ne2000->CR.pgsel) { + case 0x00: + pclog("page 0 read from port %04x\n", address); + + switch (address) { + case 0x1: // CLDA0 + return (ne2000->local_dma & 0xff); + break; + + case 0x2: // CLDA1 + return (ne2000->local_dma >> 8); + break; + + case 0x3: // BNRY + return (ne2000->bound_ptr); + break; + + case 0x4: // TSR + return ((ne2000->TSR.ow_coll << 7) | + (ne2000->TSR.cd_hbeat << 6) | + (ne2000->TSR.fifo_ur << 5) | + (ne2000->TSR.no_carrier << 4) | + (ne2000->TSR.aborted << 3) | + (ne2000->TSR.collided << 2) | + (ne2000->TSR.tx_ok)); + break; + + case 0x5: // NCR + return (ne2000->num_coll); + break; + + case 0x6: // FIFO + // reading FIFO is only valid in loopback mode + pclog("reading FIFO not supported yet\n"); + return (ne2000->fifo); + break; + + case 0x7: // ISR + return ((ne2000->ISR.reset << 7) | + (ne2000->ISR.rdma_done << 6) | + (ne2000->ISR.cnt_oflow << 5) | + (ne2000->ISR.overwrite << 4) | + (ne2000->ISR.tx_err << 3) | + (ne2000->ISR.rx_err << 2) | + (ne2000->ISR.pkt_tx << 1) | + (ne2000->ISR.pkt_rx)); + break; + + case 0x8: // CRDA0 + return (ne2000->remote_dma & 0xff); + break; + + case 0x9: // CRDA1 + return (ne2000->remote_dma >> 8); + break; + + case 0xa: // reserved + pclog("reserved read - page 0, 0xa\n"); + if (network_card_current == 2) return ne2000->i8029id0; + return (0xff); + break; + + case 0xb: // reserved + pclog("reserved read - page 0, 0xb\n"); + if (network_card_current == 2) return ne2000->i8029id1; + return (0xff); + break; + + case 0xc: // RSR + return ((ne2000->RSR.deferred << 7) | + (ne2000->RSR.rx_disabled << 6) | + (ne2000->RSR.rx_mbit << 5) | + (ne2000->RSR.rx_missed << 4) | + (ne2000->RSR.fifo_or << 3) | + (ne2000->RSR.bad_falign << 2) | + (ne2000->RSR.bad_crc << 1) | + (ne2000->RSR.rx_ok)); + break; + + case 0xd: // CNTR0 + return (ne2000->tallycnt_0); + break; + + case 0xe: // CNTR1 + return (ne2000->tallycnt_1); + break; + + case 0xf: // CNTR2 + return (ne2000->tallycnt_2); + break; + } + + return(0); + break; + + case 0x01: + pclog("page 1 read from port %04x\n", address); + + switch (address) { + case 0x1: // PAR0-5 + case 0x2: + case 0x3: + case 0x4: + case 0x5: + case 0x6: + return (ne2000->physaddr[address - 1]); + break; + + case 0x7: // CURR + pclog("returning current page: %02x\n", (ne2000->curr_page)); + return (ne2000->curr_page); + + case 0x8: // MAR0-7 + case 0x9: + case 0xa: + case 0xb: + case 0xc: + case 0xd: + case 0xe: + case 0xf: + return (ne2000->mchash[address - 8]); + break; + } + + return (0); + break; + + case 0x02: + pclog("page 2 read from port %04x\n", address); + + switch (address) { + case 0x1: // PSTART + return (ne2000->page_start); + break; + + case 0x2: // PSTOP + return (ne2000->page_stop); + break; + + case 0x3: // Remote Next-packet pointer + return (ne2000->rempkt_ptr); + break; + + case 0x4: // TPSR + return (ne2000->tx_page_start); + break; + + case 0x5: // Local Next-packet pointer + return (ne2000->localpkt_ptr); + break; + + case 0x6: // Address counter (upper) + return (ne2000->address_cnt >> 8); + break; + + case 0x7: // Address counter (lower) + return (ne2000->address_cnt & 0xff); + break; + + case 0x8: // Reserved + case 0x9: + case 0xa: + case 0xb: + pclog("reserved read - page 2, 0x%02x\n", address); + break; + + case 0xc: // RCR + return ((ne2000->RCR.monitor << 5) | + (ne2000->RCR.promisc << 4) | + (ne2000->RCR.multicast << 3) | + (ne2000->RCR.broadcast << 2) | + (ne2000->RCR.runts_ok << 1) | + (ne2000->RCR.errors_ok)); + break; + + case 0xd: // TCR + return ((ne2000->TCR.coll_prio << 4) | + (ne2000->TCR.ext_stoptx << 3) | + ((ne2000->TCR.loop_cntl & 0x3) << 1) | + (ne2000->TCR.crc_disable)); + break; + + case 0xe: // DCR + return (((ne2000->DCR.fifo_size & 0x3) << 5) | + (ne2000->DCR.auto_rx << 4) | + (ne2000->DCR.loop << 3) | + (ne2000->DCR.longaddr << 2) | + (ne2000->DCR.endian << 1) | + (ne2000->DCR.wdsize)); + break; + + case 0xf: // IMR + return ((ne2000->IMR.rdma_inte << 6) | + (ne2000->IMR.cofl_inte << 5) | + (ne2000->IMR.overw_inte << 4) | + (ne2000->IMR.txerr_inte << 3) | + (ne2000->IMR.rxerr_inte << 2) | + (ne2000->IMR.tx_inte << 1) | + (ne2000->IMR.rx_inte)); + break; + } + break; + + case 3: + if (network_card_current == 1) fatal("ne2000 unknown value of pgsel in read - %d\n", ne2000->CR.pgsel); + + switch(address) + { + case 0: + return ne2000->cr; + case 1: + return ne2000->i9346cr; + case 3: + return ne2000->config0; + case 5: + return ne2000->config2; + case 6: + return ne2000->config3; + case 9: + return 0xFF; + case 0xE: + return ne2000->i8029asid0; + case 0xF: + return ne2000->i8029asid1; + } + break; + + default: + fatal("ne2000 unknown value of pgsel in read - %d\n", ne2000->CR.pgsel); + } + } + return ret; +} + +// +// write_handler/write - i/o 'catcher' function called from BOCHS +// mainline when the CPU attempts a write in the i/o space registered +// by this ne2000 instance +// +void ne2000_write(uint32_t address, uint16_t value, void *p) +{ + ne2000_t *ne2000 = (ne2000_t *)p; + + pclog("write address %x, val=%x\n", address, value); + + address &= 0xf; + + // + // The high 16 bytes of i/o space are for the ne2000 asic - + // the low 16 bytes are for the DS8390, with the current + // page being selected by the PS0,PS1 registers in the + // command register + // + if (address == 0x00) { + pclog("wrote 0x%02x to CR\n", value); + + // Validate remote-DMA + if ((value & 0x38) == 0x00) { + pclog("CR write - invalid rDMA value 0\n"); + value |= 0x20; /* dma_cmd == 4 is a safe default */ + //value = 0x22; /* dma_cmd == 4 is a safe default */ + } + + // Check for s/w reset + if (value & 0x01) { + ne2000->ISR.reset = 1; + ne2000->CR.stop = 1; + } else { + ne2000->CR.stop = 0; + } + + ne2000->CR.rdma_cmd = (value & 0x38) >> 3; + + // If start command issued, the RST bit in the ISR + // must be cleared + if ((value & 0x02) && !ne2000->CR.start) { + ne2000->ISR.reset = 0; + } + + ne2000->CR.start = ((value & 0x02) == 0x02); + ne2000->CR.pgsel = (value & 0xc0) >> 6; + + // Check for send-packet command + if (ne2000->CR.rdma_cmd == 3) { + // Set up DMA read from receive ring + ne2000->remote_start = ne2000->remote_dma = + ne2000->bound_ptr * 256; + ne2000->remote_bytes = *((uint16_t*) & + ne2000->mem[ne2000->bound_ptr * 256 + 2 - BX_NE2K_MEMSTART]); + pclog("Sending buffer #x%x length %d\n", + ne2000->remote_start, + ne2000->remote_bytes); + } + + // Check for start-tx + if ((value & 0x04) && ne2000->TCR.loop_cntl) { + // loopback mode + if (ne2000->TCR.loop_cntl != 1) { + pclog("Loop mode %d not supported.\n", ne2000->TCR.loop_cntl); + } else { + ne2000_rx_frame (ne2000, &ne2000->mem[ne2000->tx_page_start*256 - + BX_NE2K_MEMSTART], + ne2000->tx_bytes); + + // do a TX interrupt + // Generate an interrupt if not masked and not one in progress + if (ne2000->IMR.tx_inte && !ne2000->ISR.pkt_tx) { + //LOG_MSG("tx complete interrupt"); + picint(1 << ne2000->base_irq); + } + ne2000->ISR.pkt_tx = 1; + } + } else if (value & 0x04) { + // start-tx and no loopback + if (ne2000->CR.stop || !ne2000->CR.start) + pclog("CR write - tx start, dev in reset\n"); + + if (ne2000->tx_bytes == 0) + pclog("CR write - tx start, tx bytes == 0\n"); + + // Send the packet to the system driver + /* TODO: Transmit packet */ + //BX_NE2K_THIS ethdev->sendpkt(& ne2000->mem[ne2000->tx_page_start*256 - BX_NE2K_MEMSTART], ne2000->tx_bytes); + //pcap_sendpacket(adhandle,&ne2000->mem[ne2000->tx_page_start*256 - BX_NE2K_MEMSTART], ne2000->tx_bytes); +if(net_is_slirp) { + slirp_input(&ne2000->mem[ne2000->tx_page_start*256 - BX_NE2K_MEMSTART], ne2000->tx_bytes); + pclog("ne2000 slirp sending packet\n"); + } +if(net_is_pcap && net_pcap!=NULL) { + _pcap_sendpacket(net_pcap, &ne2000->mem[ne2000->tx_page_start*256 - BX_NE2K_MEMSTART], ne2000->tx_bytes); + pclog("ne2000 pcap sending packet\n"); + } + + ne2000_tx_event(value, ne2000); + // Schedule a timer to trigger a tx-complete interrupt + // The number of microseconds is the bit-time / 10. + // The bit-time is the preamble+sfd (64 bits), the + // inter-frame gap (96 bits), the CRC (4 bytes), and the + // the number of bits in the frame (s.tx_bytes * 8). + // + + /* TODO: Code transmit timer */ + /* + bx_pc_system.activate_timer(ne2000->tx_timer_index, + (64 + 96 + 4*8 + ne2000->tx_bytes*8)/10, + 0); // not continuous + */ + } // end transmit-start branch + + // Linux probes for an interrupt by setting up a remote-DMA read + // of 0 bytes with remote-DMA completion interrupts enabled. + // Detect this here + if (ne2000->CR.rdma_cmd == 0x01 && + ne2000->CR.start && + ne2000->remote_bytes == 0) { + ne2000->ISR.rdma_done = 1; + if (ne2000->IMR.rdma_inte) { + picint(1 << ne2000->base_irq); + picintc(1 << ne2000->base_irq); + //DEV_pic_raise_irq(ne2000->base_irq); + } + } + } else { + switch (ne2000->CR.pgsel) { + case 0x00: + pclog("page 0 write to port %04x\n", address); + + // It appears to be a common practice to use outw on page0 regs... + + switch (address) { + case 0x1: // PSTART + ne2000->page_start = value; + break; + + case 0x2: // PSTOP + // BX_INFO(("Writing to PSTOP: %02x", value)); + ne2000->page_stop = value; + break; + + case 0x3: // BNRY + ne2000->bound_ptr = value; + break; + + case 0x4: // TPSR + ne2000->tx_page_start = value; + break; + + case 0x5: // TBCR0 + // Clear out low byte and re-insert + ne2000->tx_bytes &= 0xff00; + ne2000->tx_bytes |= (value & 0xff); + break; + + case 0x6: // TBCR1 + // Clear out high byte and re-insert + ne2000->tx_bytes &= 0x00ff; + ne2000->tx_bytes |= ((value & 0xff) << 8); + break; + + case 0x7: // ISR + value &= 0x7f; // clear RST bit - status-only bit + // All other values are cleared iff the ISR bit is 1 + ne2000->ISR.pkt_rx &= ~((int)((value & 0x01) == 0x01)); + ne2000->ISR.pkt_tx &= ~((int)((value & 0x02) == 0x02)); + ne2000->ISR.rx_err &= ~((int)((value & 0x04) == 0x04)); + ne2000->ISR.tx_err &= ~((int)((value & 0x08) == 0x08)); + ne2000->ISR.overwrite &= ~((int)((value & 0x10) == 0x10)); + ne2000->ISR.cnt_oflow &= ~((int)((value & 0x20) == 0x20)); + ne2000->ISR.rdma_done &= ~((int)((value & 0x40) == 0x40)); + value = ((ne2000->ISR.rdma_done << 6) | + (ne2000->ISR.cnt_oflow << 5) | + (ne2000->ISR.overwrite << 4) | + (ne2000->ISR.tx_err << 3) | + (ne2000->ISR.rx_err << 2) | + (ne2000->ISR.pkt_tx << 1) | + (ne2000->ISR.pkt_rx)); + value &= ((ne2000->IMR.rdma_inte << 6) | + (ne2000->IMR.cofl_inte << 5) | + (ne2000->IMR.overw_inte << 4) | + (ne2000->IMR.txerr_inte << 3) | + (ne2000->IMR.rxerr_inte << 2) | + (ne2000->IMR.tx_inte << 1) | + (ne2000->IMR.rx_inte)); + if (value == 0) + picintc(1 << ne2000->base_irq); + //DEV_pic_lower_irq(ne2000->base_irq); + break; + + case 0x8: // RSAR0 + // Clear out low byte and re-insert + ne2000->remote_start &= 0xff00; + ne2000->remote_start |= (value & 0xff); + ne2000->remote_dma = ne2000->remote_start; + break; + + case 0x9: // RSAR1 + // Clear out high byte and re-insert + ne2000->remote_start &= 0x00ff; + ne2000->remote_start |= ((value & 0xff) << 8); + ne2000->remote_dma = ne2000->remote_start; + break; + + case 0xa: // RBCR0 + // Clear out low byte and re-insert + ne2000->remote_bytes &= 0xff00; + ne2000->remote_bytes |= (value & 0xff); + break; + + case 0xb: // RBCR1 + // Clear out high byte and re-insert + ne2000->remote_bytes &= 0x00ff; + ne2000->remote_bytes |= ((value & 0xff) << 8); + break; + + case 0xc: // RCR + // Check if the reserved bits are set + if (value & 0xc0) + pclog("RCR write, reserved bits set\n"); + + // Set all other bit-fields + ne2000->RCR.errors_ok = ((value & 0x01) == 0x01); + ne2000->RCR.runts_ok = ((value & 0x02) == 0x02); + ne2000->RCR.broadcast = ((value & 0x04) == 0x04); + ne2000->RCR.multicast = ((value & 0x08) == 0x08); + ne2000->RCR.promisc = ((value & 0x10) == 0x10); + ne2000->RCR.monitor = ((value & 0x20) == 0x20); + + // Monitor bit is a little suspicious... + if (value & 0x20) + pclog("RCR write, monitor bit set!\n"); + break; + + case 0xd: // TCR + // Check reserved bits + if (value & 0xe0) + pclog("TCR write, reserved bits set\n"); + + // Test loop mode (not supported) + if (value & 0x06) { + ne2000->TCR.loop_cntl = (value & 0x6) >> 1; + pclog("TCR write, loop mode %d not supported\n", ne2000->TCR.loop_cntl); + } else { + ne2000->TCR.loop_cntl = 0; + } + + // Inhibit-CRC not supported. + if (value & 0x01) + { + //fatal("ne2000 TCR write, inhibit-CRC not supported\n"); + pclog("ne2000 TCR write, inhibit-CRC not supported\n"); + return; + } + + // Auto-transmit disable very suspicious + if (value & 0x08) { + //fatal("ne2000 TCR write, auto transmit disable not supported\n"); + pclog("ne2000 TCR write, auto transmit disable not supported\n"); + } + + // Allow collision-offset to be set, although not used + ne2000->TCR.coll_prio = ((value & 0x08) == 0x08); + break; + + case 0xe: // DCR + // the loopback mode is not suppported yet + if (!(value & 0x08)) { + pclog("DCR write, loopback mode selected\n"); + } + // It is questionable to set longaddr and auto_rx, since they + // aren't supported on the ne2000. Print a warning and continue + if (value & 0x04) + pclog("DCR write - LAS set ???\n"); + if (value & 0x10) + pclog("DCR write - AR set ???\n"); + + // Set other values. + ne2000->DCR.wdsize = ((value & 0x01) == 0x01); + ne2000->DCR.endian = ((value & 0x02) == 0x02); + ne2000->DCR.longaddr = ((value & 0x04) == 0x04); // illegal ? + ne2000->DCR.loop = ((value & 0x08) == 0x08); + ne2000->DCR.auto_rx = ((value & 0x10) == 0x10); // also illegal ? + ne2000->DCR.fifo_size = (value & 0x50) >> 5; + break; + + case 0xf: // IMR + // Check for reserved bit + if (value & 0x80) + pclog("IMR write, reserved bit set\n"); + + // Set other values + ne2000->IMR.rx_inte = ((value & 0x01) == 0x01); + ne2000->IMR.tx_inte = ((value & 0x02) == 0x02); + ne2000->IMR.rxerr_inte = ((value & 0x04) == 0x04); + ne2000->IMR.txerr_inte = ((value & 0x08) == 0x08); + ne2000->IMR.overw_inte = ((value & 0x10) == 0x10); + ne2000->IMR.cofl_inte = ((value & 0x20) == 0x20); + ne2000->IMR.rdma_inte = ((value & 0x40) == 0x40); + if(ne2000->ISR.pkt_tx && ne2000->IMR.tx_inte) { + pclog("tx irq retrigger\n"); + picint(1 << ne2000->base_irq); + picintc(1 << ne2000->base_irq); + } + break; + } + break; + + case 0x01: + pclog("page 1 w offset %04x\n", address); + switch (address) { + case 0x1: // PAR0-5 + case 0x2: + case 0x3: + case 0x4: + case 0x5: + case 0x6: + ne2000->physaddr[address - 1] = value; + break; + + case 0x7: // CURR + ne2000->curr_page = value; + break; + + case 0x8: // MAR0-7 + case 0x9: + case 0xa: + case 0xb: + case 0xc: + case 0xd: + case 0xe: + case 0xf: + ne2000->mchash[address - 8] = value; + break; + } + break; + + case 0x02: + if (address != 0) + pclog("page 2 write ?\n"); + + switch (address) { + case 0x1: // CLDA0 + // Clear out low byte and re-insert + ne2000->local_dma &= 0xff00; + ne2000->local_dma |= (value & 0xff); + break; + + case 0x2: // CLDA1 + // Clear out high byte and re-insert + ne2000->local_dma &= 0x00ff; + ne2000->local_dma |= ((value & 0xff) << 8); + break; + + case 0x3: // Remote Next-pkt pointer + ne2000->rempkt_ptr = value; + break; + + case 0x4: + //fatal("page 2 write to reserved offset 4\n"); + //OS/2 Warp can cause this to freak out. + pclog("ne2000 page 2 write to reserved offset 4\n"); + break; + + case 0x5: // Local Next-packet pointer + ne2000->localpkt_ptr = value; + break; + + case 0x6: // Address counter (upper) + // Clear out high byte and re-insert + ne2000->address_cnt &= 0x00ff; + ne2000->address_cnt |= ((value & 0xff) << 8); + break; + + case 0x7: // Address counter (lower) + // Clear out low byte and re-insert + ne2000->address_cnt &= 0xff00; + ne2000->address_cnt |= (value & 0xff); + break; + + case 0x8: + case 0x9: + case 0xa: + case 0xb: + case 0xc: + case 0xd: + case 0xe: + case 0xf: + //fatal("page 2 write to reserved offset %0x\n", address); + pclog("ne2000 page 2 write to reserved offset %0x\n", address); + default: + break; + } + break; + + case 3: + if (network_card_current == 1) + { + pclog("ne2000 unknown value of pgsel in write - %d\n", ne2000->CR.pgsel); + break; + } + + switch (address) + { + case 0: + ne2000->cr = value; + break; + case 1: + ne2000->i9346cr = value; + break; + case 5: + if ((ne2000->i9346cr & 0xC0) == 0xC0) ne2000->config2 = value; + break; + case 6: + if ((ne2000->i9346cr & 0xC0) == 0xC0) ne2000->config3 = value; + break; + case 9: + ne2000->hltclk = value; + break; + } + break; + + default: + //fatal("ne2K: unknown value of pgsel in write - %d\n", ne2000->CR.pgsel); + pclog("ne2000 unknown value of pgsel in write - %d\n", ne2000->CR.pgsel); + break; + } + } +} + +/* + * mcast_index() - return the 6-bit index into the multicast + * table. Stolen unashamedly from FreeBSD's if_ed.c + */ +static int mcast_index(const void *dst) +{ +#define POLYNOMIAL 0x04c11db6 + unsigned long crc = 0xffffffffL; + int carry, i, j; + unsigned char b; + unsigned char *ep = (unsigned char *) dst; + + for (i = 6; --i >= 0;) { + b = *ep++; + for (j = 8; --j >= 0;) { + carry = ((crc & 0x80000000L) ? 1 : 0) ^ (b & 0x01); + crc <<= 1; + b >>= 1; + if (carry) + crc = ((crc ^ POLYNOMIAL) | carry); + } + } + return (crc >> 26); +#undef POLYNOMIAL +} + +/* + * rx_frame() - called by the platform-specific code when an + * ethernet frame has been received. The destination address + * is tested to see if it should be accepted, and if the + * rx ring has enough room, it is copied into it and + * the receive process is updated + */ +void ne2000_rx_frame(void *p, const void *buf, int io_len) +{ + ne2000_t *ne2000 = (ne2000_t *)p; + + int pages; + int avail; + int idx; + int wrapped; + int nextpage; + uint8_t pkthdr[4]; + uint8_t *pktbuf = (uint8_t *) buf; + uint8_t *startptr; + static uint8_t bcast_addr[6] = {0xff,0xff,0xff,0xff,0xff,0xff}; + + if(io_len != 60) { + pclog("rx_frame with length %d\n", io_len); + } + + //LOG_MSG("stop=%d, pagestart=%x, dcr_loop=%x, tcr_loopcntl=%x", + // ne2000->CR.stop, ne2000->page_start, + // ne2000->DCR.loop, ne2000->TCR.loop_cntl); + if ((ne2000->CR.stop != 0) || + (ne2000->page_start == 0) /*|| + ((ne2000->DCR.loop == 0) && + (ne2000->TCR.loop_cntl != 0))*/) { + return; + } + + // Add the pkt header + CRC to the length, and work + // out how many 256-byte pages the frame would occupy + pages = (io_len + 4 + 4 + 255)/256; + + if (ne2000->curr_page < ne2000->bound_ptr) { + avail = ne2000->bound_ptr - ne2000->curr_page; + } else { + avail = (ne2000->page_stop - ne2000->page_start) - + (ne2000->curr_page - ne2000->bound_ptr); + wrapped = 1; + } + + // Avoid getting into a buffer overflow condition by not attempting + // to do partial receives. The emulation to handle this condition + // seems particularly painful. + if ((avail < pages) +#if BX_NE2K_NEVER_FULL_RING + || (avail == pages) +#endif + ) { + pclog("no space\n"); + return; + } + + if ((io_len < 40/*60*/) && !ne2000->RCR.runts_ok) { + pclog("rejected small packet, length %d\n", io_len); + return; + } + // some computers don't care... + if (io_len < 60) io_len=60; + + // Do address filtering if not in promiscuous mode + if (! ne2000->RCR.promisc) { + if (!memcmp(buf, bcast_addr, 6)) { + if (!ne2000->RCR.broadcast) { + return; + } + } else if (pktbuf[0] & 0x01) { + if (! ne2000->RCR.multicast) { + return; + } + idx = mcast_index(buf); + if (!(ne2000->mchash[idx >> 3] & (1 << (idx & 0x7)))) { + return; + } + } else if (0 != memcmp(buf, ne2000->physaddr, 6)) { + return; + } + } else { + pclog("rx_frame promiscuous receive\n"); + } + + pclog("rx_frame %d to %x:%x:%x:%x:%x:%x from %x:%x:%x:%x:%x:%x\n", + io_len, + pktbuf[0], pktbuf[1], pktbuf[2], pktbuf[3], pktbuf[4], pktbuf[5], + pktbuf[6], pktbuf[7], pktbuf[8], pktbuf[9], pktbuf[10], pktbuf[11]); + + nextpage = ne2000->curr_page + pages; + if (nextpage >= ne2000->page_stop) { + nextpage -= ne2000->page_stop - ne2000->page_start; + } + + // Setup packet header + pkthdr[0] = 0; // rx status - old behavior + pkthdr[0] = 1; // Probably better to set it all the time + // rather than set it to 0, which is clearly wrong. + if (pktbuf[0] & 0x01) { + pkthdr[0] |= 0x20; // rx status += multicast packet + } + pkthdr[1] = nextpage; // ptr to next packet + pkthdr[2] = (io_len + 4) & 0xff; // length-low + pkthdr[3] = (io_len + 4) >> 8; // length-hi + + // copy into buffer, update curpage, and signal interrupt if config'd + startptr = & ne2000->mem[ne2000->curr_page * 256 - + BX_NE2K_MEMSTART]; + if ((nextpage > ne2000->curr_page) || + ((ne2000->curr_page + pages) == ne2000->page_stop)) { + memcpy(startptr, pkthdr, 4); + memcpy(startptr + 4, buf, io_len); + ne2000->curr_page = nextpage; + } else { + int endbytes = (ne2000->page_stop - ne2000->curr_page) + * 256; + memcpy(startptr, pkthdr, 4); + memcpy(startptr + 4, buf, endbytes - 4); + startptr = & ne2000->mem[ne2000->page_start * 256 - + BX_NE2K_MEMSTART]; + memcpy(startptr, (void *)(pktbuf + endbytes - 4), + io_len - endbytes + 8); + ne2000->curr_page = nextpage; + } + + ne2000->RSR.rx_ok = 1; + if (pktbuf[0] & 0x80) { + ne2000->RSR.rx_mbit = 1; + } + + ne2000->ISR.pkt_rx = 1; + + if (ne2000->IMR.rx_inte) { + //LOG_MSG("packet rx interrupt"); + picint(1 << ne2000->base_irq); + //DEV_pic_raise_irq(ne2000->base_irq); + } //else LOG_MSG("no packet rx interrupt"); + +} + +void ne2000_tx_timer(void *p) +{ + ne2000_t *ne2000 = (ne2000_t *)p; + + pclog("tx_timer\n"); + ne2000->TSR.tx_ok = 1; + // Generate an interrupt if not masked and not one in progress + if (ne2000->IMR.tx_inte && !ne2000->ISR.pkt_tx) { + //LOG_MSG("tx complete interrupt"); + picint(1 << ne2000->base_irq); + //DEV_pic_raise_irq(ne2000->base_irq); + } //else LOG_MSG("no tx complete interrupt"); + ne2000->ISR.pkt_tx = 1; + ne2000->tx_timer_active = 0; +} + +static void ne2000_tx_event(int val, void *p) +{ + ne2000_t *ne2000 = (ne2000_t *)p; + ne2000_tx_timer(ne2000); +} + +static void ne2000_poller(void *p) +{ + ne2000_t *ne2000 = (ne2000_t *)p; + struct queuepacket *qp; + const unsigned char *data; + struct pcap_pkthdr h; + + + int res; +if(net_is_slirp) { + while(QueuePeek(slirpq)>0) + { + qp=QueueDelete(slirpq); + if((ne2000->DCR.loop == 0) || (ne2000->TCR.loop_cntl != 0)) + { + free(qp); + return; + } + ne2000_rx_frame(ne2000,&qp->data,qp->len); + pclog("ne2000 inQ:%d got a %dbyte packet @%d\n",QueuePeek(slirpq),qp->len,qp); + free(qp); + } + fizz++; + if(fizz>1200){fizz=0;slirp_tic();} + }//end slirp +if(net_is_pcap && net_pcap!=NULL) + { + data=_pcap_next(net_pcap,&h); + if(data==0x0){goto WTF;} + if((memcmp(data+6,maclocal,6))==0) + pclog("ne2000 we just saw ourselves\n"); + else { + if((ne2000->DCR.loop == 0) || (ne2000->TCR.loop_cntl != 0)) + { + return; + } + pclog("ne2000 pcap received a frame %d bytes\n",h.caplen); + ne2000_rx_frame(ne2000,data,h.caplen); + } + WTF: + {} + } +} + + +uint16_t io_base = 0x300; + +uint8_t ne2000_pci_regs[256]; + +void ne2000_io_set(uint16_t addr, ne2000_t *ne2000) +{ + io_sethandler(addr, 0x0010, ne2000_read, NULL, NULL, ne2000_write, NULL, NULL, ne2000); + io_sethandler(addr+0x10, 0x0010, ne2000_asic_read_b, ne2000_asic_read_w, NULL, ne2000_asic_write_b, ne2000_asic_write_w, NULL, ne2000); + io_sethandler(addr+0x1f, 0x0001, ne2000_reset_read, NULL, NULL, ne2000_reset_write, NULL, NULL, ne2000); +} + +void ne2000_io_remove(uint16_t addr, ne2000_t *ne2000) +{ + io_removehandler(addr, 0x0010, ne2000_read, NULL, NULL, ne2000_write, NULL, NULL, ne2000); + io_removehandler(addr+0x10, 0x0010, ne2000_asic_read_b, ne2000_asic_read_w, NULL, ne2000_asic_write_b, ne2000_asic_write_w, NULL, ne2000); + io_removehandler(addr+0x1f, 0x0001, ne2000_reset_read, NULL, NULL, ne2000_reset_write, NULL, NULL, ne2000); +} + +uint8_t ne2000_pci_read(int func, int addr, void *p) +{ + ne2000_t *ne2000 = (ne2000_t *) p; + + // pclog("NE2000 PCI read %08X\n", addr); + switch (addr) + { + case 0x00:/* case 0x2C:*/ return 0xec; + case 0x01:/* case 0x2D:*/ return 0x10; + + case 0x02:/* case 0x2E:*/ return 0x29; + case 0x03:/* case 0x2F:*/ return 0x80; + + case 0x2C: return 0xF4; + case 0x2D: return 0x1A; + case 0x2E: return 0x00; + case 0x2F: return 0x11; + + case 0x04: + return ne2000_pci_regs[0x04] & 3; /*Respond to IO and memory accesses*/ + case 0x05: + return ne2000_pci_regs[0x05]; + + case 0x07: return 2; + + case 0x08: return 0; /*Revision ID*/ + case 0x09: return 0; /*Programming interface*/ + + case 0x0B: return ne2000_pci_regs[0x0B]; + + case 0x10: return 1; /*I/O space*/ + case 0x11: return ne2000_pci_regs[0x11]; + case 0x12: return ne2000_pci_regs[0x12]; + case 0x13: return ne2000_pci_regs[0x13]; + + case 0x30: return ne2000_pci_regs[0x30] & 0x01; /*BIOS ROM address*/ + case 0x31: return (ne2000_pci_regs[0x31] & 0xE0) | 0x18; + case 0x32: return ne2000_pci_regs[0x32]; + case 0x33: return ne2000_pci_regs[0x33]; + + case 0x3C: return ne2000_pci_regs[0x3C]; + case 0x3D: return ne2000_pci_regs[0x3D]; + + default: return 0; + } + return 0; +} + +int bios_addr = 0xD0000; + +void ne2000_update_bios(ne2000_t *ne2000) +{ + int reg_bios_enable; + FILE *f; + int filelen; + struct stat st; + + // reg_bios_enable = ne2000_pci_regs[0x30]; + reg_bios_enable = 1; + + /* PCI BIOS stuff, just enable_disable. */ + if (!disable_netbios && reg_bios_enable) + { + mem_mapping_enable(&ne2000->bios_rom.mapping); + mem_mapping_set_addr(&ne2000->bios_rom.mapping, bios_addr, 0x8000); + pclog("Network BIOS now at: %08X\n", bios_addr); + // if (network_card_current == 2) *(uint32_t *) &(ne2000_pci_regs[0x30]) = bios_addr | 0x1801; + } + else + { + mem_mapping_disable(&ne2000->bios_rom.mapping); + if (network_card_current == 2) *(uint32_t *) &(ne2000_pci_regs[0x30]) = 0; + } +} + +void ne2000_pci_write(int func, int addr, uint8_t val, void *p) +{ + ne2000_t *ne2000 = (ne2000_t *) p; + + uint32_t ba1, ba2, ba3, ba4; + + // pclog("ne2000_pci_write: addr=%02x val=%02x\n", addr, val); + switch (addr) + { + case 0x04: + ne2000_pci_regs[0x04] = val & 3; + if (val & PCI_COMMAND_IO) + { + if (io_base >= 0x280) + { + ne2000_io_set(io_base, ne2000); + ne2000_reset(BX_RESET_SOFTWARE, ne2000); + } + } + else + if (io_base >= 0x280) ne2000_io_remove(io_base, ne2000); + break; + + case 0x10: + val &= 0xfc; + val |= 1; + case 0x11: case 0x12: case 0x13: + /* I/O Base set. */ + /* First, remove the old I/O, if old base was >= 0x280. */ + if (io_base < 0x280) ne2000_io_remove(io_base, ne2000); + /* Then let's set the PCI regs. */ + ne2000_pci_regs[addr] = val; + /* Then let's calculate the new I/O base. */ + // io_base = (uint16_t) ((*(uint32_t *) (&ne2000_pci_regs[0x10])) & 0xff00); + io_base = (*(uint32_t *) (&ne2000_pci_regs[0x10])) & 0xff00; + /* If the base is below 0x280, return. */ + if (io_base < 0x280) return; + /* Set new I/O base. */ + ne2000_io_set(io_base, ne2000); + /* Log the new base. */ + // pclog("NE2000 RTL8029AS PCI: New I/O base is %04X\n" , io_base); + /* We're done, so get out of the here. */ + return; + + case 0x30: case 0x31: case 0x32: case 0x33: + ne2000_pci_regs[addr] = val/* | ((addr == 0x30) ? 1 : 0)*/; + bios_addr = (*(uint32_t *) (&ne2000_pci_regs[0x30])) & 0x000f8000; + (*(uint32_t *) (&ne2000_pci_regs[0x30])) &= 0x000f8000; + (*(uint32_t *) (&ne2000_pci_regs[0x30])) |= 0x1801; + // bios_addr = ((ne2000_pci_regs[0x31] & 0x00) << 8) | (ne2000_pci_regs[0x32] << 16) | (ne2000_pci_regs[0x33] << 24); + ne2000_update_bios(ne2000); + return; + + case 0x3C: + ne2000_pci_regs[addr] = val; + if (val != 0xFF) + { + pclog("NE2000 IRQ now: %i\n", val); + ne2000_setirq(ne2000, val); + ne2000_reset(BX_RESET_SOFTWARE, ne2000); + } + return; + } +} + +void rtl8029as_init(ne2000_t *ne2000) +{ + pci_add(ne2000_pci_read, ne2000_pci_write, ne2000); + + memset(ne2000_pci_regs, 0, 256); + + ne2000_pci_regs[0x04] = 3; + ne2000_pci_regs[0x05] = 0; + + ne2000_pci_regs[0x07] = 2; + + /* Network controller. */ + ne2000_pci_regs[0x0B] = 2; + + *(uint32_t *) &(ne2000_pci_regs[0x10]) = 0x0000FF01; + ne2000_io_set(io_base, ne2000); + + *(uint32_t *) &(ne2000_pci_regs[0x30]) = 0x000F8000 | 0x1801; + bios_addr = 0xD0000; + + if (disable_netbios) ne2000_pci_regs[0x33] = 0x00; + + ne2000_pci_regs[0x3C] = 10; + ne2000_pci_regs[0x3D] = 1; + + memset(rtl8029as_eeprom, 0, 128); + rtl8029as_eeprom[0x76] = rtl8029as_eeprom[0x7A] = rtl8029as_eeprom[0x7E] = 0x29; + rtl8029as_eeprom[0x77] = rtl8029as_eeprom[0x7B] = rtl8029as_eeprom[0x7F] = 0x80; + rtl8029as_eeprom[0x78] = rtl8029as_eeprom[0x7C] = 0x10; + rtl8029as_eeprom[0x79] = rtl8029as_eeprom[0x7D] = 0xEC; + + ne2000->i8029id0 = 0x50; + ne2000->i8029id1 = 0x43; + + ne2000->cr = 0x21; + ne2000->i9346cr = 0; + ne2000->config0 = 0; + ne2000->config2 = 3; + ne2000->config3 = 0; + ne2000->hltclk = 0x52; + ne2000->i8029asid0 = 0x29; + ne2000->i8029asid1 = 0x80; +} + +void *ne2000_init() +{ + struct in_addr myaddr; + int rc; + int config_net_type; + int net_type; + + ne2000_t *ne2000 = malloc(sizeof(ne2000_t)); + memset(ne2000, 0, sizeof(ne2000_t)); + + uint16_t addr = 0xC000; + if (network_card_current == 1) addr = device_get_config_int("addr"); + disable_netbios = device_get_config_int("disable_netbios"); + io_base = addr; + if (network_card_current == 1) ne2000_setirq(ne2000, device_get_config_int("irq")); + + //net_type + //0 pcap + //1 slirp + // + config_net_type = device_get_config_int("net_type"); + // net_is_slirp = config_get_int(NULL, "net_type", 1); + /* Network type is now specified in device config. */ + net_is_slirp = config_net_type ? 1 : 0; + // pclog("ne2000 pcap device %s\n",config_get_string(NULL,"pcap_device","nothing")); + + //Check that we have a string setup, otherwise turn pcap off + if(!strcmp("nothing",config_get_string(NULL,"pcap_device","nothing"))) { + net_is_pcap = 0; + } + else { + if( net_is_slirp == 0) + net_is_pcap = 1; + } + + ne2000_io_set(addr, ne2000); + memcpy(ne2000->physaddr, maclocal, 6); + + if (!disable_netbios) + { + if (network_card_current == 2) + { + rtl8029as_init(ne2000); + rom_init(&ne2000->bios_rom, "roms/rtl8029as.rom", 0xd0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + if (PCI) + mem_mapping_disable(&ne2000->bios_rom.mapping); + } + else + { + rom_init(&ne2000->bios_rom, "roms/ne2000.rom", 0xd0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); + } + } + + ne2000_reset(BX_RESET_HARDWARE, ne2000); + vlan_handler(ne2000_poller, ne2000); + + pclog("ne2000 init 0x%X %d\tslirp is %d net_is_pcap is %d\n",addr,device_get_config_int("irq"),net_is_slirp,net_is_pcap); + + //need a switch statment for more network types. + + if ( net_is_slirp ) { + pclog("ne2000 initalizing SLiRP\n"); + net_is_pcap=0; + rc=slirp_init(); + pclog("ne2000 slirp_init returned: %d\n",rc); + if ( rc == 0 ) + { + pclog("ne2000 slirp initalized!\n"); + inet_aton("10.0.2.15",&myaddr); + //YES THIS NEEDS TO PULL FROM A CONFIG FILE... but for now. + rc=slirp_redir(0,42323,myaddr,23); + pclog("ne2000 slirp redir returned %d on port 42323 -> 23\n",rc); + rc=slirp_redir(0,42380,myaddr,80); + pclog("ne2000 slirp redir returned %d on port 42380 -> 80\n",rc); + rc=slirp_redir(0,42443,myaddr,443); + pclog("ne2000 slirp redir returned %d on port 42443 -> 443\n",rc); + rc=slirp_redir(0,42322,myaddr,22); + pclog("ne2000 slirp redir returned %d on port 42322 -> 22\n",rc); + + //Kali + rc=slirp_redir(1,2213,myaddr,2213); + pclog("ne2000 slirp redir returned %d on port 2213 -> 2213\n",rc); + rc=slirp_redir(1,2231,myaddr,2231); + pclog("ne2000 slirp redir returned %d on port 2231 -> 2231\n",rc); + rc=slirp_redir(1,2271,myaddr,2271); + pclog("ne2000 slirp redir returned %d on port 2271 -> 2271\n",rc); + + + net_slirp_inited=1; + slirpq = QueueCreate(); + net_is_slirp=1; + fizz=0; + pclog("ne2000 slirpq is %x\n",&slirpq); + } + else { + net_slirp_inited=0; + net_is_slirp=0; + } + } + if ( net_is_pcap ) { //pcap + char errbuf[32768]; + + pclog("ne2000 initalizing libpcap\n"); + net_is_slirp=0; + net_hLib = LoadLibraryA(net_lib_name); + if(net_hLib==0) + { + pclog("ne2000 Failed to load %s\n",net_lib_name); + net_is_pcap=0; + //return; + } + _pcap_lib_version =(PCAP_LIB_VERSION)GetProcAddress(net_hLib,"pcap_lib_version"); + _pcap_open_live=(PCAP_OPEN_LIVE)GetProcAddress(net_hLib,"pcap_open_live"); + _pcap_sendpacket=(PCAP_SENDPACKET)GetProcAddress(net_hLib,"pcap_sendpacket"); + _pcap_setnonblock=(PCAP_SETNONBLOCK)GetProcAddress(net_hLib,"pcap_setnonblock"); + _pcap_next=(PCAP_NEXT)GetProcAddress(net_hLib,"pcap_next"); + _pcap_close=(PCAP_CLOSE)GetProcAddress(net_hLib,"pcap_close"); + _pcap_getnonblock=(PCAP_GETNONBLOCK)GetProcAddress(net_hLib,"pcap_getnonblock"); + _pcap_compile=(PCAP_COMPILE)GetProcAddress(net_hLib,"pcap_compile"); + _pcap_setfilter=(PCAP_SETFILTER)GetProcAddress(net_hLib,"pcap_setfilter"); + + if(_pcap_lib_version && _pcap_open_live && _pcap_sendpacket && _pcap_setnonblock && _pcap_next && _pcap_close && _pcap_getnonblock) + { + pclog("ne2000 Pcap version [%s]\n",_pcap_lib_version()); + + //if((net_pcap=_pcap_open_live("\\Device\\NPF_{0CFA803F-F443-4BB9-A83A-657029A98195}",1518,1,15,errbuf))==0) + if((net_pcap=_pcap_open_live(config_get_string(NULL,"pcap_device","nothing"),1518,1,15,errbuf))==0) + { + pclog("ne2000 pcap_open_live error on %s!\n",config_get_string(NULL,"pcap_device","whatever the ethernet is")); + net_is_pcap=0; return(ne2000); //YUCK!!! + } + } + else { + pclog("%d %d %d %d %d %d %d\n",_pcap_lib_version, _pcap_open_live,_pcap_sendpacket,_pcap_setnonblock,_pcap_next,_pcap_close,_pcap_getnonblock); + net_is_pcap=1; + } + + //Time to check that we are in non-blocking mode. + rc=_pcap_getnonblock(net_pcap,errbuf); + pclog("ne2000 pcap is currently in %s mode\n",rc? "non-blocking":"blocking"); + switch(rc) + { + case 0: + pclog("ne2000 Setting interface to non-blocking mode.."); + rc=_pcap_setnonblock(net_pcap,1,errbuf); + if(rc==0) { //no errors! + pclog(".."); + rc=_pcap_getnonblock(net_pcap,errbuf); + if(rc==1) { + pclog("..!",rc); + net_is_pcap=1; + } + else{ + pclog("\tunable to set pcap into non-blocking mode!\nContinuining without pcap.\n"); + net_is_pcap=0; + } + }//end set nonblock + else{pclog("There was an unexpected error of [%s]\n\nexiting.\n",errbuf);net_is_pcap=0;} + pclog("\n"); + break; + case 1: + pclog("non blocking\n"); + break; + default: + pclog("this isn't right!!!\n"); + net_is_pcap=0; + break; + } + if( net_is_pcap ) { + if(_pcap_compile && _pcap_setfilter) { //we can do this! + struct bpf_program fp; + char filter_exp[255]; + pclog("ne2000 Building packet filter..."); + sprintf(filter_exp,"( ((ether dst ff:ff:ff:ff:ff:ff) or (ether dst %02x:%02x:%02x:%02x:%02x:%02x)) and not (ether src %02x:%02x:%02x:%02x:%02x:%02x) )", \ + maclocal[0], maclocal[1], maclocal[2], maclocal[3], maclocal[4], maclocal[5],\ + maclocal[0], maclocal[1], maclocal[2], maclocal[3], maclocal[4], maclocal[5]); + + //I'm doing a MAC level filter so TCP/IP doesn't matter. + if (_pcap_compile(net_pcap, &fp, filter_exp, 0, 0xffffffff) == -1) { + pclog("\nne2000 Couldn't compile filter\n"); + } + else { + pclog("..."); + if (_pcap_setfilter(net_pcap, &fp) == -1) { + pclog("\nError installing pcap filter.\n"); + }//end of set_filter failure + else { + pclog("...!\n"); + } + } + pclog("ne2000 Using filter\t[%s]\n",filter_exp); + //scanf(filter_exp); //pause + } + else + { + pclog("ne2000 Your platform lacks pcap_compile & pcap_setfilter\n"); + net_is_pcap=0; + } + pclog("ne2000 net_is_pcap is %d and net_pcap is %x\n",net_is_pcap,net_pcap); + } + } //end pcap setup + + //timer_add(slirp_tic,&delay,TIMER_ALWAYS_ENABLED,NULL); + //timer_add(keyboard_amstrad_poll, &keybsenddelay, TIMER_ALWAYS_ENABLED, NULL); +pclog("ne2000 is_slirp %d is_pcap %d\n",net_is_slirp,net_is_pcap); +//exit(0); +return ne2000; +} + +void ne2000_close(void *p) +{ + ne2000_t *ne2000 = (ne2000_t *)p; + ne2000_io_remove(io_base, ne2000); + free(ne2000); +if(net_is_slirp) { + QueueDestroy(slirpq); + slirp_exit(0); + net_slirp_inited=0; + pclog("ne2000 exiting slirp\n"); + } +if(net_is_pcap && net_pcap!=NULL) + { + _pcap_close(net_pcap); + FreeLibrary(net_hLib); + pclog("ne2000 closing pcap\n"); + } +pclog("ne2000 close\n"); +} + +static device_config_t ne2000_config[] = +{ + { + .name = "addr", + .description = "Address", + .type = CONFIG_BINARY, + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "0x280", + .value = 0x280 + }, + { + .description = "0x300", + .value = 0x300 + }, + { + .description = "0x320", + .value = 0x320 + }, + { + .description = "0x340", + .value = 0x340 + }, + { + .description = "0x360", + .value = 0x360 + }, + { + .description = "0x380", + .value = 0x380 + }, + { + .description = "" + } + }, + .default_int = 0x300 + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "IRQ 3", + .value = 3 + }, + { + .description = "IRQ 5", + .value = 5 + }, + { + .description = "IRQ 7", + .value = 7 + }, + { + .description = "IRQ 10", + .value = 10 + }, + { + .description = "IRQ 11", + .value = 11 + }, + { + .description = "" + } + }, + .default_int = 10 + }, + { + .name = "net_type", + .description = "Network type", + .type = CONFIG_BINARY, + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "PCap", + .value = 0 + }, + { + .description = "SLiRP", + .value = 1 + }, + { + .description = "" + } + }, + .default_int = 0 + }, + { + .name = "disable_netbios", + .description = "Network bios", + .type = CONFIG_BINARY, + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "Enabled", + .value = 0 + }, + { + .description = "Disabled", + .value = 1 + }, + { + .description = "" + } + }, + .default_int = 0 + }, + { + .type = -1 + } +}; + +static device_config_t rtl8029as_config[] = +{ + { + .name = "net_type", + .description = "Network type", + .type = CONFIG_BINARY, + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "PCap", + .value = 0 + }, + { + .description = "SLiRP", + .value = 1 + }, + { + .description = "" + } + }, + .default_int = 0 + }, + { + .name = "disable_netbios", + .description = "Network bios", + .type = CONFIG_BINARY, + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "Enabled", + .value = 0 + }, + { + .description = "Disabled", + .value = 1 + }, + { + .description = "" + } + }, + .default_int = 0 + }, + { + .type = -1 + } +}; + +device_t ne2000_device = +{ + "Novell NE2000", + 0, + ne2000_init, + ne2000_close, + NULL, + NULL, + NULL, + NULL, + ne2000_config +}; + +device_t rtl8029as_device = +{ + "Realtek RTL8029AS", + 0, + ne2000_init, + ne2000_close, + NULL, + NULL, + NULL, + NULL, + rtl8029as_config +}; + + +//SLIRP stuff +int slirp_can_output(void) +{ +return net_slirp_inited; +} + +void slirp_output (const unsigned char *pkt, int pkt_len) +{ +struct queuepacket *p; +p=(struct queuepacket *)malloc(sizeof(struct queuepacket)); +p->len=pkt_len; +memcpy(p->data,pkt,pkt_len); +QueueEnter(slirpq,p); +pclog("ne2000 slirp_output %d @%d\n",pkt_len,p); +} + +// Instead of calling this and crashing some times +// or experencing jitter, this is called by the +// 60Hz clock which seems to do the job. +void slirp_tic() +{ + int ret2,nfds; + struct timeval tv; + fd_set rfds, wfds, xfds; + int timeout; + nfds=-1; + + if(net_slirp_inited) + { + FD_ZERO(&rfds); + FD_ZERO(&wfds); + FD_ZERO(&xfds); + timeout=slirp_select_fill(&nfds,&rfds,&wfds,&xfds); //this can crash + + if(timeout<0) + timeout=500; + tv.tv_sec=0; + tv.tv_usec = timeout; //basilisk default 10000 + + ret2 = select(nfds + 1, &rfds, &wfds, &xfds, &tv); + if(ret2>=0){ + slirp_select_poll(&rfds, &wfds, &xfds); + } + //pclog("ne2000 slirp_tic()\n"); + }//end if slirp inited +} diff --git a/src/ne2000.h b/src/ne2000.h new file mode 100644 index 000000000..dccfc79f7 --- /dev/null +++ b/src/ne2000.h @@ -0,0 +1,2 @@ +extern device_t ne2000_device; +extern device_t rtl8029as_device; diff --git a/src/neat.c b/src/neat.c new file mode 100644 index 000000000..23c72695d --- /dev/null +++ b/src/neat.c @@ -0,0 +1,68 @@ +/*This is the chipset used in the AMI 286 clone model*/ +#include "ibm.h" +#include "io.h" +#include "neat.h" + +static uint8_t neat_regs[256]; +static int neat_index; +static int neat_emspage[4]; + +void neat_write(uint16_t port, uint8_t val, void *priv) +{ + switch (port) + { + case 0x22: + neat_index = val; + break; + + case 0x23: + neat_regs[neat_index] = val; + switch (neat_index) + { + case 0x6E: /*EMS page extension*/ + neat_emspage[3] = (neat_emspage[3] & 0x7F) | (( val & 3) << 7); + neat_emspage[2] = (neat_emspage[2] & 0x7F) | (((val >> 2) & 3) << 7); + neat_emspage[1] = (neat_emspage[1] & 0x7F) | (((val >> 4) & 3) << 7); + neat_emspage[0] = (neat_emspage[0] & 0x7F) | (((val >> 6) & 3) << 7); + break; + } + break; + + case 0x0208: case 0x0209: case 0x4208: case 0x4209: + case 0x8208: case 0x8209: case 0xC208: case 0xC209: + neat_emspage[port >> 14] = (neat_emspage[port >> 14] & 0x180) | (val & 0x7F); + break; + } +} + +uint8_t neat_read(uint16_t port, void *priv) +{ + switch (port) + { + case 0x22: + return neat_index; + + case 0x23: + return neat_regs[neat_index]; + } + return 0xff; +} + +void neat_writeems(uint32_t addr, uint8_t val) +{ + ram[(neat_emspage[(addr >> 14) & 3] << 14) + (addr & 0x3FFF)] = val; +} + +uint8_t neat_readems(uint32_t addr) +{ + return ram[(neat_emspage[(addr >> 14) & 3] << 14) + (addr & 0x3FFF)]; +} + +void neat_init() +{ + io_sethandler(0x0022, 0x0002, neat_read, NULL, NULL, neat_write, NULL, NULL, NULL); + io_sethandler(0x0208, 0x0002, neat_read, NULL, NULL, neat_write, NULL, NULL, NULL); + io_sethandler(0x4208, 0x0002, neat_read, NULL, NULL, neat_write, NULL, NULL, NULL); + io_sethandler(0x8208, 0x0002, neat_read, NULL, NULL, neat_write, NULL, NULL, NULL); + io_sethandler(0xc208, 0x0002, neat_read, NULL, NULL, neat_write, NULL, NULL, NULL); +} diff --git a/src/neat.h b/src/neat.h new file mode 100644 index 000000000..d87232243 --- /dev/null +++ b/src/neat.h @@ -0,0 +1 @@ +void neat_init(); diff --git a/src/nethandler.c b/src/nethandler.c new file mode 100644 index 000000000..1bd84b25b --- /dev/null +++ b/src/nethandler.c @@ -0,0 +1,98 @@ +#include +#include +#include +#include +#include +#include +#include "nethandler.h" + +#include "ibm.h" +#include "device.h" + +#include "ne2000.h" +#include "timer.h" + +int network_card_current = 0; +static int network_card_last = 0; + +typedef struct +{ + char name[32]; + device_t *device; +} NETWORK_CARD; + +static NETWORK_CARD network_cards[] = +{ + {"None", NULL}, + {"Novell NE2000", &ne2000_device}, + {"Realtek RTL8029AS", &rtl8029as_device}, + {"", NULL} +}; + +int network_card_available(int card) +{ + if (network_cards[card].device) + return device_available(network_cards[card].device); + + return 1; +} + +char *network_card_getname(int card) +{ + return network_cards[card].name; +} + +device_t *network_card_getdevice(int card) +{ + return network_cards[card].device; +} + +int network_card_has_config(int card) +{ + if (!network_cards[card].device) + return 0; + return network_cards[card].device->config ? 1 : 0; +} + +void network_card_init() +{ + if (network_cards[network_card_current].device) + device_add(network_cards[network_card_current].device); + network_card_last = network_card_current; +} + +static struct +{ + void (*poller)(void *p); + void *priv; +} vlan_handlers[8]; + +static int vlan_handlers_num; + +static int vlan_poller_time = 0; + +void vlan_handler(void (*poller)(void *p), void *p) +//void vlan_handler(int (*can_receive)(void *p), void (*receive)(void *p, const uint8_t *buf, int size), void *p) +{ + /* vlan_handlers[vlan_handlers_num].can_receive = can_receive; */ + vlan_handlers[vlan_handlers_num].poller = poller; + vlan_handlers[vlan_handlers_num].priv = p; + vlan_handlers_num++; +} + +void vlan_poller(void *priv) +{ + int c; + + vlan_poller_time += (int)((double)TIMER_USEC * (1000000.0 / 8.0 / 1500.0)); + + for (c = 0; c < vlan_handlers_num; c++) + vlan_handlers[c].poller(vlan_handlers[c].priv); +} + +void vlan_reset() +{ + timer_add(vlan_poller, &vlan_poller_time, TIMER_ALWAYS_ENABLED, NULL); + + vlan_handlers_num = 0; +} diff --git a/src/nethandler.h b/src/nethandler.h new file mode 100644 index 000000000..d73ffb272 --- /dev/null +++ b/src/nethandler.h @@ -0,0 +1,15 @@ +#include + +//void vlan_handler(int (*can_receive)(void *p), void (*receive)(void *p, const uint8_t *buf, int size), void *p); +void vlan_handler(void (*poller)(void *p), void *p); + +extern int network_card_current; + +int network_card_available(int card); +char *network_card_getname(int card); +struct device_t *network_card_getdevice(int card); +int network_card_has_config(int card); +void network_card_init(); + +void initpcap(); +void closepcap(); diff --git a/src/nmi.c b/src/nmi.c new file mode 100644 index 000000000..5b8205328 --- /dev/null +++ b/src/nmi.c @@ -0,0 +1,15 @@ +#include "ibm.h" +#include "nmi.h" + +int nmi_mask; + +void nmi_write(uint16_t port, uint8_t val, void *p) +{ + nmi_mask = val & 0x80; +} + +void nmi_init() +{ + io_sethandler(0x00a0, 0x0001, NULL, NULL, NULL, nmi_write, NULL, NULL, NULL); + nmi_mask = 0; +} diff --git a/src/nmi.h b/src/nmi.h new file mode 100644 index 000000000..8e38a2c6a --- /dev/null +++ b/src/nmi.h @@ -0,0 +1,5 @@ +void nmi_init(); +void nmi_write(uint16_t port, uint8_t val, void *p); +extern int nmi_mask; + + diff --git a/src/nvr.c b/src/nvr.c new file mode 100644 index 000000000..13efe84f4 --- /dev/null +++ b/src/nvr.c @@ -0,0 +1,489 @@ +#include +#include "ibm.h" +#include "io.h" +#include "nvr.h" +#include "pic.h" +#include "timer.h" + +int oldromset; +int nvrmask=63; +uint8_t nvrram[128]; +int nvraddr; + +int nvr_dosave = 0; + +static int nvr_onesec_time = 0, nvr_onesec_cnt = 0; + +int enable_sync = 0; + +#define second internal_time[0] +#define minute internal_time[1] +#define hour internal_time[2] +#define day internal_time[3] +#define month internal_time[4] +#define year internal_time[5] +int internal_time[6]; +int days_in_month[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; + +static int is_leap(int org_year) +{ + if (org_year % 400 == 0) return 1; + if (org_year % 100 == 0) return 0; + if (org_year % 4 == 0) return 1; + return 0; +} + +static int get_days(int org_month, int org_year) +{ + if (org_month != 2) + { + return days_in_month[org_month]; + } + else + { + return is_leap(org_year) ? 29 : 28; + } +} + +static int convert_to_bcd(int number) +{ + int n1, n2; + n1 = number % 10; + n2 = number - n1; + n2 /= 10; + n2 <<= 4; + return (n2 | n1); +} + +static int convert_from_bcd(int number) +{ + int n1, n2; + n1 = number & 0xF; + n2 = number >> 4; + n2 *= 10; + return (n2 + n1); +} + +static int final_form(int isbcd, int number) +{ + return isbcd ? convert_to_bcd(number) : number; +} + +static int original_form(int isbcd, int number) +{ + return isbcd ? convert_from_bcd(number) : number; +} + +static void nvr_recalc_clock() +{ + if (second == 60) + { + second = 0; + minute++; + } + if (minute == 60) + { + minute = 0; + hour++; + } + if (hour == 24) + { + hour = 0; + day++; + } + if (day == (get_days(month, year) + 1)) + { + day = 1; + month++; + } + if (month == 13) + { + month = 1; + year++; + } + nvr_dosave = 1; +} + +static void nvr_update_internal_clock() +{ + second++; + nvr_recalc_clock(); +} + +void nvr_add_10sec() +{ + time_sleep(10000); + if (!enable_sync) + { + second+=10; + nvr_recalc_clock(); + } +} + +static int to_12_hour(int org_hour) +{ + int hour2 = org_hour; + hour2 %= 12; + if (!hour2) hour2 = 12; + return hour2; +} + +static int from_12_hour(int org_hour) +{ + int hour2 = org_hour & 0x7F; + if (hour2 == 12) hour2 = 0; + if (hour & 0x80) hour2 += 12; + return hour2; +} + +static int week_day() +{ + int day_of_month = day; + int month2 = month; + int year2 = year % 100; + int century = ((year - year2) / 100) % 4; + int sum = day_of_month + month2 + year2 + century; + /* (sum mod 7) gives 0 for Saturday, we need it for Monday, so +5 */ + int raw_wd = ((sum + 5) % 7); + /* +1 so 1 = Monday, 7 = Sunday */ + return raw_wd + 1; +} + +/* Called on every get time. */ +static void set_registers() +{ + int is24hour = (nvrram[0xB] & 2) ? 1 : 0; + int isbcd = (nvrram[0xB] & 4) ? 0 : 1; + + uint8_t baknvr[10]; + + memcpy(baknvr,nvrram,10); + + if (AMSTRAD) + { + is24hour = 1; + isbcd = 1; + } + + nvrram[0] = final_form(isbcd, second); + nvrram[2] = final_form(isbcd, minute); + nvrram[4] = is24hour ? final_form(isbcd, hour) : final_form(isbcd, to_12_hour(hour)); + nvrram[6] = week_day(); + nvrram[7] = final_form(isbcd, day); + nvrram[8] = final_form(isbcd, month); + nvrram[9] = final_form(isbcd, (year % 100)); + + if (baknvr[0] != nvrram[0] || + baknvr[2] != nvrram[2] || + baknvr[4] != nvrram[4] || + baknvr[6] != nvrram[6] || + baknvr[7] != nvrram[7] || + baknvr[8] != nvrram[8] || + baknvr[9] != nvrram[9]) + nvrram[0xA]|=0x80; +} + +/* Called on NVR load and write. */ +static void get_registers() +{ + int is24hour = (nvrram[0xB] & 2) ? 1 : 0; + int isbcd = (nvrram[0xB] & 4) ? 0 : 1; + + int temp_hour = 0; + + if (AMSTRAD) + { + is24hour = 1; + isbcd = 1; + } + + second = original_form(isbcd, nvrram[0]); + minute = original_form(isbcd, nvrram[2]); + hour = is24hour ? original_form(isbcd, nvrram[4]) : from_12_hour(original_form(isbcd, nvrram[4])); + day = original_form(isbcd, nvrram[7]); + month = original_form(isbcd, nvrram[8]); + year = original_form(isbcd, nvrram[9]) + 1900; +} + +void getnvrtime() +{ + if (enable_sync) + { + /* Get time from host. */ + time_get(nvrram); + } + else + { + /* Get time from internal clock. */ + set_registers(); + } +} + +void update_sync() +{ + if (enable_sync) + { + /* Get time from host. */ + time_get(nvrram); + } + else + { + /* Save time to registers but keep it as is. */ + get_registers(); + } +} + +void nvr_recalc() +{ + int c; + int newrtctime; + c=1<<((nvrram[0xA]&0xF)-1); + newrtctime=(int)(RTCCONST * c * (1 << TIMER_SHIFT)); + if (rtctime>newrtctime) rtctime=newrtctime; +} + +void nvr_rtc(void *p) +{ + int c; + if (!(nvrram[0xA]&0xF)) + { + rtctime=0x7fffffff; + return; + } + c=1<<((nvrram[0xA]&0xF)-1); + rtctime += (int)(RTCCONST * c * (1 << TIMER_SHIFT)); +// pclog("RTCtime now %f\n",rtctime); + nvrram[0xC] |= 0x40; + if (nvrram[0xB]&0x40) + { + nvrram[0xC]|=0x80; + if (AMSTRAD) picint(2); + else picint(0x100); +// pclog("RTC int\n"); + } +} + +void nvr_onesec(void *p) +{ + nvr_onesec_cnt++; + if (nvr_onesec_cnt >= 100) + { + nvr_onesec_cnt = 0; + /* If sync is disabled, move internal clock ahead by 1 second. */ + if (!enable_sync) nvr_update_internal_clock(); + nvrram[0xC] |= 0x10; + if (nvrram[0xB] & 0x10) + { + nvrram[0xC] |= 0x80; + if (AMSTRAD) picint(2); + else picint(0x100); + } +// pclog("RTC onesec\n"); + } + nvr_onesec_time += (int)(10000 * TIMER_USEC); +} + +void writenvr(uint16_t addr, uint8_t val, void *priv) +{ + int c, old; +// printf("Write NVR %03X %02X %02X %04X:%04X %i\n",addr,nvraddr,val,cs>>4,pc,ins); + if (addr&1) + { +// if (nvraddr == 0x33) pclog("NVRWRITE33 %02X %04X:%04X %i\n",val,CS,pc,ins); + old = nvrram[nvraddr]; + if (nvraddr >= 0xe && nvrram[nvraddr] != val) + nvr_dosave = 1; + // if (nvraddr==0xB) update_reg_0B(val); + if (nvraddr!=0xC && nvraddr!=0xD) nvrram[nvraddr]=val; + + /* If not syncing the time with the host, we need to update our internal clock on write. */ + if (!enable_sync) + { + switch(nvraddr) + { + case 0: + case 2: + case 4: + case 6: + case 7: + case 8: + case 9: + if (old != val) + { + get_registers(); + nvr_dosave = 1; + } + return; + } + } + + if (nvraddr==0xA) + { +// pclog("NVR rate %i\n",val&0xF); + if (val&0xF) + { + c=1<<((val&0xF)-1); + rtctime += (int)(RTCCONST * c * (1 << TIMER_SHIFT)); + } + else + rtctime = 0x7fffffff; + } + } + else nvraddr=val&nvrmask; +} + +uint8_t readnvr(uint16_t addr, void *priv) +{ + uint8_t temp; +// printf("Read NVR %03X %02X %02X %04X:%04X\n",addr,nvraddr,nvrram[nvraddr],cs>>4,pc); + if (addr&1) + { + if (nvraddr<=0xA) getnvrtime(); + if (nvraddr==0xD) nvrram[0xD]|=0x80; + if (nvraddr==0xA) + { + temp=nvrram[0xA]; + nvrram[0xA]&=~0x80; + return temp; + } + if (nvraddr==0xC) + { + if (AMSTRAD) picintc(2); + else picintc(0x100); + temp=nvrram[0xC]; + nvrram[0xC]=0; + return temp; + } +// if (AMIBIOS && nvraddr==0x36) return 0; +// if (nvraddr==0xA) nvrram[0xA]^=0x80; + return nvrram[nvraddr]; + } + return nvraddr; +} + +void loadnvr() +{ + FILE *f; + int c; + nvrmask=63; + oldromset=romset; + switch (romset) + { + case ROM_PC1512: f = romfopen("nvr/pc1512.nvr", "rb"); break; + case ROM_PC1640: f = romfopen("nvr/pc1640.nvr", "rb"); break; + case ROM_PC200: f = romfopen("nvr/pc200.nvr", "rb"); break; + case ROM_PC2086: f = romfopen("nvr/pc2086.nvr", "rb"); break; + case ROM_PC3086: f = romfopen("nvr/pc3086.nvr", "rb"); break; + case ROM_IBMAT: f = romfopen("nvr/at.nvr", "rb"); break; + case ROM_IBMPS1_2011: f = romfopen("nvr/ibmps1_2011.nvr", "rb"); /*nvrmask = 127; */break; + case ROM_IBMPS1_2121: f = romfopen("nvr/ibmps1_2121.nvr", "rb"); nvrmask = 127; break; + case ROM_CMDPC30: f = romfopen("nvr/cmdpc30.nvr", "rb"); nvrmask = 127; break; + case ROM_AMI286: f = romfopen("nvr/ami286.nvr", "rb"); nvrmask = 127; break; + case ROM_AWARD286: f = romfopen("nvr/award286.nvr", "rb"); nvrmask = 127; break; + case ROM_DELL200: f = romfopen("nvr/dell200.nvr", "rb"); nvrmask = 127; break; + case ROM_IBMAT386: f = romfopen("nvr/at386.nvr", "rb"); nvrmask = 127; break; + case ROM_DESKPRO_386: f = romfopen("nvr/deskpro386.nvr", "rb"); break; + case ROM_ACER386: f = romfopen("nvr/acer386.nvr", "rb"); nvrmask = 127; break; + case ROM_MEGAPC: f = romfopen("nvr/megapc.nvr", "rb"); nvrmask = 127; break; + case ROM_AMI386: f = romfopen("nvr/ami386.nvr", "rb"); nvrmask = 127; break; + case ROM_AMI486: f = romfopen("nvr/ami486.nvr", "rb"); nvrmask = 127; break; + case ROM_WIN486: f = romfopen("nvr/win486.nvr", "rb"); nvrmask = 127; break; + case ROM_PCI486: f = romfopen("nvr/hot-433.nvr", "rb"); nvrmask = 127; break; + case ROM_SIS496: f = romfopen("nvr/sis496.nvr", "rb"); nvrmask = 127; break; + case ROM_430VX: f = romfopen("nvr/430vx.nvr", "rb"); nvrmask = 127; break; + case ROM_REVENGE: f = romfopen("nvr/revenge.nvr", "rb"); nvrmask = 127; break; + case ROM_ENDEAVOR: f = romfopen("nvr/endeavor.nvr", "rb"); nvrmask = 127; break; + case ROM_PX386: f = romfopen("nvr/px386.nvr", "rb"); nvrmask = 127; break; + case ROM_DTK386: f = romfopen("nvr/dtk386.nvr", "rb"); nvrmask = 127; break; + case ROM_DTK486: f = romfopen("nvr/dtk486.nvr", "rb"); nvrmask = 127; break; + case ROM_R418: f = romfopen("nvr/r418.nvr", "rb"); nvrmask = 127; break; + case ROM_586MC1: f = romfopen("nvr/586mc1.nvr", "rb"); nvrmask = 127; break; + case ROM_PLATO: f = romfopen("nvr/plato.nvr", "rb"); nvrmask = 127; break; + case ROM_MB500N: f = romfopen("nvr/mb500n.nvr", "rb"); nvrmask = 127; break; + case ROM_P54TP4XE: f = romfopen("nvr/p54tp4xe.nvr", "rb"); nvrmask = 127; break; + case ROM_ACERM3A: f = romfopen("nvr/acerm3a.nvr", "rb"); nvrmask = 127; break; + case ROM_ACERV35N: f = romfopen("nvr/acerv35n.nvr", "rb"); nvrmask = 127; break; + case ROM_P55T2P4: f = romfopen("nvr/p55t2p4.nvr", "rb"); nvrmask = 127; break; + case ROM_P55TVP4: f = romfopen("nvr/p55tvp4.nvr", "rb"); nvrmask = 127; break; + case ROM_P55VA: f = romfopen("nvr/p55va.nvr", "rb"); nvrmask = 127; break; + case ROM_440FX: f = romfopen("nvr/440fx.nvr", "rb"); nvrmask = 127; break; + case ROM_KN97: f = romfopen("nvr/kn97.nvr", "rb"); nvrmask = 127; break; + default: return; + } + if (!f) + { + memset(nvrram,0xFF,128); + return; + } + fread(nvrram,128,1,f); + if (!(feof(f))) + fread(internal_time,6,4,f); + else + { + if (!enable_sync) get_registers(); + } + fclose(f); + nvrram[0xA]=6; + nvrram[0xB]=0; + c=1<<((6&0xF)-1); + rtctime += (int)(RTCCONST * c * (1 << TIMER_SHIFT)); +} +void savenvr() +{ + FILE *f; + switch (oldromset) + { + case ROM_PC1512: f = romfopen("nvr/pc1512.nvr", "wb"); break; + case ROM_PC1640: f = romfopen("nvr/pc1640.nvr", "wb"); break; + case ROM_PC200: f = romfopen("nvr/pc200.nvr", "wb"); break; + case ROM_PC2086: f = romfopen("nvr/pc2086.nvr", "wb"); break; + case ROM_PC3086: f = romfopen("nvr/pc3086.nvr", "wb"); break; + case ROM_IBMAT: f = romfopen("nvr/at.nvr", "wb"); break; + case ROM_IBMPS1_2011: f = romfopen("nvr/ibmps1_2011.nvr", "wb"); break; + case ROM_IBMPS1_2121: f = romfopen("nvr/ibmps1_2121.nvr", "wb"); break; + case ROM_CMDPC30: f = romfopen("nvr/cmdpc30.nvr", "wb"); break; + case ROM_AMI286: f = romfopen("nvr/ami286.nvr", "wb"); break; + case ROM_AWARD286: f = romfopen("nvr/award286.nvr", "wb"); break; + case ROM_DELL200: f = romfopen("nvr/dell200.nvr", "wb"); break; + case ROM_IBMAT386: f = romfopen("nvr/at386.nvr", "wb"); break; + case ROM_DESKPRO_386: f = romfopen("nvr/deskpro386.nvr", "wb"); break; + case ROM_ACER386: f = romfopen("nvr/acer386.nvr", "wb"); break; + case ROM_MEGAPC: f = romfopen("nvr/megapc.nvr", "wb"); break; + case ROM_AMI386: f = romfopen("nvr/ami386.nvr", "wb"); break; + case ROM_AMI486: f = romfopen("nvr/ami486.nvr", "wb"); break; + case ROM_WIN486: f = romfopen("nvr/win486.nvr", "wb"); break; + case ROM_PCI486: f = romfopen("nvr/hot-433.nvr", "wb"); break; + case ROM_SIS496: f = romfopen("nvr/sis496.nvr", "wb"); break; + case ROM_430VX: f = romfopen("nvr/430vx.nvr", "wb"); break; + case ROM_REVENGE: f = romfopen("nvr/revenge.nvr", "wb"); break; + case ROM_ENDEAVOR: f = romfopen("nvr/endeavor.nvr", "wb"); break; + case ROM_PX386: f = romfopen("nvr/px386.nvr", "wb"); break; + case ROM_DTK386: f = romfopen("nvr/dtk386.nvr", "wb"); break; + case ROM_DTK486: f = romfopen("nvr/dtk486.nvr", "wb"); break; + case ROM_R418: f = romfopen("nvr/r418.nvr", "wb"); break; + case ROM_586MC1: f = romfopen("nvr/586mc1.nvr", "wb"); break; + case ROM_PLATO: f = romfopen("nvr/plato.nvr", "wb"); break; + case ROM_MB500N: f = romfopen("nvr/mb500n.nvr", "wb"); break; + case ROM_P54TP4XE: f = romfopen("nvr/p54tp4xe.nvr", "wb"); break; + case ROM_ACERM3A: f = romfopen("nvr/acerm3a.nvr", "wb"); break; + case ROM_ACERV35N: f = romfopen("nvr/acerv35n.nvr", "wb"); break; + case ROM_P55T2P4: f = romfopen("nvr/p55t2p4.nvr", "wb"); break; + case ROM_P55TVP4: f = romfopen("nvr/p55tvp4.nvr", "wb"); break; + case ROM_P55VA: f = romfopen("nvr/p55va.nvr", "wb"); break; + case ROM_440FX: f = romfopen("nvr/440fx.nvr", "wb"); break; + case ROM_KN97: f = romfopen("nvr/kn97.nvr", "wb"); break; + default: return; + } + /* If sync is disabled, save internal clock to registers. */ + if (!enable_sync) set_registers(); + fwrite(nvrram,128,1,f); + fwrite(internal_time,6,4,f); + fclose(f); +} + +void nvr_init() +{ + io_sethandler(0x0070, 0x0002, readnvr, NULL, NULL, writenvr, NULL, NULL, NULL); + timer_add(nvr_rtc, &rtctime, TIMER_ALWAYS_ENABLED, NULL); + timer_add(nvr_onesec, &nvr_onesec_time, TIMER_ALWAYS_ENABLED, NULL); +} diff --git a/src/nvr.h b/src/nvr.h new file mode 100644 index 000000000..fe3c72e1b --- /dev/null +++ b/src/nvr.h @@ -0,0 +1,11 @@ +void nvr_init(); + +extern int nvr_dosave; +extern int enable_sync; + +void time_sleep(int count); + +void time_get(char *nvrram); +void nvr_add_10sec(); + +void update_sync(); diff --git a/src/olivetti_m24.c b/src/olivetti_m24.c new file mode 100644 index 000000000..72f08a373 --- /dev/null +++ b/src/olivetti_m24.c @@ -0,0 +1,20 @@ +#include "ibm.h" +#include "io.h" +#include "olivetti_m24.h" + +uint8_t olivetti_m24_read(uint16_t port, void *priv) +{ + switch (port) + { + case 0x66: + return 0x00; + case 0x67: + return 0x20 | 0x40 | 0x0C; + } + return 0xff; +} + +void olivetti_m24_init() +{ + io_sethandler(0x0066, 0x0002, olivetti_m24_read, NULL, NULL, NULL, NULL, NULL, NULL); +} diff --git a/src/olivetti_m24.h b/src/olivetti_m24.h new file mode 100644 index 000000000..7475072f0 --- /dev/null +++ b/src/olivetti_m24.h @@ -0,0 +1 @@ +void olivetti_m24_init(); diff --git a/src/opti.c b/src/opti.c new file mode 100644 index 000000000..392837e05 --- /dev/null +++ b/src/opti.c @@ -0,0 +1,284 @@ +/*OPTi 82C495 emulation + This is the chipset used in the AMI386 model*/ +#include "ibm.h" + +uint8_t optiregs[0x10]; +int optireg; + +void writeopti(uint16_t addr, uint8_t val) +{ + switch (addr) + { + case 0x22: + optireg=val; + break; + case 0x24: + printf("Writing OPTI reg %02X %02X\n",optireg,val); + if (optireg>=0x20 && optireg<=0x2C) optiregs[optireg-0x20]=val; + break; + } +} + +uint8_t readopti(uint16_t addr) +{ + switch (addr) + { + case 0x24: + printf("Read OPTI reg %02X\n",optireg); + if (optireg>=0x20 && optireg<=0x2C) return optiregs[optireg-0x20]; + break; + } + return 0xFF; +} + +/*Details for the chipset from Ralph Brown's interrupt list + This describes the OPTi 82C493, the 82C495 seems similar except there is one + more register (2C) + +----------P00220024-------------------------- +PORT 0022-0024 - OPTi 82C493 System Controller (SYSC) - CONFIGURATION REGISTERS +Desc: The OPTi 486SXWB contains three chips and is designed for systems + running at 20, 25 and 33MHz. The chipset includes an 82C493 System + Controller (SYSC), the 82C392 Data Buffer Controller, and the + 82C206 Integrated peripheral Controller (IPC). +Note: every access to PORT 0024h must be preceded by a write to PORT 0022h, + even if the same register is being accessed a second time +SeeAlso: PORT 0022h"82C206" + +0022 ?W configuration register index (see #P0178) +0024 RW configuration register data + +(Table P0178) +Values for OPTi 82C493 System Controller configuration register index: + 20h Control Register 1 (see #P0179) + 21h Control Register 2 (see #P0180) + 22h Shadow RAM Control Register 1 (see #P0181) + 23h Shadow RAM Control Register 2 (see #P0182) + 24h DRAM Control Register 1 (see #P0183) + 25h DRAM Control Register 2 (see #P0184) + 26h Shadow RAM Control Register 3 (see #P0185) + 27h Control Register 3 (see #P0186) + 28h Non-cachable Block 1 Register 1 (see #P0187) + 29h Non-cachable Block 1 Register 2 (see #P0188) + 2Ah Non-cachable Block 2 Register 1 (see #P0187) + 2Bh Non-cachable Block 2 Register 2 (see #P0188) + +Bitfields for OPTi-82C493 Control Register 1: +Bit(s) Description (Table P0179) + 7-6 Revision of 82C493 (readonly) (default=01) + 5 Burst wait state control + 1 = Secondary cache read hit cycle is 3-2-2-2 or 2-2-2-2 + 0 = Secondary cache read hit cycle is 3-1-1-1 or 2-1-1-1 (default) + (if bit 5 is set to 1, bit 4 must be set to 0) + 4 Cache memory data buffer output enable control + 0 = disable (default) + 1 = enable + (must be disabled for frequency <= 33Mhz) + 3 Single Address Latch Enable (ALE) + 0 = disable (default) + 1 = enable + (if enabled, SYSC will activate single ALE rather than multiples + during bus conversion cycles) + 2 enable Extra AT Cycle Wait State (default is 0 = disabled) + 1 Emulation keyboard Reset Control + 0 = disable (default) + 1 = enable + Note: This bit must be enabled in BIOS default value; enabling this + bit requires HALT instruction to be executed before SYSC + generates processor reset (CPURST) + 0 enable Alternative Fast Reset (default is 0 = disabled) +SeeAlso: #P0180,#P0186 + +Bitfields for OPTi-82C493 Control Register 2: +Bit(s) Description (Table P0180) + 7 Master Mode Byte Swap Enable + 0 = disable (default) + 1 = enable + 6 Emulation Keyboard Reset Delay Control + 0 = Generate reset pulse 2us later (default) + 1 = Generate reset pulse immediately + 5 disable Parity Check (default is 0 = enabled) + 4 Cache Enable + 0 = Cache disabled and DRAM burst mode enabled (default) + 1 = Cache enabled and DRAM burst mode disabled + 3-2 Cache Size + 00 64KB (default) + 01 128KB + 10 256KB + 11 512KB + 1 Secondary Cache Read Burst Cycles Control + 0 = 3-1-1-1 cycle (default) + 1 = 2-1-1-1 cycle + 0 Cache Write Wait State Control + 0 = 1 wait state (default) + 1 = 0 wait state +SeeAlso: #P0179,#P0186 + +Bitfields for OPTi-82C493 Shadow RAM Control Register 1: +Bit(s) Description (Table P0181) + 7 ROM(F0000h - FFFFFh) Enable + 0 = read/write on write-protected DRAM + 1 = read from ROM, write to DRAM (default) + 6 Shadow RAM at D0000h - EFFFFh Area + 0 = disable (default) + 1 = enable + 5 Shadow RAM at E0000h - EFFFFh Area + 0 = disable shadow RAM (default) + E0000h - EFFFFh ROM is defaulted to reside on XD bus + 1 = enable shadow RAM + 4 enable write-protect for Shadow RAM at D0000h - DFFFFh Area + 0 = disable (default) + 1 = enable + 3 enable write-protect for Shadow RAM at E0000h - EFFFFh Area + 0 = disable (default) + 1 = enable + 2 Hidden refresh enable (with holding CPU) + (Hidden refresh must be disabled if 4Mx1 or 1M x4 bit DRAM are used) + 1 = disable (default) + 0 = enable + 1 unused + 0 enable Slow Refresh (four times slower than normal refresh) + (default is 0 = disable) +SeeAlso: #P0182 + +Bitfields for OPTi-82C493 Shadow RAM Control Register 2: +Bit(s) Description (Table P0182) + 7 enable Shadow RAM at EC000h - EFFFFh area + 6 enable Shadow RAM at E8000h - EBFFFh area + 5 enable Shadow RAM at E4000h - E7FFFh area + 4 enable Shadow RAM at E0000h - E3FFFh area + 3 enable Shadow RAM at DC000h - DFFFFh area + 2 enable Shadow RAM at D8000h - DBFFFh area + 1 enable Shadow RAM at D4000h - D7FFFh area + 0 enable Shadow RAM at D0000h - D3FFFh area +Note: the default is disabled (0) for all areas + +Bitfields for OPTi-82C493 DRAM Control Register 1: +Bit(s) Description (Table P0183) + 7 DRAM size + 0 = 256K DRAM mode + 1 = 1M and 4M DRAM mode + 6-4 DRAM types used for bank0 and bank1 + bits 7-4 Bank0 Bank1 + 0000 256K x + 0001 256K 256K + 0010 256K 1M + 0011 x x + 01xx x x + 1000 1M x (default) + 1001 1M 1M + 1010 1M 4M + 1011 4M 1M + 1100 4M x + 1101 4M 4M + 111x x x + 3 unused + 2-0 DRAM types used for bank2 and bank3 + bits 7,2-0 Bank2 Bank3 + x000 1M x + x001 1M 1M + x010 x x + x011 4M 1M + x100 4M x + x101 4M 4M + x11x x x (default) +SeeAlso: #P0184 + +Bitfields for OPTi-82C493 DRAM Control Register 2: +Bit(s) Description (Table P0184) + 7-6 Read cycle additional wait states + 00 not used + 01 = 0 + 10 = 1 + 11 = 2 (default) + 5-4 Write cycle additional wait states + 00 = 0 + 01 = 1 + 10 = 2 + 11 = 3 (default) + 3 Fast decode enable + 0 = disable fast decode. DRAM base wait states not changed (default) + 1 = enable fast decode. DRAM base wait state is decreased by 1 + Note: This function may be enabled in 20/25Mhz operation to speed up + DRAM access. If bit 4 of index register 21h (cache enable + bit) is enabled, this bit is automatically disabled--even if + set to 1 + 2 unused + 1-0 ATCLK selection + 00 ATCLK = CLKI/6 (default) + 01 ATCLK = CLKI/4 (default) + 10 ATCLK = CLKI/3 + 11 ATCLK = CLK2I/5 (CLKI * 2 /5) + Note: bit 0 will reflect the BCLKS (pin 142) status and bit 1 will be + set to 0 when 82C493 is reset. +SeeAlso: #P0183,#P0185 + +Bitfields for OPTi-82C493 Shadow RAM Control Register 3: +Bit(s) Description (Table P0185) + 7 unused + 6 Shadow RAM copy enable for address C0000h - CFFFFh + 0 = Read/write at AT bus (default) + 1 = Read from AT bus and write into shadow RAM + 5 Shadow write protect at address C0000h - CFFFFh + 0 = Write protect disable (default) + 1 = Write protect enable + 4 enable Shadow RAM at C0000h - CFFFFh + 3 enable Shadow RAM at CC000h - CFFFFh + 2 enable Shadow RAM at C8000h - CBFFFh + 1 enable Shadow RAM at C4000h - C7FFFh + 0 enable Shadow RAM at C0000h - C3FFFh +Note: the default is disabled (0) for bits 4-0 +SeeAlso: #P0183,#P0184 + +Bitfields for OPTi-82C493 Control Register 3: +Bit(s) Description (Table P0186) + 7 enable NCA# pin to low state (default is 1 = enabled) + 6-5 unused + 4 Video BIOS at C0000h - C8000h non-cacheable + 0 = cacheable + 1 = non-cacheable (default) + 3-0 Cacheable address range for local memory + 0000 0 - 64MB + 0001 0 - 4MB (default) + 0010 0 - 8MB + 0011 0 - 12MB + 0100 0 - 16MB + 0101 0 - 20MB + 0110 0 - 24MB + 0111 0 - 28MB + 1000 0 - 32MB + 1001 0 - 36MB + 1010 0 - 40MB + 1011 0 - 44MB + 1100 0 - 48MB + 1101 0 - 52MB + 1110 0 - 56MB + 1111 0 - 60MB + Note: If total memory is 1MB or 2MB the cacheable range is 0-1 MB or + 0-2 MB and independent of the value of bits 3-0 +SeeAlso: #P0179,#P0180 + +Bitfields for OPTi-82C493 Non-cacheable Block Register 1: +Bit(s) Description (Table P0187) + 7-5 Size of non-cachable memory block + 000 64K + 001 128K + 010 256K + 011 512K + 1xx disabled (default) + 4-2 unused + 1-0 Address bits 25 and 24 of non-cachable memory block (default = 00) +Note: this register is used together with configuration register 29h + (non-cacheable block 1) or register 2Bh (block 2) (see #P0188) to + define a non-cacheable block. The starting address must be a + multiple of the block size +SeeAlso: #P0178,#P0188 + +Bitfields for OPTi-82C493 Non-cacheable Block Register 2: +Bit(s) Description (Table P0188) + 7-0 Address bits 23-16 of non-cachable memory block (default = 0001xxxx) +Note: the block address is forced to be a multiple of the block size by + ignoring the appropriate number of the least-significant bits +SeeAlso: #P0178,#P0187 + +*/ diff --git a/src/pc.c b/src/pc.c new file mode 100644 index 000000000..c5a7b9441 --- /dev/null +++ b/src/pc.c @@ -0,0 +1,809 @@ +#include +#include +#include +#include "ibm.h" +#include "device.h" + +#include "ali1429.h" +#include "amstrad.h" +#include "cdrom-ioctl.h" +#include "disc.h" +#include "mem.h" +#include "x86_ops.h" +#include "codegen.h" +#include "cdrom-iso.h" +#include "cdrom-null.h" +#include "config.h" +#include "cpu.h" +#include "dma.h" +#include "fdc.h" +#include "fdd.h" +#include "gameport.h" +#include "sound_gus.h" +#include "ide.h" +#include "keyboard.h" +#include "keyboard_at.h" +#include "model.h" +#include "mouse.h" +#include "nvr.h" +#include "pic.h" +#include "pit.h" +#include "plat-joystick.h" +#include "plat-mouse.h" +#include "serial.h" +#include "sound.h" +#include "sound_cms.h" +#include "sound_opl.h" +#include "sound_sb.h" +#include "sound_ssi2001.h" +#include "timer.h" +#include "vid_voodoo.h" +#include "video.h" +#include "nethandler.h" +#define NE2000 1 +#define RTL8029AS 2 +uint8_t ethif; +int inum; + +int window_w, window_h, window_x, window_y, window_remember; + +int start_in_fullscreen = 0; +int frame = 0; + +int cdrom_enabled; +int CPUID; +int vid_resize, vid_api; + +int cycles_lost = 0; + +int clockrate; +int insc=0; +float mips,flops; +extern int mmuflush; +extern int readlnum,writelnum; +void fullspeed(); + +int framecount,fps; +int intcount; + +int output; +int atfullspeed; + +void saveconfig(); +int infocus; +int mousecapture; +// FILE *pclogf; +void pclog(const char *format, ...) +{ +#ifndef RELEASE_BUILD + va_list ap; + va_start(ap, format); + vprintf(format, ap); + va_end(ap); + fflush(stdout); +#endif +} + +void fatal(const char *format, ...) +{ + va_list ap; + va_start(ap, format); + vprintf(format, ap); + va_end(ap); + fflush(stdout); + dumppic(); + dumpregs(); + fflush(stdout); + exit(-1); +} + +uint8_t cgastat; + +int pollmouse_delay = 2; +void pollmouse() +{ + int x,y; +// return; + pollmouse_delay--; + if (pollmouse_delay) return; + pollmouse_delay = 2; + mouse_poll_host(); + mouse_get_mickeys(&x,&y); + if (mouse_poll) + mouse_poll(x, y, mouse_buttons); +// if (mousecapture) position_mouse(64,64); +} + +/*PC1512 languages - + 7=English + 6=German + 5=French + 4=Spanish + 3=Danish + 2=Swedish + 1=Italian + 3,2,1 all cause the self test to fail for some reason + */ + +int cpuspeed2; + +int clocks[3][12][4]= +{ + { + {4772728,13920,59660,5965}, /*4.77MHz*/ + {8000000,23333,110000,0}, /*8MHz*/ + {10000000,29166,137500,0}, /*10MHz*/ + {12000000,35000,165000,0}, /*12MHz*/ + {16000000,46666,220000,0}, /*16MHz*/ + }, + { + {8000000,23333,110000,0}, /*8MHz*/ + {12000000,35000,165000,0}, /*12MHz*/ + {16000000,46666,220000,0}, /*16MHz*/ + {20000000,58333,275000,0}, /*20MHz*/ + {25000000,72916,343751,0}, /*25MHz*/ + }, + { + {16000000, 46666,220000,0}, /*16MHz*/ + {20000000, 58333,275000,0}, /*20MHz*/ + {25000000, 72916,343751,0}, /*25MHz*/ + {33000000, 96000,454000,0}, /*33MHz*/ + {40000000,116666,550000,0}, /*40MHz*/ + {50000000, 72916*2,343751*2,0}, /*50MHz*/ + {33000000*2, 96000*2,454000*2,0}, /*66MHz*/ + {75000000, 72916*3,343751*3,0}, /*75MHz*/ + {80000000,116666*2,550000*2,0}, /*80MHz*/ + {100000000, 72916*4,343751*4,0}, /*100MHz*/ + {120000000,116666*3,550000*3,0}, /*120MHz*/ + {133000000, 96000*4,454000*4,0}, /*133MHz*/ + } +}; + +int updatestatus; +int win_title_update=0; + + +void onesec() +{ + fps=framecount; + framecount=0; + win_title_update=1; +} + +void pc_reset() +{ + cpu_set(); + resetx86(); + mem_updatecache(); + //timer_reset(); + dma_reset(); + fdc_reset(); + pic_reset(); + pit_reset(); + serial_reset(); + + if (AT) + setpitclock(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed); + else + setpitclock(14318184.0); + +// sb_reset(); + + ali1429_reset(); +// video_init(); +} +#undef printf +void initpc(int argc, char *argv[]) +{ + char *p; + char *config_file = NULL; + int c; + FILE *ff; +// allegro_init(); + get_executable_name(pcempath,511); + pclog("executable_name = %s\n", pcempath); + p=get_filename(pcempath); + *p=0; + pclog("path = %s\n", pcempath); + + for (c = 1; c < argc; c++) + { + if (!strcasecmp(argv[c], "--help")) + { + printf("PCem command line options :\n\n"); + printf("--config file.cfg - use given config file as initial configuration\n"); + printf("--fullscreen - start in fullscreen mode\n"); + exit(-1); + } + else if (!strcasecmp(argv[c], "--fullscreen")) + { + start_in_fullscreen = 1; + } + else if (!strcasecmp(argv[c], "--config")) + { + if ((c+1) == argc) + break; + config_file = argv[c+1]; + c++; + } + } + + keyboard_init(); + mouse_init(); + joystick_init(); + midi_init(); + + append_filename(config_file_default, pcempath, "pcem.cfg", 511); + + loadconfig(config_file); + pclog("Config loaded\n"); + if (config_file) + saveconfig(); + + codegen_init(); + + cpuspeed2=(AT)?2:1; +// cpuspeed2=cpuspeed; + atfullspeed=0; + + initvideo(); + mem_init(); + loadbios(); + mem_add_bios(); + + device_init(); + + timer_reset(); + sound_reset(); + fdc_init(); + disc_init(); + fdi_init(); + img_init(); + + vlan_reset(); //NETWORK + network_card_init(network_card_current); + + disc_load(0, discfns[0]); + disc_load(1, discfns[1]); + + //loadfont(); + loadnvr(); + sound_init(); + resetide(); + if ((cdrom_drive == -1) || (cdrom_drive == 0)) + cdrom_null_open(cdrom_drive); + else + { + if (cdrom_drive == 200) + { + ff = fopen(iso_path, "rb"); + if (ff) + { + fclose(ff); + iso_open(iso_path); + } + else + { +#if __unix + cdrom_drive = -1; +#else + cdrom_drive = 0; +#endif + cdrom_null_open(cdrom_drive); + } + } + else + { + ioctl_open(cdrom_drive); + } + } + + pit_reset(); +/* if (romset==ROM_AMI386 || romset==ROM_AMI486) */fullspeed(); + ali1429_reset(); +// CPUID=(is486 && (cpuspeed==7 || cpuspeed>=9)); +// pclog("Init - CPUID %i %i\n",CPUID,cpuspeed); + shadowbios=0; + + if ((cdrom_drive == -1) || (cdrom_drive == 0)) + cdrom_null_reset(); + else + { + if (cdrom_drive == 200) + { + iso_reset(); + } + else + { + ioctl_reset(); + } + } +} + +void resetpc() +{ + pc_reset(); +// cpuspeed2=(AT)?2:1; +// atfullspeed=0; +///* if (romset==ROM_AMI386 || romset==ROM_AMI486) */fullspeed(); + shadowbios=0; +} + +void pc_keyboard_send(uint8_t val) +{ + if (AT) + { + keyboard_at_adddata_keyboard_raw(val); + } + else + { + keyboard_send(val); + } +} + +void resetpc_cad() +{ + pc_keyboard_send(29); /* Ctrl key pressed */ + pc_keyboard_send(56); /* Alt key pressed */ + pc_keyboard_send(83); /* Delete key pressed */ + pc_keyboard_send(157); /* Ctrl key released */ + pc_keyboard_send(184); /* Alt key released */ + pc_keyboard_send(211); /* Delete key released */ +} + +void resetpchard() +{ + savenvr(); + + device_close_all(); + device_init(); + + midi_close(); + midi_init(); + + timer_reset(); + sound_reset(); + mem_resize(); + fdc_init(); + disc_reset(); + + model_init(); + // mem_add_bios(); + video_init(); + speaker_init(); + + vlan_reset(); //NETWORK + network_card_init(network_card_current); + + sound_card_init(sound_card_current); + if (GUS) + device_add(&gus_device); + if (GAMEBLASTER) + device_add(&cms_device); + if (SSI2001) + device_add(&ssi2001_device); + if (voodoo_enabled) + device_add(&voodoo_device); + pc_reset(); + + resetide(); + + loadnvr(); + +// cpuspeed2 = (AT)?2:1; +// atfullspeed = 0; +// setpitclock(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed); + + shadowbios = 0; + ali1429_reset(); + + keyboard_at_reset(); + +// output=3; + + if ((cdrom_drive == -1) || (cdrom_drive == 0)) + cdrom_null_reset(); + else + { + if (cdrom_drive == 200) + { + iso_reset(); + } + else + { + ioctl_reset(); + } + } +} + +char romsets[17][40]={"IBM PC","IBM XT","Generic Turbo XT","Euro PC","Tandy 1000","Amstrad PC1512","Sinclair PC200","Amstrad PC1640","IBM AT","AMI 286 clone","Dell System 200","Misc 286","IBM AT 386","Misc 386","386 clone","486 clone","486 clone 2"}; +char clockspeeds[3][12][16]= +{ + {"4.77MHz","8MHz","10MHz","12MHz","16MHz"}, + {"8MHz","12MHz","16MHz","20MHz","25MHz"}, + {"16MHz","20MHz","25MHz","33MHz","40MHz","50MHz","66MHz","75MHz","80MHz","100MHz","120MHz","133MHz"}, +}; +int framecountx=0; +int sndcount=0; +int oldat70hz; + +int sreadlnum,swritelnum,segareads,segawrites, scycles_lost; + +int serial_fifo_read, serial_fifo_write; + +int emu_fps = 0; + +void runpc() +{ + char s[200]; + int done=0; + + startblit(); + clockrate = models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed; + + if (is386) + { + if (cpu_use_dynarec) + exec386_dynarec(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed / 100); + else + exec386(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed / 100); + } + else if (AT) + exec386(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed / 100); + else + execx86(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed / 100); + + keyboard_poll_host(); + keyboard_process(); +// checkkeys(); + pollmouse(); + joystick_poll(); + endblit(); + + framecountx++; + framecount++; + if (framecountx>=100) + { + pclog("onesec\n"); + framecountx=0; + mips=(float)insc/1000000.0f; + insc=0; + flops=(float)fpucount/1000000.0f; + fpucount=0; + sreadlnum=readlnum; + swritelnum=writelnum; + segareads=egareads; + segawrites=egawrites; + scycles_lost = cycles_lost; + + cpu_recomp_blocks_latched = cpu_recomp_blocks; + cpu_recomp_ins_latched = cpu_recomp_ins; + cpu_recomp_full_ins_latched = cpu_recomp_full_ins; + cpu_new_blocks_latched = cpu_new_blocks; + cpu_recomp_flushes_latched = cpu_recomp_flushes; + cpu_recomp_evicted_latched = cpu_recomp_evicted; + cpu_recomp_reuse_latched = cpu_recomp_reuse; + cpu_recomp_removed_latched = cpu_recomp_removed; + cpu_reps_latched = cpu_reps; + cpu_notreps_latched = cpu_notreps; + + cpu_recomp_blocks = 0; + cpu_recomp_ins = 0; + cpu_recomp_full_ins = 0; + cpu_new_blocks = 0; + cpu_recomp_flushes = 0; + cpu_recomp_evicted = 0; + cpu_recomp_reuse = 0; + cpu_recomp_removed = 0; + cpu_reps = 0; + cpu_notreps = 0; + + updatestatus=1; + readlnum=writelnum=0; + egareads=egawrites=0; + cycles_lost = 0; + mmuflush=0; + intcount=0; + intcount=pitcount=0; + emu_fps = frames; + frames = 0; + } + if (win_title_update) + { + win_title_update=0; + sprintf(s, "PCem v11 [Experimental] - %i%% - %s - %s - %s", fps, model_getname(), models[model].cpu[cpu_manufacturer].cpus[cpu].name, (!mousecapture) ? "Click to capture mouse" : "Press F12-F8 or middle button to release mouse"); + set_window_title(s); + } + done++; + frame++; +} + +void fullspeed() +{ + cpuspeed2=cpuspeed; + if (!atfullspeed) + { + printf("Set fullspeed - %i %i %i\n",is386,AT,cpuspeed2); + if (AT) + setpitclock(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed); + else + setpitclock(14318184.0); +// if (is386) setpitclock(clocks[2][cpuspeed2][0]); +// else setpitclock(clocks[AT?1:0][cpuspeed2][0]); + } + atfullspeed=1; + nvr_recalc(); +} + +void speedchanged() +{ + if (AT) + setpitclock(models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed); + else + setpitclock(14318184.0); + mem_updatecache(); + nvr_recalc(); +} + +void closepc() +{ + atapi->exit(); +// ioctl_close(); + dumppic(); +// output=7; +// setpitclock(clocks[0][0][0]); +// while (1) runpc(); + disc_close(0); + disc_close(1); + dumpregs(); + closevideo(); + device_close_all(); + midi_close(); +} + +/*int main() +{ + initpc(); + while (!key[KEY_F11]) + { + runpc(); + } + closepc(); + return 0; +} + +END_OF_MAIN();*/ + +int cga_comp=0; + +void loadconfig(char *fn) +{ + int c, d; + char s[512]; + char *p; + + if (!fn) + config_load(config_file_default); + else + config_load(fn); + + GAMEBLASTER = config_get_int(NULL, "gameblaster", 0); + GUS = config_get_int(NULL, "gus", 0); + SSI2001 = config_get_int(NULL, "ssi2001", 0); + voodoo_enabled = config_get_int(NULL, "voodoo", 0); + + //network + ethif = config_get_int(NULL, "netinterface", 1); + if (ethif >= inum) + inum = ethif + 1; + network_card_current = config_get_int(NULL, "netcard", NE2000); + + model = config_get_int(NULL, "model", 14); + + if (model >= model_count()) + model = model_count() - 1; + + romset = model_getromset(); + cpu_manufacturer = config_get_int(NULL, "cpu_manufacturer", 0); + cpu = config_get_int(NULL, "cpu", 0); + cpu_use_dynarec = config_get_int(NULL, "cpu_use_dynarec", 0); + + gfxcard = config_get_int(NULL, "gfxcard", 0); + video_speed = config_get_int(NULL, "video_speed", 3); + sound_card_current = config_get_int(NULL, "sndcard", SB2); + + p = (char *)config_get_string(NULL, "disc_a", ""); + if (p) strcpy(discfns[0], p); + else strcpy(discfns[0], ""); + + p = (char *)config_get_string(NULL, "disc_b", ""); + if (p) strcpy(discfns[1], p); + else strcpy(discfns[1], ""); + + mem_size = config_get_int(NULL, "mem_size", 4096); + if (mem_size < (models[model].is_at ? models[model].min_ram*1024 : models[model].min_ram)) + mem_size = (models[model].is_at ? models[model].min_ram*1024 : models[model].min_ram); + + cdrom_drive = config_get_int(NULL, "cdrom_drive", 0); + old_cdrom_drive = cdrom_drive; + cdrom_enabled = config_get_int(NULL, "cdrom_enabled", 0); + + cdrom_channel = config_get_int(NULL, "cdrom_channel", 2); + + p = (char *)config_get_string(NULL, "cdrom_path", ""); + if (p) strcpy(iso_path, p); + else strcpy(iso_path, ""); + + slowega = config_get_int(NULL, "slow_video", 1); + cache = config_get_int(NULL, "cache", 3); + cga_comp = config_get_int(NULL, "cga_composite", 0); + + vid_resize = config_get_int(NULL, "vid_resize", 0); + vid_api = config_get_int(NULL, "vid_api", 0); + video_fullscreen_scale = config_get_int(NULL, "video_fullscreen_scale", 0); + video_fullscreen_first = config_get_int(NULL, "video_fullscreen_first", 1); + + hdc[0].spt = config_get_int(NULL, "hdc_sectors", 0); + hdc[0].hpc = config_get_int(NULL, "hdc_heads", 0); + hdc[0].tracks = config_get_int(NULL, "hdc_cylinders", 0); + p = (char *)config_get_string(NULL, "hdc_fn", ""); + if (p) strcpy(ide_fn[0], p); + else strcpy(ide_fn[0], ""); + hdc[1].spt = config_get_int(NULL, "hdd_sectors", 0); + hdc[1].hpc = config_get_int(NULL, "hdd_heads", 0); + hdc[1].tracks = config_get_int(NULL, "hdd_cylinders", 0); + p = (char *)config_get_string(NULL, "hdd_fn", ""); + if (p) strcpy(ide_fn[1], p); + else strcpy(ide_fn[1], ""); + hdc[2].spt = config_get_int(NULL, "hde_sectors", 0); + hdc[2].hpc = config_get_int(NULL, "hde_heads", 0); + hdc[2].tracks = config_get_int(NULL, "hde_cylinders", 0); + p = (char *)config_get_string(NULL, "hde_fn", ""); + if (p) strcpy(ide_fn[2], p); + else strcpy(ide_fn[2], ""); + hdc[3].spt = config_get_int(NULL, "hdf_sectors", 0); + hdc[3].hpc = config_get_int(NULL, "hdf_heads", 0); + hdc[3].tracks = config_get_int(NULL, "hdf_cylinders", 0); + p = (char *)config_get_string(NULL, "hdf_fn", ""); + if (p) strcpy(ide_fn[3], p); + else strcpy(ide_fn[3], ""); + + fdd_set_type(0, config_get_int(NULL, "drive_a_type", 7)); + fdd_set_type(1, config_get_int(NULL, "drive_b_type", 7)); + + force_43 = config_get_int(NULL, "force_43", 0); + enable_overscan = config_get_int(NULL, "enable_overscan", 0); + cga_color_burst = config_get_int(NULL, "cga_color_burst", 1); + cga_brown = config_get_int(NULL, "cga_brown", 1); + enable_flash = config_get_int(NULL, "enable_flash", 1); + + enable_sync = config_get_int(NULL, "enable_sync", 0); + mouse_always_serial = config_get_int(NULL, "mouse_always_serial", 0); + + window_w = config_get_int(NULL, "window_w", 0); + window_h = config_get_int(NULL, "window_h", 0); + window_x = config_get_int(NULL, "window_x", 0); + window_y = config_get_int(NULL, "window_y", 0); + window_remember = config_get_int(NULL, "window_remember", 0); + + joystick_type = config_get_int(NULL, "joystick_type", 0); + + for (c = 0; c < joystick_get_max_joysticks(joystick_type); c++) + { + sprintf(s, "joystick_%i_nr", c); + joystick_state[c].plat_joystick_nr = config_get_int("Joysticks", s, 0); + + if (joystick_state[c].plat_joystick_nr) + { + for (d = 0; d < joystick_get_axis_count(joystick_type); d++) + { + sprintf(s, "joystick_%i_axis_%i", c, d); + joystick_state[c].axis_mapping[d] = config_get_int("Joysticks", s, d); + } + for (d = 0; d < joystick_get_button_count(joystick_type); d++) + { + sprintf(s, "joystick_%i_button_%i", c, d); + joystick_state[c].button_mapping[d] = config_get_int("Joysticks", s, d); + } + } + } +} + +void saveconfig() +{ + int c, d; + + config_set_int(NULL, "gameblaster", GAMEBLASTER); + config_set_int(NULL, "gus", GUS); + config_set_int(NULL, "ssi2001", SSI2001); + config_set_int(NULL, "voodoo", voodoo_enabled); + + config_set_int(NULL, "netinterface", ethif); + config_set_int(NULL, "netcard", network_card_current); + + config_set_int(NULL, "model", model); + config_set_int(NULL, "cpu_manufacturer", cpu_manufacturer); + config_set_int(NULL, "cpu", cpu); + config_set_int(NULL, "cpu_use_dynarec", cpu_use_dynarec); + + config_set_int(NULL, "gfxcard", gfxcard); + config_set_int(NULL, "video_speed", video_speed); + config_set_int(NULL, "sndcard", sound_card_current); + config_set_int(NULL, "cpu_speed", cpuspeed); + config_set_int(NULL, "has_fpu", hasfpu); + config_set_int(NULL, "slow_video", slowega); + config_set_int(NULL, "cache", cache); + config_set_int(NULL, "cga_composite", cga_comp); + config_set_string(NULL, "disc_a", discfns[0]); + config_set_string(NULL, "disc_b", discfns[1]); + config_set_int(NULL, "mem_size", mem_size); + config_set_int(NULL, "cdrom_drive", cdrom_drive); + config_set_int(NULL, "cdrom_enabled", cdrom_enabled); + config_set_int(NULL, "cdrom_channel", cdrom_channel); + config_set_string(NULL, "cdrom_path", iso_path); + config_set_int(NULL, "vid_resize", vid_resize); + config_set_int(NULL, "vid_api", vid_api); + config_set_int(NULL, "video_fullscreen_scale", video_fullscreen_scale); + config_set_int(NULL, "video_fullscreen_first", video_fullscreen_first); + + config_set_int(NULL, "hdc_sectors", hdc[0].spt); + config_set_int(NULL, "hdc_heads", hdc[0].hpc); + config_set_int(NULL, "hdc_cylinders", hdc[0].tracks); + config_set_string(NULL, "hdc_fn", ide_fn[0]); + config_set_int(NULL, "hdd_sectors", hdc[1].spt); + config_set_int(NULL, "hdd_heads", hdc[1].hpc); + config_set_int(NULL, "hdd_cylinders", hdc[1].tracks); + config_set_string(NULL, "hdd_fn", ide_fn[1]); + config_set_int(NULL, "hde_sectors", hdc[2].spt); + config_set_int(NULL, "hde_heads", hdc[2].hpc); + config_set_int(NULL, "hde_cylinders", hdc[2].tracks); + config_set_string(NULL, "hde_fn", ide_fn[2]); + config_set_int(NULL, "hdf_sectors", hdc[3].spt); + config_set_int(NULL, "hdf_heads", hdc[3].hpc); + config_set_int(NULL, "hdf_cylinders", hdc[3].tracks); + config_set_string(NULL, "hdf_fn", ide_fn[3]); + + config_set_int(NULL, "drive_a_type", fdd_get_type(0)); + config_set_int(NULL, "drive_b_type", fdd_get_type(1)); + + config_set_int(NULL, "force_43", force_43); + config_set_int(NULL, "enable_overscan", enable_overscan); + config_set_int(NULL, "cga_color_burst", cga_color_burst); + config_set_int(NULL, "cga_brown", cga_brown); + config_set_int(NULL, "enable_flash", enable_flash); + + config_set_int(NULL, "enable_sync", enable_sync); + config_set_int(NULL, "mouse_always_serial", mouse_always_serial); + + config_set_int(NULL, "joystick_type", joystick_type); + + for (c = 0; c < joystick_get_max_joysticks(joystick_type); c++) + { + char s[80]; + + sprintf(s, "joystick_%i_nr", c); + config_set_int("Joysticks", s, joystick_state[c].plat_joystick_nr); + + if (joystick_state[c].plat_joystick_nr) + { + for (d = 0; d < joystick_get_axis_count(joystick_type); d++) + { + sprintf(s, "joystick_%i_axis_%i", c, d); + config_set_int("Joysticks", s, joystick_state[c].axis_mapping[d]); + } + for (d = 0; d < joystick_get_button_count(joystick_type); d++) + { + sprintf(s, "joystick_%i_button_%i", c, d); + config_set_int("Joysticks", s, joystick_state[c].button_mapping[d]); + } + } + } + + config_set_int(NULL, "window_w", window_w); + config_set_int(NULL, "window_h", window_h); + config_set_int(NULL, "window_x", window_x); + config_set_int(NULL, "window_y", window_y); + config_set_int(NULL, "window_remember", window_remember); + + config_save(config_file_default); +} diff --git a/src/pc.rc b/src/pc.rc new file mode 100644 index 000000000..a820d6f35 --- /dev/null +++ b/src/pc.rc @@ -0,0 +1,252 @@ +#include +#include "resources.h" + +#ifndef UPDOWN_CLASS +#define UPDOWN_CLASS L"msctls_updown32" +#endif + +MainMenu MENU DISCARDABLE +BEGIN + POPUP "&File" + BEGIN + MENUITEM "&Hard Reset", IDM_FILE_HRESET + MENUITEM "&Ctrl+Alt+Del", IDM_FILE_RESET_CAD + MENUITEM "E&xit", IDM_FILE_EXIT + END + POPUP "&Disc" + BEGIN + MENUITEM "Change drive &A:...", IDM_DISC_A + MENUITEM "Change drive &B:...", IDM_DISC_B + MENUITEM "&Eject drive A:", IDM_EJECT_A + MENUITEM "Eject drive B:", IDM_EJECT_B + MENUITEM "&Configure hard discs...",IDM_HDCONF + END + POPUP "&Settings" + BEGIN + MENUITEM "&Configure...", IDM_CONFIG + POPUP "&CD-ROM" + BEGIN + MENUITEM "&Disabled", IDM_CDROM_DISABLED + MENUITEM "&Empty",IDM_CDROM_EMPTY + MENUITEM "&ISO...",IDM_CDROM_ISO + END + POPUP "&Video" + BEGIN + MENUITEM "&Resizeable window",IDM_VID_RESIZE + MENUITEM "Remember size && position",IDM_VID_REMEMBER + MENUITEM SEPARATOR + MENUITEM "&DirectDraw", IDM_VID_DDRAW + MENUITEM "Direct&3D", IDM_VID_D3D + MENUITEM SEPARATOR + MENUITEM "&Fullscreen", IDM_VID_FULLSCREEN + POPUP "Fullscreen &stretch mode" + BEGIN + MENUITEM "&Full screen stretch", IDM_VID_FS_FULL + MENUITEM "&4:3", IDM_VID_FS_43 + MENUITEM "&Square pixels", IDM_VID_FS_SQ + MENUITEM "&Integer scale", IDM_VID_FS_INT + END + END + MENUITEM SEPARATOR + MENUITEM "&Load configuration...", IDM_CONFIG_LOAD + MENUITEM "&Save configuration...", IDM_CONFIG_SAVE + END + POPUP "&Misc" + BEGIN + MENUITEM "&Status", IDM_STATUS + END +END + +ConfigureDlg DIALOGEX 0, 0, 248+40, 248+76 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Configure PCem" +FONT 9, "Segoe UI" +BEGIN + DEFPUSHBUTTON "OK",IDOK,64,300,50,14, WS_TABSTOP + PUSHBUTTON "Cancel",IDCANCEL,128,300,50,14, WS_TABSTOP + COMBOBOX IDC_COMBO1,62,16,157,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBOVID,62,36,157,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure", IDC_CONFIGUREVID, 224, 36, 40, 14, WS_TABSTOP + COMBOBOX IDC_COMBOCPUM,62,56,157,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBO3,62,76,102,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + CONTROL "Dynamic Recompiler",IDC_CHECKDYNAREC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,169,76,99,10 + COMBOBOX IDC_COMBOCHC,62,96,57,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBOSPD,162,96,57,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBOSND,62,116,157,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure", IDC_CONFIGURESND, 224, 116, 40, 14, WS_TABSTOP + EDITTEXT IDC_MEMTEXT, 62, 136, 36, 14, ES_AUTOHSCROLL | ES_NUMBER + CONTROL "", IDC_MEMSPIN, UPDOWN_CLASS, UDS_ALIGNRIGHT | UDS_ARROWKEYS | UDS_NOTHOUSANDS | UDS_SETBUDDYINT, 98, 136, 12, 14 + LTEXT "MB", IDC_TEXT_MB, 98, 136, 10, 10 + CONTROL "CMS / Game Blaster",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,172,102,10 + CONTROL "Gravis Ultrasound",IDC_CHECKGUS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,188,102,10 + CONTROL "Innovation SSI-2001",IDC_CHECKSSI,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,204,102,10 + CONTROL "Composite CGA",IDC_CHECK4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,220,102,10 + CONTROL "Enable time sync",IDC_CHECKSYNC,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,236,102,10 + + CONTROL "Force 4:3 display ratio",IDC_CHECKFORCE43,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,118,172,102,10 + CONTROL "Composite CGA color burst",IDC_CHECKCBURST,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,118,188,102,10 + CONTROL "RGB CGA brown circuit",IDC_CHECKBROWN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,118,204,102,10 + CONTROL "EGA/(S)VGA overscan",IDC_CHECKOVERSCAN,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,118,220,102,10 + CONTROL "Disk activity flash",IDC_CHECKFLASH,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,118,236,102,10 + + CONTROL "Ser. mouse instead of PS/2",IDC_CHECKSERIAL,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,252,102,10 + + CONTROL "Voodoo Graphics",IDC_CHECKVOODOO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,118,252,102,10 + PUSHBUTTON "Configure", IDC_CONFIGUREVOODOO, 224, 252, 40, 14, WS_TABSTOP + + LTEXT "Joystick :",IDC_STATIC,15,268,40,10 + COMBOBOX IDC_COMBOJOY,62,268,157,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + DEFPUSHBUTTON "Joystick 1...",IDC_JOY1,16,284,50,14, WS_TABSTOP + PUSHBUTTON "Joystick 2...",IDC_JOY2,80,284,50,14, WS_TABSTOP + DEFPUSHBUTTON "Joystick 3...",IDC_JOY3,144,284,50,14, WS_TABSTOP + PUSHBUTTON "Joystick 4...",IDC_JOY4,208,284,50,14, WS_TABSTOP + + LTEXT "Machine :",IDC_STATIC,15,16,40,10 + LTEXT "Video :",IDC_STATIC,15,36,34,10 + LTEXT "CPU type :",IDC_STATIC,15,56,34,10 + LTEXT "CPU :",IDC_STATIC,15,76,34,10 + LTEXT "Cache :",IDC_STATIC,15,96,40,10 + LTEXT "Vid. speed :",IDC_STATIC,125,96,34,10 + LTEXT "Soundcard :",IDC_STATIC,15,116,40,10 + LTEXT "Network :",IDC_STATIC,125,136,34,10 + COMBOBOX IDC_COMBONET,162,136,57,120,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Configure", IDC_CONFIGURENET, 224, 136, 40, 14, WS_TABSTOP + LTEXT "Memory :",IDC_STATIC,15,136,40,10 + LTEXT "Drive A: :",IDC_STATIC,15,156,40,10 + LTEXT "Drive B: :",IDC_STATIC,125,156,40,10 + COMBOBOX IDC_COMBODRA,62,156,57,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_COMBODRB,162,156,57,120,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP +END + +HdConfDlg DIALOGEX 0, 0, 210, 310+4*16 + STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU + CAPTION "Configure Hard Discs" + FONT 8, "MS Sans Serif" + BEGIN + DEFPUSHBUTTON "OK",IDOK,31+12,290+64,50,14 + PUSHBUTTON "Cancel",IDCANCEL,101+12,290+64,50,14 + + LTEXT "C:",IDC_STATIC,7,6,27,10 + RADIOBUTTON "Hard drive", IDC_CHDD, 7+64, 6, 53, 12 , WS_TABSTOP + RADIOBUTTON "CD-ROM", IDC_CCDROM, 7+128, 6, 53, 12 , WS_TABSTOP + EDITTEXT IDC_EDIT_C_FN, 7, 6+16, 136, 12, WS_DISABLED + PUSHBUTTON "...",IDC_CFILE,7 + 136, 6+16, 16, 14 + PUSHBUTTON "New",IDC_CNEW,7 + 136 + 16, 6+16, 24, 14 + PUSHBUTTON "Eject", IDC_EJECTC, 7 + 136 + 16 + 24, 6+16, 24, 14 + + EDITTEXT IDC_EDIT_C_SPT,36,22+16,16,12, WS_DISABLED + EDITTEXT IDC_EDIT_C_HPC,94,22+16,16,12, WS_DISABLED + EDITTEXT IDC_EDIT_C_CYL,152,22+16,28,12, WS_DISABLED + LTEXT "Sectors:",IDC_STATIC,7,22+16,27,10 + LTEXT "Heads:",IDC_STATIC,63,22+16,29,8 + LTEXT "Cylinders:",IDC_STATIC,120,22+16,32,12 + LTEXT "", IDC_TEXT_C_SIZE, 7, 38+16, 136, 12 + + LTEXT "D:",IDC_STATIC,7,60+16,27,10 + RADIOBUTTON "Hard drive", IDC_DHDD, 7+64, 60+16, 53, 12 , WS_TABSTOP + RADIOBUTTON "CD-ROM", IDC_DCDROM, 7+128, 60+16, 53, 12 , WS_TABSTOP + EDITTEXT IDC_EDIT_D_FN, 7, 60+32, 136, 12, WS_DISABLED + PUSHBUTTON "...",IDC_DFILE,7 + 136, 60+32, 16, 14 + PUSHBUTTON "New",IDC_DNEW,7 + 136 + 16, 60+32, 24, 14 + PUSHBUTTON "Eject", IDC_EJECTD, 7 + 136 + 16 + 24, 60+32, 24, 14 + + EDITTEXT IDC_EDIT_D_SPT,36,76+32,16,12, WS_DISABLED + EDITTEXT IDC_EDIT_D_HPC,94,76+32,16,12, WS_DISABLED + EDITTEXT IDC_EDIT_D_CYL,152,76+32,28,12, WS_DISABLED + LTEXT "Sectors:",IDC_STATIC,7,76+32,27,10 + LTEXT "Heads:",IDC_STATIC,63,76+32,29,8 + LTEXT "Cylinders:",IDC_STATIC,120,76+32,32,12 + LTEXT "", IDC_TEXT_D_SIZE, 7, 92+32, 136, 12 + + LTEXT "E:",IDC_STATIC,7,114+32,27,10 + RADIOBUTTON "Hard drive", IDC_EHDD, 7+64, 114+32, 53, 12 , WS_TABSTOP + RADIOBUTTON "CD-ROM", IDC_ECDROM, 7+128, 114+32, 53, 12 , WS_TABSTOP + EDITTEXT IDC_EDIT_E_FN, 7, 114+48, 136, 12, WS_DISABLED + PUSHBUTTON "...",IDC_EFILE,7 + 136, 114+48, 16, 14 + PUSHBUTTON "New",IDC_ENEW,7 + 136 + 16, 114+48, 24, 14 + PUSHBUTTON "Eject", IDC_EJECTE, 7 + 136 + 16 + 24, 114+48, 24, 14 + + EDITTEXT IDC_EDIT_E_SPT,36,130+48,16,12, WS_DISABLED + EDITTEXT IDC_EDIT_E_HPC,94,130+48,16,12, WS_DISABLED + EDITTEXT IDC_EDIT_E_CYL,152,130+48,28,12, WS_DISABLED + LTEXT "Sectors:",IDC_STATIC,7,130+48,27,10 + LTEXT "Heads:",IDC_STATIC,63,130+48,29,8 + LTEXT "Cylinders:",IDC_STATIC,120,130+48,32,12 + LTEXT "", IDC_TEXT_E_SIZE, 7, 146+48, 136, 12 + + LTEXT "F:",IDC_STATIC,7,168+48,27,10 + RADIOBUTTON "Hard drive", IDC_FHDD, 7+64, 168+48, 53, 12 , WS_TABSTOP + RADIOBUTTON "CD-ROM", IDC_FCDROM, 7+128, 168+48, 53, 12 , WS_TABSTOP + EDITTEXT IDC_EDIT_F_FN, 7, 168+64, 136, 12, WS_DISABLED + PUSHBUTTON "...",IDC_FFILE,7 + 136, 168+64, 16, 14 + PUSHBUTTON "New",IDC_FNEW,7 + 136 + 16, 168+64, 24, 14 + PUSHBUTTON "Eject", IDC_EJECTF, 7 + 136 + 16 + 24, 168+64, 24, 14 + + EDITTEXT IDC_EDIT_F_SPT,36,184+64,16,12, WS_DISABLED + EDITTEXT IDC_EDIT_F_HPC,94,184+64,16,12, WS_DISABLED + EDITTEXT IDC_EDIT_F_CYL,152,184+64,28,12, WS_DISABLED + LTEXT "Sectors:",IDC_STATIC,7,184+64,27,10 + LTEXT "Heads:",IDC_STATIC,63,184+64,29,8 + LTEXT "Cylinders:",IDC_STATIC,120,184+64,32,12 + LTEXT "", IDC_TEXT_F_SIZE, 7, 200+64, 136, 12 + + LTEXT "G:",IDC_STATIC,7,222+64,27,10 + RADIOBUTTON "CD-ROM", IDC_GCDROM, 7+128, 222+64, 53, 12 , WS_TABSTOP + + LTEXT "H:",IDC_STATIC,7,262+64,27,10 + RADIOBUTTON "CD-ROM", IDC_HCDROM, 7+128, 262+64, 53, 12 , WS_TABSTOP + +END + +HdNewDlg DIALOGEX 0, 0, 186, 86 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "New Hard Disc" +FONT 9, "Segoe UI" +BEGIN + DEFPUSHBUTTON "OK",IDOK,31,66,50,14 + PUSHBUTTON "Cancel",IDCANCEL,101,66,50,14 + + EDITTEXT IDC_EDITC, 7, 6, 136, 12 + PUSHBUTTON "...",IDC_CFILE,7 + 136, 6, 16, 14 + + EDITTEXT IDC_EDIT1,36,22,16,12 + EDITTEXT IDC_EDIT2,94,22,16,12 + EDITTEXT IDC_EDIT3,152,22,28,12 + LTEXT "Sectors:",IDC_STATIC,7,22,27,10 + LTEXT "Heads:",IDC_STATIC,63,22,29,8 + LTEXT "Cylinders:",IDC_STATIC,120,22,32,12 + LTEXT "", IDC_TEXT1, 7, 38, 136, 12 +END + +HdSizeDlg DIALOGEX 0, 0, 186, 86 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Hard disc parameters" +FONT 9, "Segoe UI" +BEGIN + DEFPUSHBUTTON "OK",IDOK,31,66,50,14 + PUSHBUTTON "Cancel",IDCANCEL,101,66,50,14 + + LTEXT "Initial settings are based on file size",IDC_STATIC,7,6,170,10 + + EDITTEXT IDC_EDIT1,36,22,16,12 + EDITTEXT IDC_EDIT2,94,22,16,12 + EDITTEXT IDC_EDIT3,152,22,28,12 + LTEXT "Sectors:",IDC_STATIC,7,22,27,10 + LTEXT "Heads:",IDC_STATIC,63,22,29,8 + LTEXT "Cylinders:",IDC_STATIC,120,22,32,12 + LTEXT "", IDC_TEXT1, 7, 38, 136, 12 +END + +StatusDlg DIALOGEX 0,0,186,186+20+180 +STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Status" +FONT 9, "Segoe UI" +BEGIN + LTEXT "1",IDC_STEXT_DEVICE,16,16,180,1000 + LTEXT "1",IDC_STEXT1,16,186,180,1000 +END + +1 24 "PCem.manifest" + +/* Icon by PixelOz - http://pixeloz.deviantart.com/art/Computer-Emulator-Icons-135675096 */ +100 ICON "IBMPCAT-1.ico" diff --git a/src/pc87306.c b/src/pc87306.c new file mode 100644 index 000000000..f7b0023fd --- /dev/null +++ b/src/pc87306.c @@ -0,0 +1,295 @@ +/* + National Semiconductors PC87306 Super I/O Chip + Used by Intel Advanced/EV +*/ + +#include "ibm.h" + +#include "fdc.h" +#include "fdd.h" +#include "io.h" +#include "lpt.h" +#include "mouse_serial.h" +#include "serial.h" +#include "pc87306.h" + +static int pc87306_locked; +static int pc87306_curreg; +static uint8_t pc87306_regs[29]; +static uint8_t pc87306_gpio[2] = {0xFF, 0xFF}; +static uint8_t tries; +static uint16_t lpt_port; + +void pc87306_gpio_remove(); +void pc87306_gpio_init(); + +void pc87306_gpio_write(uint16_t port, uint8_t val, void *priv) +{ + pc87306_gpio[port & 1] = val; +} + +uint8_t uart_int1() +{ + return ((pc87306_regs[0x1C] >> 2) & 1) ? 3 : 4; +} + +uint8_t uart_int2() +{ + return ((pc87306_regs[0x1C] >> 6) & 1) ? 3 : 4; +} + +uint8_t uart1_int() +{ + return (pc87306_regs[0x1C] & 1) ? uart_int1() : 4; +} + +uint8_t uart2_int() +{ + return (pc87306_regs[0x1C] & 1) ? uart_int2() : 3; +} + +void serial1_handler() +{ + int temp; + temp = (pc87306_regs[1] >> 2) & 3; + switch (temp) + { + case 0: serial1_set(0x3f8, uart1_int()); break; + case 1: serial1_set(0x2f8, uart1_int()); break; + case 2: + switch ((pc87306_regs[1] >> 6) & 3) + { + case 0: serial1_set(0x3e8, uart1_int()); break; + case 1: serial1_set(0x338, uart1_int()); break; + case 2: serial1_set(0x2e8, uart1_int()); break; + case 3: serial1_set(0x220, uart1_int()); break; + } + break; + case 3: + switch ((pc87306_regs[1] >> 6) & 3) + { + case 0: serial1_set(0x2e8, uart1_int()); break; + case 1: serial1_set(0x238, uart1_int()); break; + case 2: serial1_set(0x2e0, uart1_int()); break; + case 3: serial1_set(0x228, uart1_int()); break; + } + break; + } +} + +void serial2_handler() +{ + int temp; + temp = (pc87306_regs[1] >> 4) & 3; + switch (temp) + { + case 0: serial2_set(0x3f8, uart2_int()); break; + case 1: serial2_set(0x2f8, uart2_int()); break; + case 2: + switch ((pc87306_regs[1] >> 6) & 3) + { + case 0: serial2_set(0x3e8, uart2_int()); break; + case 1: serial2_set(0x338, uart2_int()); break; + case 2: serial2_set(0x2e8, uart2_int()); break; + case 3: serial2_set(0x220, uart2_int()); break; + } + break; + case 3: + switch ((pc87306_regs[1] >> 6) & 3) + { + case 0: serial2_set(0x2e8, uart2_int()); break; + case 1: serial2_set(0x238, uart2_int()); break; + case 2: serial2_set(0x2e0, uart2_int()); break; + case 3: serial2_set(0x228, uart2_int()); break; + } + break; + } +} + +void pc87306_write(uint16_t port, uint8_t val, void *priv) +{ + uint8_t index = (port & 1) ? 0 : 1; + int temp; + uint8_t valxor; + // pclog("pc87306_write : port=%04x reg %02X = %02X locked=%i\n", port, pc87306_curreg, val, pc87306_locked); + + if (index) + { + pc87306_curreg = val; + tries = 0; + return; + } + else + { + if (tries) + { + if (pc87306_curreg <= 28) valxor = val ^ pc87306_regs[pc87306_curreg]; + if (pc87306_curreg == 0xF) pc87306_gpio_remove(); + if (pc87306_curreg <= 28) pc87306_regs[pc87306_curreg] = val; + tries = 0; + if (pc87306_curreg <= 28) goto process_value; + } + else + { + tries++; + return; + } + } + +process_value: + switch(pc87306_curreg) + { + case 0: + if (valxor & 1) + { + lpt1_remove(); + lpt2_remove(); + } + if ((valxor & 1) && (val & 1)) + { + if (pc87306_regs[0x1B] & 0x10) + { + temp = (pc87306_regs[0x1B] & 0x20) >> 5; + if (temp) + { + lpt1_init(0x378); break; + } + else + { + lpt1_init(0x278); break; + } + } + else + { + temp = pc87306_regs[1] & 3; + switch (temp) + { + case 0: lpt1_init(0x378); break; + case 1: lpt1_init(0x3bc); break; + case 2: lpt1_init(0x278); break; + } + } + } + serial1_remove(); + serial2_remove(); + if (val & 2) + { + serial1_handler(); + // mouse_serial_init(); + } + if (val & 4) serial2_handler(); + + break; + case 1: + lpt1_remove(); + if (pc87306_regs[0] & 1) + { + if (pc87306_regs[0x1B] & 0x10) + { + temp = (pc87306_regs[0x1B] & 0x20) >> 5; + if (temp) + { + lpt_port = 0x378; break; + } + else + { + lpt_port = 0x278; break; + } + } + else + { + temp = val & 3; + switch (temp) + { + case 0: lpt_port = 0x378; break; + case 1: lpt_port = 0x3bc; break; + case 2: lpt_port = 0x278; break; + } + } + lpt1_init(lpt_port); + pc87306_regs[0x19] = lpt_port >> 2; + } + serial1_remove(); + serial2_remove(); + + if (pc87306_regs[0] & 2) + { + serial1_handler(); + // mouse_serial_init(); + } + if (pc87306_regs[0] & 4) serial2_handler(); + break; + case 9: + // pclog("Setting DENSEL polarity to: %i (before: %i)\n", (val & 0x40 ? 1 : 0), fdc_get_densel_polarity()); + fdc_update_densel_polarity(val & 0x40 ? 1 : 0); + break; + case 0xF: + pc87306_gpio_init(); + break; + case 0x1C: + if (valxor & 1) + { + serial1_remove(); + serial2_remove(); + if (pc87306_regs[0] & 2) + { + serial1_handler(); + // mouse_serial_init(); + } + if (pc87306_regs[0] & 4) serial2_handler(); + } + break; + } +} + +uint8_t pc87306_gpio_read(uint16_t port, void *priv) +{ + return pc87306_gpio[port & 1]; +} + +uint8_t pc87306_read(uint16_t port, void *priv) +{ + // pclog("pc87306_read : port=%04x reg %02X locked=%i\n", port, pc87306_curreg, pc87306_locked); + uint8_t index = (port & 1) ? 0 : 1; + + if (index) + return pc87306_curreg; + else + { + if (pc87306_curreg >= 28) + return 0xff; + else + return pc87306_regs[pc87306_curreg]; + } +} + +void pc87306_gpio_remove() +{ + io_removehandler(pc87306_regs[0xF] << 2, 0x0002, pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, NULL); +} + +void pc87306_gpio_init() +{ + io_sethandler(pc87306_regs[0xF] << 2, 0x0002, pc87306_gpio_read, NULL, NULL, pc87306_gpio_write, NULL, NULL, NULL); +} + +void pc87306_init() +{ + pc87306_regs[0] = 0xF; + pc87306_regs[1] = 0x11; + pc87306_regs[5] = 0xD; + pc87306_regs[8] = 0x70; + pc87306_regs[9] = 0xFF; + pc87306_regs[0xF] = 0x1E; + pc87306_regs[0x19] = 0xDE; + pc87306_regs[0x1B] = 0x10; + pc87306_regs[0x1C] = 0; + /* + 0 = 360 rpm @ 500 kbps for 3.5" + 1 = Default, 300 rpm @ 500,300,250,1000 kbps for 3.5" + */ + fdc_update_is_nsc(1); + fdc_update_densel_polarity(1); + fdd_swap = 0; + io_sethandler(0x02e, 0x0002, pc87306_read, NULL, NULL, pc87306_write, NULL, NULL, NULL); +} diff --git a/src/pc87306.h b/src/pc87306.h new file mode 100644 index 000000000..61a926722 --- /dev/null +++ b/src/pc87306.h @@ -0,0 +1 @@ +extern void pc87306_init(); diff --git a/src/pci.c b/src/pci.c new file mode 100644 index 000000000..ebffaa007 --- /dev/null +++ b/src/pci.c @@ -0,0 +1,166 @@ +#include "ibm.h" +#include "io.h" +#include "mem.h" + +#include "pci.h" + +void (*pci_card_write[32])(int func, int addr, uint8_t val, void *priv); +uint8_t (*pci_card_read[32])(int func, int addr, void *priv); +void *pci_priv[32]; +static int pci_index, pci_func, pci_card, pci_bus, pci_enable, pci_key; +static int pci_min_card, pci_max_card; +int pci_burst_time, pci_nonburst_time; + +void pci_cf8_write(uint16_t port, uint32_t val, void *p) +{ + pci_index = val & 0xff; + pci_func = (val >> 8) & 7; + pci_card = (val >> 11) & 31; + pci_bus = (val >> 16) & 0xff; + pci_enable = (val >> 31) & 1; + // pclog("PCI card selected: %i\n", pci_card); +} + +uint32_t pci_cf8_read(uint16_t port, void *p) +{ + return pci_index | (pci_func << 8) | (pci_card << 11) | (pci_bus << 16) | (pci_enable << 31); +} + +void pci_write(uint16_t port, uint8_t val, void *priv) +{ +// pclog("pci_write: port=%04x val=%02x %08x:%08x\n", port, val, cs, pc); + switch (port) + { + case 0xcfc: case 0xcfd: case 0xcfe: case 0xcff: + if (!pci_enable) + return; + +// pclog("PCI write bus %i card %i func %i index %02X val %02X %04X:%04X\n", pci_bus, pci_card, pci_func, pci_index | (port & 3), val, CS, pc); + + if (!pci_bus && pci_card_write[pci_card]) + pci_card_write[pci_card](pci_func, pci_index | (port & 3), val, pci_priv[pci_card]); + + break; + } +} + +uint8_t pci_read(uint16_t port, void *priv) +{ +// pclog("pci_read: port=%04x %08x:%08x\n", port, cs, pc); + switch (port) + { + case 0xcfc: case 0xcfd: case 0xcfe: case 0xcff: + if (!pci_enable) + return 0xff; + +// pclog("PCI read bus %i card %i func %i index %02X\n", pci_bus, pci_card, pci_func, pci_index | (port & 3)); + + if (!pci_bus && pci_card_read[pci_card]) + return pci_card_read[pci_card](pci_func, pci_index | (port & 3), pci_priv[pci_card]); + + return 0xff; + } +} + +void pci_type2_write(uint16_t port, uint8_t val, void *priv); +uint8_t pci_type2_read(uint16_t port, void *priv); + +void pci_type2_write(uint16_t port, uint8_t val, void *priv) +{ +// pclog("pci_type2_write: port=%04x val=%02x %08x:%08x\n", port, val, cs, pc); + if (port == 0xcf8) + { + pci_func = (val >> 1) & 7; + if (!pci_key && (val & 0xf0)) + io_sethandler(0xc000, 0x1000, pci_type2_read, NULL, NULL, pci_type2_write, NULL, NULL, NULL); + else + io_removehandler(0xc000, 0x1000, pci_type2_read, NULL, NULL, pci_type2_write, NULL, NULL, NULL); + pci_key = val & 0xf0; + } + else if (port == 0xcfa) + { + pci_bus = val; + } + else + { + pci_card = (port >> 8) & 0xf; + pci_index = port & 0xff; + +// pclog("PCI write bus %i card %i func %i index %02X val %02X %04X:%04X\n", pci_bus, pci_card, pci_func, pci_index | (port & 3), val, CS, pc); + + if (!pci_bus && pci_card_write[pci_card]) + pci_card_write[pci_card](pci_func, pci_index | (port & 3), val, pci_priv[pci_card]); + } +} + +uint8_t pci_type2_read(uint16_t port, void *priv) +{ +// pclog("pci_type2_read: port=%04x %08x:%08x\n", port, cs, pc); + if (port == 0xcf8) + { + return pci_key | (pci_func << 1); + } + else if (port == 0xcfa) + { + return pci_bus; + } + else + { + pci_card = (port >> 8) & 0xf; + pci_index = port & 0xff; + +// pclog("PCI read bus %i card %i func %i index %02X %04X:%04X\n", pci_bus, pci_card, pci_func, pci_index | (port & 3), CS, pc); + + if (!pci_bus && pci_card_write[pci_card]) + return pci_card_read[pci_card](pci_func, pci_index | (port & 3), pci_priv[pci_card]); + } + return 0xff; +} + +void pci_init(int type, int min_card, int max_card) +{ + int c; + + PCI = 1; + + if (type == PCI_CONFIG_TYPE_1) + { + io_sethandler(0x0cf8, 0x0001, NULL, NULL, pci_cf8_read, NULL, NULL, pci_cf8_write, NULL); + io_sethandler(0x0cfc, 0x0004, pci_read, NULL, NULL, pci_write, NULL, NULL, NULL); + } + else + { + io_sethandler(0x0cf8, 0x0001, pci_type2_read, NULL, NULL, pci_type2_write, NULL, NULL, NULL); + io_sethandler(0x0cfa, 0x0001, pci_type2_read, NULL, NULL, pci_type2_write, NULL, NULL, NULL); + } + + for (c = 0; c < 32; c++) + pci_card_read[c] = pci_card_write[c] = pci_priv[c] = NULL; + + pci_min_card = min_card; + pci_max_card = max_card; +} + +void pci_add_specific(int card, uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv) +{ + pci_card_read[card] = read; + pci_card_write[card] = write; + pci_priv[card] = priv; +} + +void pci_add(uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv) +{ + int c; + + for (c = pci_min_card; c <= pci_max_card; c++) + { + if (!pci_card_read[c] && !pci_card_write[c]) + { + pci_card_read[c] = read; + pci_card_write[c] = write; + pci_priv[c] = priv; + // pclog("PCI device added to card: %i\n", c); + return; + } + } +} diff --git a/src/pci.h b/src/pci.h new file mode 100644 index 000000000..8fcbd1893 --- /dev/null +++ b/src/pci.h @@ -0,0 +1,13 @@ +void pci_init(int type, int min_card, int max_card); +void pci_add_specific(int card, uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv); +void pci_add(uint8_t (*read)(int func, int addr, void *priv), void (*write)(int func, int addr, uint8_t val, void *priv), void *priv); + +#define PCI_REG_COMMAND 0x04 + +#define PCI_COMMAND_IO 0x01 +#define PCI_COMMAND_MEM 0x02 + +#define PCI_CONFIG_TYPE_1 1 +#define PCI_CONFIG_TYPE_2 2 + +extern int pci_burst_time, pci_nonburst_time; diff --git a/src/pic.c b/src/pic.c new file mode 100644 index 000000000..e3549f71c --- /dev/null +++ b/src/pic.c @@ -0,0 +1,423 @@ +#include "ibm.h" +#include "io.h" +#include "pic.h" + +int output; +int intclear; +int keywaiting=0; +int pic_intpending; + +void pic_updatepending() +{ + if ((pic2.pend&~pic2.mask)&~pic2.mask2) + pic.pend |= (1 << 2); + else + pic.pend &= ~(1 << 2); + pic_intpending = (pic.pend & ~pic.mask) & ~pic.mask2; + if (!((pic.mask | pic.mask2) & (1 << 2))) + pic_intpending |= ((pic2.pend&~pic2.mask)&~pic2.mask2); +/* pclog("pic_intpending = %i %02X %02X %02X %02X\n", pic_intpending, pic.ins, pic.pend, pic.mask, pic.mask2); + pclog(" %02X %02X %02X %02X %i %i\n", pic2.ins, pic2.pend, pic2.mask, pic2.mask2, ((pic.mask | pic.mask2) & (1 << 2)), ((pic2.pend&~pic2.mask)&~pic2.mask2));*/ +} + + +void pic_reset() +{ + pic.icw=0; + pic.mask=0xFF; + pic.mask2=0; + pic.pend=pic.ins=0; + pic.vector=8; + pic.read=1; + pic2.icw=0; + pic2.mask=0xFF; + pic.mask2=0; + pic2.pend=pic2.ins=0; + pic_intpending = 0; +} + +void pic_update_mask(uint8_t *mask, uint8_t ins) +{ + int c; + *mask = 0; + for (c = 0; c < 8; c++) + { + if (ins & (1 << c)) + { + *mask = 0xff << c; + return; + } + } +} + +static void pic_autoeoi() +{ + int c; + + for (c=0;c<8;c++) + { + if (pic.ins&(1<0xFF) + { + pic2.pend|=(num>>8); + if ((pic2.pend&~pic2.mask)&~pic2.mask2) + pic.pend |= (1 << 2); + } + else + { + pic.pend|=num; + } +// pclog("picint : PEND now %02X %02X\n", pic.pend, pic2.pend); + pic_updatepending(); +} + +void picintlevel(uint16_t num) +{ + int c = 0; + while (!(num & (1 << c))) c++; + if (AT && c == 2) + { + c = 9; + num = 1 << 9; + } +// pclog("INTLEVEL %04X %i\n", num, c); + if (!pic_current[c]) + { + pic_current[c]=1; + if (num>0xFF) + { + pic2.pend|=(num>>8); + } + else + { + pic.pend|=num; + } + } + pic_updatepending(); +} +void picintc(uint16_t num) +{ + int c = 0; + if (!num) + return; + while (!(num & (1 << c))) c++; + if (AT && c == 2) + { + c = 9; + num = 1 << 9; + } +// pclog("INTC %04X %i\n", num, c); + pic_current[c]=0; + + if (num > 0xff) + { + pic2.pend &= ~(num >> 8); + if (!((pic2.pend&~pic2.mask)&~pic2.mask2)) + pic.pend &= ~(1 << 2); + } + else + { + pic.pend&=~num; + } + pic_updatepending(); +} + +uint8_t picinterrupt() +{ + uint8_t temp=pic.pend&~pic.mask; + int c; + for (c = 0; c < 2; c++) + { + if (temp & (1 << c)) + { + pic.pend &= ~(1 << c); + pic.ins |= (1 << c); + pic_update_mask(&pic.mask2, pic.ins); + pic_updatepending(); + + if (pic.icw4 & 0x02) + pic_autoeoi(); + + return c+pic.vector; + } + } + if (temp & (1 << 2)) + { + uint8_t temp2 = pic2.pend & ~pic2.mask; + for (c = 0; c < 8; c++) + { + if (temp2 & (1 << c)) + { + pic2.pend &= ~(1 << c); + pic2.ins |= (1 << c); + pic_update_mask(&pic2.mask2, pic2.ins); + + pic.pend &= ~(1 << c); + pic.ins |= (1 << 2); /*Cascade IRQ*/ + pic_update_mask(&pic.mask2, pic.ins); + + pic_updatepending(); + + if (pic2.icw4 & 0x02) + pic2_autoeoi(); + + return c+pic2.vector; + } + } + } + for (c = 3; c < 8; c++) + { + if (temp & (1 << c)) + { + pic.pend &= ~(1 << c); + pic.ins |= (1 << c); + pic_update_mask(&pic.mask2, pic.ins); + pic_updatepending(); + + if (pic.icw4 & 0x02) + pic_autoeoi(); + + return c+pic.vector; + } + } + return 0xFF; +} + +void dumppic() +{ + pclog("PIC1 : MASK %02X PEND %02X INS %02X VECTOR %02X\n",pic.mask,pic.pend,pic.ins,pic.vector); + pclog("PIC2 : MASK %02X PEND %02X INS %02X VECTOR %02X\n",pic2.mask,pic2.pend,pic2.ins,pic2.vector); +} + diff --git a/src/pic.h b/src/pic.h new file mode 100644 index 000000000..419315c5f --- /dev/null +++ b/src/pic.h @@ -0,0 +1,9 @@ +void pic_init(); +void pic2_init(); +void pic_reset(); + +void picint(uint16_t num); +void picintlevel(uint16_t num); +void picintc(uint16_t num); +uint8_t picinterrupt(); +void picclear(int num); diff --git a/src/piix.c b/src/piix.c new file mode 100644 index 000000000..4f32d7202 --- /dev/null +++ b/src/piix.c @@ -0,0 +1,570 @@ +/*PRD format : + + word 0 - base address + word 1 - bits 1 - 15 = byte count, bit 31 = end of transfer +*/ +#include + +#include "ibm.h" +#include "ide.h" +#include "io.h" +#include "mem.h" +#include "pci.h" + +#include "piix.h" + +uint8_t piix_33 = 0; + +uint8_t piix_bus_master_read(uint16_t port, void *priv); +void piix_bus_master_write(uint16_t port, uint8_t val, void *priv); + +static uint8_t piix_type = 1; +static uint8_t card_piix[256], card_piix_ide[256]; + +void piix_write(int func, int addr, uint8_t val, void *priv) +{ +// pclog("piix_write: func=%d addr=%02x val=%02x %04x:%08x\n", func, addr, val, CS, pc); + if (func > 1) + return; + + if (func == 1) /*IDE*/ + { + switch (addr) + { + case 0x04: + if (val & 0x10) resetide(); /* Only the ASUS boards attempt to modify this register - reset IDE when that happens. Fixes soft reset on the ASUS boards. */ + card_piix_ide[0x04] = (card_piix_ide[0x04] & ~5) | (val & 5); + break; + case 0x07: + card_piix_ide[0x07] = (card_piix_ide[0x07] & ~0x38) | (val & 0x38); + break; + case 0x0d: + card_piix_ide[0x0d] = val; + break; + + case 0x20: + card_piix_ide[0x20] = (val & ~0x0f) | 1; + break; + case 0x21: + card_piix_ide[0x21] = val; + break; + +#if 0 + case 0x33: + /* Note by OBattler: This is a hack, but it's needed to reset the cylinders of the IDE devices. */ + if (romset != ROM_P55T2P4) break; + if (val != piix_33) + { + resetide(); + } + piix_33 = val; + break; +#endif + + case 0x40: + card_piix_ide[0x40] = val; + break; + case 0x41: + if ((val ^ card_piix_ide[0x41]) & 0x80) + { + ide_pri_disable(); + if (val & 0x80) + ide_pri_enable(); + } + card_piix_ide[0x41] = val; + break; + case 0x42: + card_piix_ide[0x42] = val; + break; + case 0x43: + if ((val ^ card_piix_ide[0x43]) & 0x80) + { + ide_sec_disable(); + if (val & 0x80) + ide_sec_enable(); + } + card_piix_ide[0x43] = val; + break; + case 0x44: + if (piix_type >= 3) card_piix_ide[0x44] = val; + break; + } + if (addr == 4 || (addr & ~3) == 0x20) /*Bus master base address*/ + { + uint16_t base = (card_piix_ide[0x20] & 0xf0) | (card_piix_ide[0x21] << 8); + io_removehandler(0, 0x10000, piix_bus_master_read, NULL, NULL, piix_bus_master_write, NULL, NULL, NULL); + if (card_piix_ide[0x04] & 1) + io_sethandler(base, 0x10, piix_bus_master_read, NULL, NULL, piix_bus_master_write, NULL, NULL, NULL); + } +// pclog("PIIX write %02X %02X\n", addr, val); + } + else + { + switch (addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0e: + return; + } + if (addr == 0x6A) + { + if (piix_type == 1) + card_piix[addr] = (val & 0xFC) | (card_piix[addr] | 3); + else if (piix_type == 3) + card_piix[addr] = (val & 0xFD) | (card_piix[addr] | 2); + } + else + card_piix[addr] = val; + } +} + +uint8_t piix_read(int func, int addr, void *priv) +{ +// pclog("piix_read: func=%d addr=%02x %04x:%08x\n", func, addr, CS, pc); + if (func > 1) + return 0xff; + + if (func == 1) /*IDE*/ + { +// pclog("PIIX IDE read %02X %02X\n", addr, card_piix_ide[addr]); + + if (addr == 4) + { + return (card_piix_ide[addr] & 4) | 3; + } + else if (addr == 5) + { + return 0; + } + else if (addr == 6) + { + return 0x80; + } + else if (addr == 7) + { + return card_piix_ide[addr] & 0x3E; + } + else if (addr == 0xD) + { + return card_piix_ide[addr] & 0xF0; + } + else if (addr == 0x20) + { + return card_piix_ide[addr] & 0xF1; + } + else if (addr == 0x22) + { + return 0; + } + else if (addr == 0x23) + { + return 0; + } + else if (addr == 0x41) + { + if (piix_type == 1) + return card_piix_ide[addr] & 0xB3; + else if (piix_type == 3) + return card_piix_ide[addr] & 0xF3; + } + else if (addr == 0x43) + { + if (piix_type == 1) + return card_piix_ide[addr] & 0xB3; + else if (piix_type == 3) + return card_piix_ide[addr] & 0xF3; + } + else + { + return card_piix_ide[addr]; + } + } + else + { + if ((addr & 0xFC) == 0x60) + { + return card_piix[addr] & 0x8F; + } + if (addr == 4) + { + return (card_piix[addr] & 0x80) | 7; + } + else if (addr == 5) + { + if (piix_type == 1) + return 0; + else if (piix_type == 3) + return card_piix[addr] & 1; + } + else if (addr == 6) + { + return card_piix[addr] & 0x80; + } + else if (addr == 7) + { + if (piix_type == 1) + return card_piix[addr] & 0x3E; + else if (piix_type == 3) + return card_piix[addr]; + } + else if (addr == 0x69) + { + return card_piix[addr] & 0xFE; + } + else if (addr == 0x6A) + { + if (piix_type == 1) + return card_piix[addr] & 0x07; + else if (piix_type == 3) + return card_piix[addr] & 0xD1; + } + else if (addr == 0x6B) + { + if (piix_type == 1) + return 0; + else if (piix_type == 3) + return card_piix[addr] & 0x80; + } + else if (addr == 0x70) + { + if (piix_type == 1) + return card_piix[addr] & 0xCF; + else if (piix_type == 3) + return card_piix[addr] & 0xEF; + } + else if (addr == 0x71) + { + if (piix_type == 1) + return card_piix[addr] & 0xCF; + else if (piix_type == 3) + return 0; + } + else if (addr == 0x76) + { + if (piix_type == 1) + return card_piix[addr] & 0x8F; + else if (piix_type == 3) + return card_piix[addr] & 0x87; + } + else if (addr == 0x77) + { + if (piix_type == 1) + return card_piix[addr] & 0x8F; + else if (piix_type == 3) + return card_piix[addr] & 0x87; + } + else if (addr == 0x80) + { + if (piix_type == 1) + return 0; + else if (piix_type == 3) + return card_piix[addr] & 0x7F; + } + else if (addr == 0x82) + { + if (piix_type == 1) + return 0; + else if (piix_type == 3) + return card_piix[addr] & 0x0F; + } + else if (addr == 0xA0) + { + return card_piix[addr] & 0x1F; + } + else if (addr == 0xA3) + { + if (piix_type == 1) + return 0; + else if (piix_type == 3) + return card_piix[addr] & 1; + } + else if (addr == 0xA7) + { + if (piix_type == 1) + return card_piix[addr] & 0xEF; + else if (piix_type == 3) + return card_piix[addr]; + } + else if (addr == 0xAB) + { + if (piix_type == 1) + return card_piix[addr] & 0xFE; + else if (piix_type == 3) + return card_piix[addr]; + } + else + return card_piix[addr]; + } +} + +struct +{ + uint8_t command; + uint8_t status; + uint32_t ptr, ptr_cur; + int count; + uint32_t addr; + int eot; +} piix_busmaster[2]; + +static void piix_bus_master_next_addr(int channel) +{ + piix_busmaster[channel].addr = ((*(uint32_t *)(&ram[piix_busmaster[channel].ptr_cur])) & ~1) % (mem_size * 1024); + piix_busmaster[channel].count = (*(uint32_t *)(&ram[piix_busmaster[channel].ptr_cur + 4])) & 0xfffe; + piix_busmaster[channel].eot = (*(uint32_t *)(&ram[piix_busmaster[channel].ptr_cur + 4])) >> 31; + piix_busmaster[channel].ptr_cur += 8; +// pclog("New DMA settings on channel %i - Addr %08X Count %04X EOT %i\n", channel, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot); +} + +void piix_bus_master_write(uint16_t port, uint8_t val, void *priv) +{ + int channel = (port & 8) ? 1 : 0; +// pclog("PIIX Bus Master write %04X %02X %04x:%08x\n", port, val, CS, pc); + switch (port & 7) + { + case 0: + if ((val & 1) && !(piix_busmaster[channel].command & 1)) /*Start*/ + { + piix_busmaster[channel].ptr_cur = piix_busmaster[channel].ptr; + piix_bus_master_next_addr(channel); + piix_busmaster[channel].status |= 1; + } + if (!(val & 1) && (piix_busmaster[channel].command & 1)) /*Stop*/ + piix_busmaster[channel].status &= ~1; + + piix_busmaster[channel].command = val; + break; + case 2: + piix_busmaster[channel].status = (val & 0x60) | ((piix_busmaster[channel].status & ~val) & 6) | (piix_busmaster[channel].status & 1); + break; + case 4: + piix_busmaster[channel].ptr = (piix_busmaster[channel].ptr & 0xffffff00) | val; + piix_busmaster[channel].ptr %= (mem_size * 1024); + break; + case 5: + piix_busmaster[channel].ptr = (piix_busmaster[channel].ptr & 0xffff00ff) | (val << 8); + piix_busmaster[channel].ptr %= (mem_size * 1024); + break; + case 6: + piix_busmaster[channel].ptr = (piix_busmaster[channel].ptr & 0xff00ffff) | (val << 16); + piix_busmaster[channel].ptr %= (mem_size * 1024); + break; + case 7: + piix_busmaster[channel].ptr = (piix_busmaster[channel].ptr & 0x00ffffff) | (val << 24); + piix_busmaster[channel].ptr %= (mem_size * 1024); + break; + + } +} + +uint8_t piix_bus_master_read(uint16_t port, void *priv) +{ + int channel = (port & 8) ? 1 : 0; +// pclog("PIIX Bus Master read %04X %04x:%08x\n", port, CS, pc); + switch (port & 7) + { + case 0: + return piix_busmaster[channel].command; + case 2: + return piix_busmaster[channel].status; + case 4: + return piix_busmaster[channel].ptr; + case 5: + return piix_busmaster[channel].ptr >> 8; + case 6: + return piix_busmaster[channel].ptr >> 16; + case 7: + return piix_busmaster[channel].ptr >> 24; + } + return 0xff; +} + +int piix_bus_master_sector_read(int channel, uint8_t *data) +{ + int transferred = 0; + + if (!(piix_busmaster[channel].status & 1)) + return 1; /*DMA disabled*/ + + while (transferred < 512) + { + if (piix_busmaster[channel].count < (512 - transferred) && piix_busmaster[channel].eot) + fatal("DMA on channel %i - Read count less than 512! Addr %08X Count %04X EOT %i\n", channel, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot); + + mem_invalidate_range(piix_busmaster[channel].addr, piix_busmaster[channel].addr+511); + + if (piix_busmaster[channel].count < (512 - transferred)) + { +// pclog("Transferring smaller - %i bytes\n", piix_busmaster[channel].count); + memcpy(&ram[piix_busmaster[channel].addr], data + transferred, piix_busmaster[channel].count); + transferred += piix_busmaster[channel].count; + piix_busmaster[channel].addr += piix_busmaster[channel].count; + piix_busmaster[channel].addr %= (mem_size * 1024); + piix_busmaster[channel].count = 0; + } + else + { +// pclog("Transferring larger - %i bytes\n", 512 - transferred); + memcpy(&ram[piix_busmaster[channel].addr], data + transferred, 512 - transferred); + piix_busmaster[channel].addr += (512 - transferred); + piix_busmaster[channel].count -= (512 - transferred); + transferred += (512 - transferred); + } + +// pclog("DMA on channel %i - Addr %08X Count %04X EOT %i\n", channel, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot); + + if (!piix_busmaster[channel].count) + { +// pclog("DMA on channel %i - block over\n", channel); + if (piix_busmaster[channel].eot) /*End of transfer?*/ + { +// pclog("DMA on channel %i - transfer over\n", channel); + piix_busmaster[channel].status &= ~1; + } + else + piix_bus_master_next_addr(channel); + } + } + return 0; +} +int piix_bus_master_sector_write(int channel, uint8_t *data) +{ + int transferred = 0; + + if (!(piix_busmaster[channel].status & 1)) + return 1; /*DMA disabled*/ + + while (transferred < 512) + { + if (piix_busmaster[channel].count < (512 - transferred) && piix_busmaster[channel].eot) + fatal("DMA on channel %i - Write count less than 512! Addr %08X Count %04X EOT %i\n", channel, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot); + + if (piix_busmaster[channel].count < (512 - transferred)) + { +// pclog("Transferring smaller - %i bytes\n", piix_busmaster[channel].count); + memcpy(data + transferred, &ram[piix_busmaster[channel].addr], piix_busmaster[channel].count); + transferred += piix_busmaster[channel].count; + piix_busmaster[channel].addr += piix_busmaster[channel].count; + piix_busmaster[channel].addr %= (mem_size * 1024); + piix_busmaster[channel].count = 0; + } + else + { +// pclog("Transferring larger - %i bytes\n", 512 - transferred); + memcpy(data + transferred, &ram[piix_busmaster[channel].addr], 512 - transferred); + piix_busmaster[channel].addr += (512 - transferred); + piix_busmaster[channel].count -= (512 - transferred); + transferred += (512 - transferred); + } + +// pclog("DMA on channel %i - Addr %08X Count %04X EOT %i\n", channel, piix_busmaster[channel].addr, piix_busmaster[channel].count, piix_busmaster[channel].eot); + + if (!piix_busmaster[channel].count) + { +// pclog("DMA on channel %i - block over\n", channel); + if (piix_busmaster[channel].eot) /*End of transfer?*/ + { +// pclog("DMA on channel %i - transfer over\n", channel); + piix_busmaster[channel].status &= ~1; + } + else + piix_bus_master_next_addr(channel); + } + } + return 0; +} + +void piix_bus_master_set_irq(int channel) +{ + piix_busmaster[channel].status |= 4; +} + +void piix_init(int card) +{ + pci_add_specific(card, piix_read, piix_write, NULL); + + memset(card_piix, 0, 256); + card_piix[0x00] = 0x86; card_piix[0x01] = 0x80; /*Intel*/ + card_piix[0x02] = 0x2e; card_piix[0x03] = 0x12; /*82371FB (PIIX)*/ + card_piix[0x04] = 0x07; card_piix[0x05] = 0x00; + card_piix[0x06] = 0x00; card_piix[0x07] = 0x02; + card_piix[0x08] = 0x00; /*A0 stepping*/ + card_piix[0x09] = 0x00; card_piix[0x0a] = 0x01; card_piix[0x0b] = 0x06; + card_piix[0x0e] = 0x80; /*Multi-function device*/ + card_piix[0x4c] = 0x4d; + card_piix[0x4e] = 0x03; + card_piix[0x60] = card_piix[0x61] = card_piix[0x62] = card_piix[0x63] = 0x80; + card_piix[0x69] = 0x02; + card_piix[0x70] = card_piix[0x71] = 0x80; + card_piix[0x76] = card_piix[0x77] = 0x0c; + card_piix[0x78] = 0x02; card_piix[0x79] = 0x00; + card_piix[0xa0] = 0x08; + card_piix[0xa2] = card_piix[0xa3] = 0x00; + card_piix[0xa4] = card_piix[0xa5] = card_piix[0xa6] = card_piix[0xa7] = 0x00; + card_piix[0xa8] = 0x0f; + card_piix[0xaa] = card_piix[0xab] = 0x00; + card_piix[0xac] = 0x00; + card_piix[0xae] = 0x00; + + card_piix_ide[0x00] = 0x86; card_piix_ide[0x01] = 0x80; /*Intel*/ + card_piix_ide[0x02] = 0x30; card_piix_ide[0x03] = 0x12; /*82371FB (PIIX)*/ + card_piix_ide[0x04] = 0x00; card_piix_ide[0x05] = 0x00; + card_piix_ide[0x06] = 0x80; card_piix_ide[0x07] = 0x02; + card_piix_ide[0x08] = 0x00; + card_piix_ide[0x09] = 0x80; card_piix_ide[0x0a] = 0x01; card_piix_ide[0x0b] = 0x01; + card_piix_ide[0x0d] = 0x00; + card_piix_ide[0x0e] = 0x00; + card_piix_ide[0x20] = 0x01; card_piix_ide[0x21] = card_piix_ide[0x22] = card_piix_ide[0x23] = 0x00; /*Bus master interface base address*/ + card_piix_ide[0x40] = card_piix_ide[0x41] = 0x00; + card_piix_ide[0x42] = card_piix_ide[0x43] = 0x00; + + piix_type = 1; + + ide_set_bus_master(piix_bus_master_sector_read, piix_bus_master_sector_write, piix_bus_master_set_irq); +} + +void piix3_init(int card) +{ + pci_add_specific(card, piix_read, piix_write, NULL); + + memset(card_piix, 0, 256); + card_piix[0x00] = 0x86; card_piix[0x01] = 0x80; /*Intel*/ + card_piix[0x02] = 0x00; card_piix[0x03] = 0x70; /*82371SB (PIIX3)*/ + card_piix[0x04] = 0x07; card_piix[0x05] = 0x00; + card_piix[0x06] = 0x00; card_piix[0x07] = 0x02; + card_piix[0x08] = 0x00; /*A0 stepping*/ + card_piix[0x09] = 0x00; card_piix[0x0a] = 0x01; card_piix[0x0b] = 0x06; + card_piix[0x0e] = 0x80; /*Multi-function device*/ + card_piix[0x4c] = 0x4d; + card_piix[0x4e] = card_piix[0x4f] = 0x03; + card_piix[0x60] = card_piix[0x61] = card_piix[0x62] = card_piix[0x63] = 0x80; + card_piix[0x69] = 0x02; + card_piix[0x70] = 0x80; + card_piix[0x76] = card_piix[0x77] = 0x0c; + card_piix[0x78] = 0x02; card_piix[0x79] = 0x00; + card_piix[0xa0] = 0x08; + card_piix[0xa2] = card_piix[0xa3] = 0x00; + card_piix[0xa4] = card_piix[0xa5] = card_piix[0xa6] = card_piix[0xa7] = 0x00; + card_piix[0xa8] = 0x0f; + card_piix[0xaa] = card_piix[0xab] = 0x00; + card_piix[0xac] = 0x00; + card_piix[0xae] = 0x00; + + card_piix_ide[0x00] = 0x86; card_piix_ide[0x01] = 0x80; /*Intel*/ + card_piix_ide[0x02] = 0x10; card_piix_ide[0x03] = 0x70; /*82371SB (PIIX3)*/ + card_piix_ide[0x04] = 0x00; card_piix_ide[0x05] = 0x00; + card_piix_ide[0x06] = 0x80; card_piix_ide[0x07] = 0x02; + card_piix_ide[0x08] = 0x00; + card_piix_ide[0x09] = 0x80; card_piix_ide[0x0a] = 0x01; card_piix_ide[0x0b] = 0x01; + card_piix_ide[0x0d] = 0x00; + card_piix_ide[0x0e] = 0x00; + card_piix_ide[0x20] = 0x01; card_piix_ide[0x21] = card_piix_ide[0x22] = card_piix_ide[0x23] = 0x00; /*Bus master interface base address*/ + card_piix_ide[0x40] = card_piix_ide[0x41] = 0x00; + card_piix_ide[0x42] = card_piix_ide[0x43] = 0x00; + card_piix_ide[0x44] = 0x00; + + piix_type = 3; + + ide_set_bus_master(piix_bus_master_sector_read, piix_bus_master_sector_write, piix_bus_master_set_irq); +} diff --git a/src/piix.h b/src/piix.h new file mode 100644 index 000000000..9bac729e6 --- /dev/null +++ b/src/piix.h @@ -0,0 +1,2 @@ +void piix_init(int card); +void piix3_init(int card); diff --git a/src/pit.c b/src/pit.c new file mode 100644 index 000000000..20baa7ee2 --- /dev/null +++ b/src/pit.c @@ -0,0 +1,627 @@ +/*IBM AT - + Write B0 + Write aa55 + Expects aa55 back*/ + +#include +#include "ibm.h" + +#include "cpu.h" +#include "dma.h" +#include "io.h" +#include "pic.h" +#include "pit.h" +#include "timer.h" +#include "video.h" +#include "model.h" +/*B0 to 40, two writes to 43, then two reads - value does not change!*/ +/*B4 to 40, two writes to 43, then two reads - value _does_ change!*/ +//Tyrian writes 4300 or 17512 +int displine; + +double PITCONST; +float cpuclock; +float isa_timing, bus_timing; + +int firsttime=1; +void setpitclock(float clock) +{ +// printf("PIT clock %f\n",clock); + cpuclock=clock; + PITCONST=clock/1193182.0; + CGACONST=(clock/(19687503.0/11.0)); + MDACONST=(clock/2032125.0); + VGACONST1=(clock/25175000.0); + VGACONST2=(clock/28322000.0); + isa_timing = clock/8000000.0; + bus_timing = clock/(double)cpu_busspeed; + video_updatetiming(); +// pclog("PITCONST=%f CGACONST=%f\n", PITCONST, CGACONST); +// pclog("CPUMULTI=%g\n", ((14318184.0*(double)(1 << TIMER_SHIFT)) / (double)models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed)); + + xt_cpu_multi = (int)((14318184.0*(double)(1 << TIMER_SHIFT)) / (double)models[model].cpu[cpu_manufacturer].cpus[cpu].rspeed); +// pclog("egacycles %i egacycles2 %i temp %f clock %f\n",egacycles,egacycles2,temp,clock); +/* if (video_recalctimings) + video_recalctimings();*/ + RTCCONST=clock/32768.0; + TIMER_USEC = (int)((clock / 1000000.0f) * (float)(1 << TIMER_SHIFT)); + device_speed_changed(); +} + +//#define PITCONST (8000000.0/1193000.0) +//#define PITCONST (cpuclock/1193000.0) +void pit_reset() +{ + memset(&pit,0,sizeof(PIT)); + pit.l[0]=0xFFFF; pit.c[0]=0xFFFF*PITCONST; + pit.l[1]=0xFFFF; pit.c[1]=0xFFFF*PITCONST; + pit.l[2]=0xFFFF; pit.c[2]=0xFFFF*PITCONST; + pit.m[0]=pit.m[1]=pit.m[2]=0; + pit.ctrls[0]=pit.ctrls[1]=pit.ctrls[2]=0; + pit.thit[0]=1; + spkstat=0; + pit.gate[0] = pit.gate[1] = 1; + pit.gate[2] = 0; + pit.using_timer[0] = pit.using_timer[1] = pit.using_timer[2] = 1; +} + +void clearpit() +{ + pit.c[0]=(pit.l[0]<<2); +} + +float pit_timer0_freq() +{ + if (pit.l[0]) + return 1193182.0f/(float)pit.l[0]; + else + return 1193182.0f/(float)0x10000; +} + +static void (*pit_set_out_funcs[3])(int new_out, int old_out); + +static void pit_set_out(int t, int out) +{ + pit_set_out_funcs[t](out, pit.out[t]); + pit.out[t] = out; +} + +static void pit_load(int t) +{ + int l = pit.l[t] ? pit.l[t] : 0x10000; + timer_process(); + pit.newcount[t] = 0; + pit.disabled[t] = 0; +// pclog("pit_load: t=%i l=%x\n", t, l); + switch (pit.m[t]) + { + case 0: /*Interrupt on terminal count*/ + pit.count[t] = l; + pit.c[t] = (int)((l << TIMER_SHIFT) * PITCONST); + pit_set_out(t, 0); + pit.thit[t] = 0; + pit.enabled[t] = pit.gate[t]; + break; + case 1: /*Hardware retriggerable one-shot*/ + pit.enabled[t] = 1; + break; + case 2: /*Rate generator*/ + if (pit.initial[t]) + { + pit.count[t] = l - 1; + pit.c[t] = (int)(((l - 1) << TIMER_SHIFT) * PITCONST); + pit_set_out(t, 1); + pit.thit[t] = 0; + } + pit.enabled[t] = pit.gate[t]; + break; + case 3: /*Square wave mode*/ + if (pit.initial[t]) + { + pit.count[t] = l; + pit.c[t] = (int)((((l + 1) >> 1) << TIMER_SHIFT) * PITCONST); + pit_set_out(t, 1); + pit.thit[t] = 0; + } + pit.enabled[t] = pit.gate[t]; +// pclog("pit_load: square wave mode c=%x\n", pit.c[t]); + break; + case 4: /*Software triggered stobe*/ + if (!pit.thit[t] && !pit.initial[t]) + pit.newcount[t] = 1; + else + { + pit.count[t] = l; + pit.c[t] = (int)((l << TIMER_SHIFT) * PITCONST); + pit_set_out(t, 0); + pit.thit[t] = 0; + } + pit.enabled[t] = pit.gate[t]; + break; + case 5: /*Hardware triggered stobe*/ + pit.enabled[t] = 1; + break; + } + pit.initial[t] = 0; + pit.running[t] = pit.enabled[t] && pit.using_timer[t] && !pit.disabled[t]; + timer_update_outstanding(); +// pclog("pit_load: t=%i running=%i thit=%i enabled=%i m=%i l=%x c=%g gate=%i\n", t, pit.running[t], pit.thit[t], pit.enabled[t], pit.m[t], pit.l[t], pit.c[t], pit.gate[t]); +} + +void pit_set_gate(int t, int gate) +{ + int l = pit.l[t] ? pit.l[t] : 0x10000; + + if (pit.disabled[t]) + { + pit.gate[t] = gate; + return; + } + + timer_process(); + switch (pit.m[t]) + { + case 0: /*Interrupt on terminal count*/ + case 4: /*Software triggered stobe*/ + pit.enabled[t] = gate; + break; + case 1: /*Hardware retriggerable one-shot*/ + case 5: /*Hardware triggered stobe*/ + if (gate && !pit.gate[t]) + { + pit.count[t] = l; + pit.c[t] = (int)((l << TIMER_SHIFT) * PITCONST); + pit_set_out(t, 0); + pit.thit[t] = 0; + pit.enabled[t] = 1; + } + break; + case 2: /*Rate generator*/ + if (gate && !pit.gate[t]) + { + pit.count[t] = l - 1; + pit.c[t] = (int)(((l - 1) << TIMER_SHIFT) * PITCONST); + pit_set_out(t, 1); + pit.thit[t] = 0; + } + pit.enabled[t] = gate; + break; + case 3: /*Square wave mode*/ + if (gate && !pit.gate[t]) + { + pit.count[t] = l; + pit.c[t] = (int)((((l + 1) >> 1) << TIMER_SHIFT) * PITCONST); + pit_set_out(t, 1); + pit.thit[t] = 0; + } + pit.enabled[t] = gate; + break; + } + pit.gate[t] = gate; + pit.running[t] = pit.enabled[t] && pit.using_timer[t] && !pit.disabled[t]; + timer_update_outstanding(); +// pclog("pit_set_gate: t=%i gate=%i\n", t, gate); +} + +static void pit_over(int t) +{ + int l = pit.l[t] ? pit.l[t] : 0x10000; + if (pit.disabled[t]) + { + pit.count[t] += 0xffff; + pit.c[t] += (int)((0xffff << TIMER_SHIFT) * PITCONST); + return; + } + +// if (!t) pclog("pit_over: t=%i l=%x c=%x %i hit=%i\n", t, pit.l[t], pit.c[t], pit.c[t] >> TIMER_SHIFT, pit.thit[t]); + switch (pit.m[t]) + { + case 0: /*Interrupt on terminal count*/ + case 1: /*Hardware retriggerable one-shot*/ + if (!pit.thit[t]) + pit_set_out(t, 1); + pit.thit[t] = 1; + pit.count[t] += 0xffff; + pit.c[t] += (int)((0xffff << TIMER_SHIFT) * PITCONST); + break; + case 2: /*Rate generator*/ + pit.count[t] += l; + pit.c[t] += (int)((l << TIMER_SHIFT) * PITCONST); + pit_set_out(t, 0); + pit_set_out(t, 1); + break; + case 3: /*Square wave mode*/ + if (pit.out[t]) + { + pit_set_out(t, 0); + pit.count[t] += (l >> 1); + pit.c[t] += (int)(((l >> 1) << TIMER_SHIFT) * PITCONST); + } + else + { + pit_set_out(t, 1); + pit.count[t] += ((l + 1) >> 1); + pit.c[t] = (int)((((l + 1) >> 1) << TIMER_SHIFT) * PITCONST); + } +// if (!t) pclog("pit_over: square wave mode c=%x %lli %f\n", pit.c[t], tsc, PITCONST); + break; + case 4: /*Software triggered strove*/ + if (!pit.thit[t]) + { + pit_set_out(t, 0); + pit_set_out(t, 1); + } + if (pit.newcount[t]) + { + pit.newcount[t] = 0; + pit.count[t] += l; + pit.c[t] += (int)((l << TIMER_SHIFT) * PITCONST); + } + else + { + pit.thit[t] = 1; + pit.count[t] += 0xffff; + pit.c[t] += (int)((0xffff << TIMER_SHIFT) * PITCONST); + } + break; + case 5: /*Hardware triggered strove*/ + if (!pit.thit[t]) + { + pit_set_out(t, 0); + pit_set_out(t, 1); + } + pit.thit[t] = 1; + pit.count[t] += 0xffff; + pit.c[t] += (int)((0xffff << TIMER_SHIFT) * PITCONST); + break; + } + pit.running[t] = pit.enabled[t] && pit.using_timer[t] && !pit.disabled[t]; +} + +int pit_get_timer_0() +{ + int read = (int)((pit.c[0] + ((1 << TIMER_SHIFT) - 1)) / PITCONST) >> TIMER_SHIFT; +//pclog("pit_get_timer_0: t=%i using_timer=%i m=%i\n", 0, pit.using_timer[0], pit.m[0]); + if (pit.m[0] == 2) + read++; + if (read < 0) + read = 0; + if (read > 0x10000) + read = 0x10000; + if (pit.m[0] == 3) + read <<= 1; + return read; +} + +static int pit_read_timer(int t) +{ + timer_clock(); +// pclog("pit_read_timer: t=%i using_timer=%i m=%i\n", t, pit.using_timer[t], pit.m[t]); + if (pit.using_timer[t]) + { + int read = (int)((pit.c[t] + ((1 << TIMER_SHIFT) - 1)) / PITCONST) >> TIMER_SHIFT; + if (pit.m[t] == 2) + read++; + if (read < 0) + read = 0; + if (read > 0x10000) + read = 0x10000; + if (pit.m[t] == 3) + read <<= 1; + return read; + } + if (pit.m[t] == 2) + return pit.count[t] + 1; + return pit.count[t]; +} + +extern int ins; +void pit_write(uint16_t addr, uint8_t val, void *priv) +{ + int t; + cycles -= (int)PITCONST; +// /*if (val != 0x40) */pclog("Write PIT %04X %02X %04X:%08X %i %i\n",addr,val,CS,pc,ins, pit.gate[0]); + + switch (addr&3) + { + case 3: /*CTRL*/ + if ((val&0xC0)==0xC0) + { + if (!(val&0x20)) + { + if (val & 2) + pit.rl[0] = pit.using_timer[0] ? ((int)(pit.c[0] / PITCONST) >> TIMER_SHIFT) : pit.count[0]; + if (val & 4) + pit.rl[1] = pit.using_timer[1] ? ((int)(pit.c[1] / PITCONST) >> TIMER_SHIFT) : pit.count[1]; + if (val & 8) + pit.rl[2] = pit.using_timer[2] ? ((int)(pit.c[2] / PITCONST) >> TIMER_SHIFT) : pit.count[2]; + } + if (!(val & 0x10)) + { + if (val & 2) + { + pit.read_status[0] = (pit.ctrls[0] & 0x3f) | 0x40 | (pit.out[0] ? 0x80 : 0); + pit.do_read_status[0] = 1; + } + if (val & 4) + { + pit.read_status[1] = (pit.ctrls[1] & 0x3f) | 0x40 | (pit.out[1] ? 0x80 : 0); + pit.do_read_status[1] = 1; + } + if (val & 8) + { + pit.read_status[2] = (pit.ctrls[2] & 0x3f) | 0x40 | (pit.out[2] ? 0x80 : 0); + pit.do_read_status[2] = 1; + } + } + return; + } + t = val >> 6; + pit.ctrl=val; + if ((val>>7)==3) + { + printf("Bad PIT reg select\n"); + return; +// dumpregs(); +// exit(-1); + } +// printf("CTRL write %02X\n",val); + if (!(pit.ctrl&0x30)) + { + pit.rl[t] = pit_read_timer(t); +// pclog("Timer latch %f %04X %04X\n",pit.c[0],pit.rl[0],pit.l[0]); + pit.ctrl |= 0x30; + pit.rereadlatch[t] = 0; + pit.rm[t] = 3; + pit.latched[t] = 1; + } + else + { + pit.ctrls[val>>6] = val; + pit.rm[val>>6]=pit.wm[val>>6]=(pit.ctrl>>4)&3; + pit.m[val>>6]=(val>>1)&7; + if (pit.m[val>>6]>5) + pit.m[val>>6]&=3; + if (!(pit.rm[val>>6])) + { + pit.rm[val>>6]=3; + pit.rl[t] = pit_read_timer(t); + } + pit.rereadlatch[val>>6]=1; + if ((val>>6)==2) ppispeakon=speakon=(pit.m[2]==0)?0:1; + pit.initial[t] = 1; + if (!pit.m[val >> 6]) + pit_set_out(val >> 6, 0); + else + pit_set_out(val >> 6, 1); + pit.disabled[val >> 6] = 1; +// pclog("ppispeakon %i\n",ppispeakon); + } + pit.wp=0; + pit.thit[pit.ctrl>>6]=0; + break; + case 0: case 1: case 2: /*Timers*/ + t=addr&3; +// if (t==2) ppispeakon=speakon=0; +// pclog("Write timer %02X %i\n",pit.ctrls[t],pit.wm[t]); + switch (pit.wm[t]) + { + case 1: + pit.l[t]=val; +// pit.thit[t]=0; + pit_load(t); +// pit.c[t]=pit.l[t]*PITCONST; +// if (!t) +// picintc(1); + break; + case 2: + pit.l[t]=(val<<8); +// pit.thit[t]=0; + pit_load(t); +// pit.c[t]=pit.l[t]*PITCONST; +// if (!t) +// picintc(1); + break; + case 0: + pit.l[t]&=0xFF; + pit.l[t]|=(val<<8); + pit_load(t); +// pit.c[t]=pit.l[t]*PITCONST; +// pclog("%04X %f\n",pit.l[t],pit.c[t]); +// pit.thit[t]=0; + pit.wm[t]=3; +// if (!t) +// picintc(1); + break; + case 3: + pit.l[t]&=0xFF00; + pit.l[t]|=val; + pit.wm[t]=0; + break; + } + speakval=(((float)pit.l[2]/(float)pit.l[0])*0x4000)-0x2000; +// printf("Speakval now %i\n",speakval); +// if (speakval>0x2000) +// printf("Speaker overflow - %i %i %04X %04X\n",pit.l[0],pit.l[2],pit.l[0],pit.l[2]); + if (speakval>0x2000) speakval=0x2000; +/* if (!pit.l[t]) + { + pit.l[t]|=0x10000; + pit.c[t]=pit.l[t]*PITCONST; + }*/ + break; + } +} + +uint8_t pit_read(uint16_t addr, void *priv) +{ + int t; + uint8_t temp; + cycles -= (int)PITCONST; +// printf("Read PIT %04X ",addr); + switch (addr&3) + { + case 0: case 1: case 2: /*Timers*/ + t = addr & 3; + if (pit.do_read_status[t]) + { + pit.do_read_status[t] = 0; + temp = pit.read_status[t]; + break; + } + if (pit.rereadlatch[addr & 3] && !pit.latched[addr & 3]) + { + pit.rereadlatch[addr & 3] = 0; + pit.rl[t] = pit_read_timer(t); + } + switch (pit.rm[addr & 3]) + { + case 0: + temp = pit.rl[addr & 3] >> 8; + pit.rm[addr & 3] = 3; + pit.latched[addr & 3] = 0; + pit.rereadlatch[addr & 3] = 1; + break; + case 1: + temp = (pit.rl[addr & 3]) & 0xFF; + pit.latched[addr & 3] = 0; + pit.rereadlatch[addr & 3] = 1; + break; + case 2: + temp = (pit.rl[addr & 3]) >> 8; + pit.latched[addr & 3] = 0; + pit.rereadlatch[addr & 3] = 1; + break; + case 3: + temp = (pit.rl[addr & 3]) & 0xFF; + if (pit.m[addr & 3] & 0x80) + pit.m[addr & 3] &= 7; + else + pit.rm[addr & 3] = 0; + break; + } + break; + case 3: /*Control*/ + temp = pit.ctrl; + break; + } +// pclog("%02X\n", temp); +// printf("%02X %i %i %04X:%04X %i\n",temp,pit.rm[addr&3],pit.wp,cs>>4,pc, ins); + return temp; +} + +void pit_poll() +{ +// printf("Poll pit %f %f %f\n",pit.c[0],pit.c[1],pit.c[2]); + if (pit.c[0] < 1 && pit.running[0]) + pit_over(0); + if (pit.c[1] < 1 && pit.running[1]) + pit_over(1); + if (pit.c[2] < 1 && pit.running[2]) + pit_over(2); +} + +void pit_timer_over(void *p) +{ + int timer = (int) p; +// pclog("pit_timer_over %i\n", timer); + + pit_over(timer); +} + +void pit_clock(int t) +{ + if (pit.thit[t] || !pit.enabled[t]) + return; + + if (pit.using_timer[t]) + return; + + pit.count[t] -= (pit.m[t] == 3) ? 2 : 1; + if (!pit.count[t]) + pit_over(t); +} + +void pit_set_using_timer(int t, int using_timer) +{ +// pclog("pit_set_using_timer: t=%i using_timer=%i\n", t, using_timer); + timer_process(); + if (pit.using_timer[t] && !using_timer) + pit.count[t] = pit_read_timer(t); + if (!pit.using_timer[t] && using_timer) + pit.c[t] = (int)((pit.count[t] << TIMER_SHIFT) * PITCONST); + pit.using_timer[t] = using_timer; + pit.running[t] = pit.enabled[t] && pit.using_timer[t] && !pit.disabled[t]; + timer_update_outstanding(); +} + +void pit_set_out_func(int t, void (*func)(int new_out, int old_out)) +{ + pit_set_out_funcs[t] = func; +} + +void pit_null_timer(int new_out, int old_out) +{ +} + +void pit_irq0_timer(int new_out, int old_out) +{ + if (new_out && !old_out) + picint(1); + if (!new_out) + picintc(1); +} + +void pit_irq0_timer_pcjr(int new_out, int old_out) +{ + if (new_out && !old_out) + { + picint(1); + pit_clock(1); + } + if (!new_out) + picintc(1); +} + +void pit_refresh_timer_xt(int new_out, int old_out) +{ + if (new_out && !old_out) + dma_channel_read(0); +} + +void pit_refresh_timer_at(int new_out, int old_out) +{ + if (new_out && !old_out) + ppi.pb ^= 0x10; +} + +void pit_speaker_timer(int new_out, int old_out) +{ + int l; + + speaker_update(); + + l = pit.l[2] ? pit.l[2] : 0x10000; + if (l < 25) + speakon = 0; + else + speakon = new_out; + ppispeakon = new_out; +} + + +void pit_init() +{ + io_sethandler(0x0040, 0x0004, pit_read, NULL, NULL, pit_write, NULL, NULL, NULL); + pit.gate[0] = pit.gate[1] = 1; + pit.gate[2] = 0; + pit.using_timer[0] = pit.using_timer[1] = pit.using_timer[2] = 1; + + timer_add(pit_timer_over, &pit.c[0], &pit.running[0], (void *)0); + timer_add(pit_timer_over, &pit.c[1], &pit.running[1], (void *)1); + timer_add(pit_timer_over, &pit.c[2], &pit.running[2], (void *)2); + + pit_set_out_func(0, pit_irq0_timer); + pit_set_out_func(1, pit_null_timer); + pit_set_out_func(2, pit_speaker_timer); +} diff --git a/src/pit.h b/src/pit.h new file mode 100644 index 000000000..a9d5cbc66 --- /dev/null +++ b/src/pit.h @@ -0,0 +1,16 @@ +extern double PITCONST; +extern float cpuclock; +void pit_init(); +void pit_reset(); +void pit_set_gate(int channel, int gate); +void pit_set_using_timer(int t, int using_timer); +void pit_set_out_func(int t, void (*func)(int new_out, int old_out)); +void pit_clock(int t); + + +void pit_null_timer(int new_out, int old_out); +void pit_irq0_timer(int new_out, int old_out); +void pit_irq0_timer_pcjr(int new_out, int old_out); +void pit_refresh_timer_xt(int new_out, int old_out); +void pit_refresh_timer_at(int new_out, int old_out); +void pit_speaker_timer(int new_out, int old_out); diff --git a/src/plat-dinput.h b/src/plat-dinput.h new file mode 100644 index 000000000..442729dab --- /dev/null +++ b/src/plat-dinput.h @@ -0,0 +1 @@ +extern LPDIRECTINPUT lpdi; diff --git a/src/plat-joystick.h b/src/plat-joystick.h new file mode 100644 index 000000000..2b789f5f8 --- /dev/null +++ b/src/plat-joystick.h @@ -0,0 +1,65 @@ +#ifdef __cplusplus +extern "C" { +#endif + void joystick_init(); + void joystick_close(); + void joystick_poll(); + + typedef struct plat_joystick_t + { + char name[64]; + + int a[8]; + int b[32]; + int p[4]; + + struct + { + char name[32]; + int id; + } axis[8]; + + struct + { + char name[32]; + int id; + } button[32]; + + struct + { + char name[32]; + int id; + } pov[4]; + + int nr_axes; + int nr_buttons; + int nr_povs; + } plat_joystick_t; + + #define MAX_PLAT_JOYSTICKS 8 + + extern plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS]; + extern int joysticks_present; + + #define POV_X 0x80000000 + #define POV_Y 0x40000000 + + typedef struct joystick_t + { + int axis[8]; + int button[32]; + int pov[4]; + + int plat_joystick_nr; + int axis_mapping[8]; + int button_mapping[32]; + } joystick_t; + + #define MAX_JOYSTICKS 4 + extern joystick_t joystick_state[MAX_JOYSTICKS]; + + #define JOYSTICK_PRESENT(n) (joystick_state[n].plat_joystick_nr != 0) + +#ifdef __cplusplus +} +#endif \ No newline at end of file diff --git a/src/plat-keyboard.h b/src/plat-keyboard.h new file mode 100644 index 000000000..6dad21d6e --- /dev/null +++ b/src/plat-keyboard.h @@ -0,0 +1,19 @@ +#ifdef __cplusplus +extern "C" { +#endif + void keyboard_init(); + void keyboard_close(); + void keyboard_poll_host(); + extern int pcem_key[272]; + extern int rawinputkey[272]; + +#ifndef __unix + #define KEY_LCONTROL 0x1d + #define KEY_RCONTROL (0x1d | 0x80) + #define KEY_END (0x4f | 0x80) +#endif + +#ifdef __cplusplus +} +#endif + diff --git a/src/plat-midi.h b/src/plat-midi.h new file mode 100644 index 000000000..ec0a469da --- /dev/null +++ b/src/plat-midi.h @@ -0,0 +1,3 @@ +void midi_init(); +void midi_close(); +void midi_write(uint8_t val); diff --git a/src/plat-mouse.h b/src/plat-mouse.h new file mode 100644 index 000000000..749f27bda --- /dev/null +++ b/src/plat-mouse.h @@ -0,0 +1,13 @@ +#ifdef __cplusplus +extern "C" { +#endif + + void mouse_init(); + void mouse_close(); + extern int mouse_buttons; + void mouse_poll_host(); + void mouse_get_mickeys(int *x, int *y); + extern int mousecapture; +#ifdef __cplusplus +} +#endif diff --git a/src/ppi.c b/src/ppi.c new file mode 100644 index 000000000..246116414 --- /dev/null +++ b/src/ppi.c @@ -0,0 +1,19 @@ +/*IBM 5150 cassette nonsense + Calls F979 twice + Expects CX to be nonzero, BX >$410 and <$540 + CX is loops between bit 4 of $62 changing + BX is timer difference between calls + */ + +#include "ibm.h" +#include "pit.h" + +#include "plat-keyboard.h" +#include "plat-mouse.h" + +void ppi_reset() +{ + ppi.pa=0x0;//0x1D; + ppi.pb=0x40; +} + diff --git a/src/ps1.c b/src/ps1.c new file mode 100644 index 000000000..988bde71a --- /dev/null +++ b/src/ps1.c @@ -0,0 +1,295 @@ +#include "ibm.h" +#include "mem.h" +#include "ps1.h" +#include "rom.h" +#include "lpt.h" + +static rom_t ps1_high_rom; +static uint8_t ps1_92, ps1_94, ps1_102, ps1_103, ps1_104, ps1_105, ps1_190; +static int ps1_e0_addr; +static uint8_t ps1_e0_regs[256]; + +static struct +{ + uint8_t status, int_status; + uint8_t attention, ctrl; +} ps1_hd; + +uint8_t ps1_read(uint16_t port, void *p) +{ + uint8_t temp; + + switch (port) + { + case 0x91: + return 0; + case 0x92: + return ps1_92; + case 0x94: + return ps1_94; + case 0x102: + return ps1_102 | 8; + case 0x103: + return ps1_103; + case 0x104: + return ps1_104; + case 0x105: + return ps1_105; + case 0x190: + return ps1_190; + + case 0x322: + temp = ps1_hd.status; + break; + case 0x324: + temp = ps1_hd.int_status; + ps1_hd.int_status &= ~0x02; + break; + + default: + temp = 0xff; + break; + } + + return temp; +} + +void ps1_write(uint16_t port, uint8_t val, void *p) +{ + switch (port) + { + case 0x0092: + ps1_92 = val; + mem_a20_alt = val & 2; + mem_a20_recalc(); + break; + case 0x94: + ps1_94 = val; + break; + case 0x102: + lpt1_remove(); + if (val & 0x04) + serial1_init(0x3f8, 4); + else + serial1_remove(); + if (val & 0x10) + { + switch ((val >> 5) & 3) + { + case 0: + lpt1_init(0x3bc); + break; + case 1: + lpt1_init(0x378); + break; + case 2: + lpt1_init(0x278); + break; + } + } + ps1_102 = val; + break; + case 0x103: + ps1_103 = val; + break; + case 0x104: + ps1_104 = val; + break; + case 0x105: + ps1_105 = val; + break; + case 0x190: + ps1_190 = val; + break; + + case 0x322: + ps1_hd.ctrl = val; + if (val & 0x80) + ps1_hd.status |= 0x02; + break; + case 0x324: + ps1_hd.attention = val & 0xf0; + if (ps1_hd.attention) + ps1_hd.status = 0x14; + break; + } +} + +void ps1mb_init() +{ + io_sethandler(0x0091, 0x0001, ps1_read, NULL, NULL, ps1_write, NULL, NULL, NULL); + io_sethandler(0x0092, 0x0001, ps1_read, NULL, NULL, ps1_write, NULL, NULL, NULL); + io_sethandler(0x0094, 0x0001, ps1_read, NULL, NULL, ps1_write, NULL, NULL, NULL); + io_sethandler(0x0102, 0x0004, ps1_read, NULL, NULL, ps1_write, NULL, NULL, NULL); + io_sethandler(0x0190, 0x0001, ps1_read, NULL, NULL, ps1_write, NULL, NULL, NULL); + io_sethandler(0x0320, 0x0001, ps1_read, NULL, NULL, ps1_write, NULL, NULL, NULL); + io_sethandler(0x0322, 0x0001, ps1_read, NULL, NULL, ps1_write, NULL, NULL, NULL); + io_sethandler(0x0324, 0x0001, ps1_read, NULL, NULL, ps1_write, NULL, NULL, NULL); + + rom_init(&ps1_high_rom, + "roms/ibmps1es/f80000.bin", + 0xf80000, + 0x80000, + 0x7ffff, + 0, + MEM_MAPPING_EXTERNAL); +/* rom_init_interleaved(&ps1_high_rom, + "roms/ibmps1es/ibm_1057757_24-05-90.bin", + "roms/ibmps1es/ibm_1057757_29-15-90.bin", + 0xfc0000, + 0x40000, + 0x3ffff, + 0, + MEM_MAPPING_EXTERNAL);*/ + ps1_190 = 0; + + lpt1_remove(); + lpt2_remove(); + lpt1_init(0x3bc); + + serial1_remove(); + serial2_remove(); + + memset(&ps1_hd, 0, sizeof(ps1_hd)); +} + +/*PS/1 Model 2121. + + This is similar to the model 2011 but some of the functionality has moved to a + chip at ports 0xe0 (index)/0xe1 (data). The only functions I have identified + are enables for the first 512kb and next 128kb of RAM, in bits 0 of registers + 0 and 1 respectively. + + Port 0x105 has bit 7 forced high. Without this 128kb of memory will be missed + by the BIOS on cold boots. + + The reserved 384kb is remapped to the top of extended memory. If this is not + done then you get an error on startup. +*/ +static uint8_t ps1_m2121_read(uint16_t port, void *p) +{ + uint8_t temp; + + switch (port) + { + case 0x91: + return 0; + case 0x92: + return ps1_92; + case 0x94: + return ps1_94; + case 0xe1: + return ps1_e0_regs[ps1_e0_addr]; + case 0x102: + return ps1_102; + case 0x103: + return ps1_103; + case 0x104: + return ps1_104; + case 0x105: + return ps1_105 | 0x80; + case 0x190: + return ps1_190; + + default: + temp = 0xff; + break; + } + + return temp; +} + +static void ps1_m2121_recalc_memory() +{ + /*Enable first 512kb*/ + mem_set_mem_state(0x00000, 0x80000, (ps1_e0_regs[0] & 0x01) ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL)); + /*Enable 512-640kb*/ + mem_set_mem_state(0x80000, 0x20000, (ps1_e0_regs[1] & 0x01) ? (MEM_READ_INTERNAL | MEM_WRITE_INTERNAL) : (MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL)); +} + +void ps1_m2121_write(uint16_t port, uint8_t val, void *p) +{ + switch (port) + { + case 0x0092: + if (val & 1) + softresetx86(); + ps1_92 = val & ~1; + mem_a20_alt = val & 2; + mem_a20_recalc(); + break; + case 0x94: + ps1_94 = val; + break; + case 0xe0: + ps1_e0_addr = val; + break; + case 0xe1: + ps1_e0_regs[ps1_e0_addr] = val; + ps1_m2121_recalc_memory(); + break; + case 0x102: + lpt1_remove(); + if (val & 0x04) + serial1_init(0x3f8, 4); + else + serial1_remove(); + if (val & 0x10) + { + switch ((val >> 5) & 3) + { + case 0: + lpt1_init(0x3bc); + break; + case 1: + lpt1_init(0x378); + break; + case 2: + lpt1_init(0x278); + break; + } + } + ps1_102 = val; + break; + case 0x103: + ps1_103 = val; + break; + case 0x104: + ps1_104 = val; + break; + case 0x105: + ps1_105 = val; + break; + case 0x190: + ps1_190 = val; + break; + } +} + +void ps1mb_m2121_init() +{ + io_sethandler(0x0091, 0x0001, ps1_m2121_read, NULL, NULL, ps1_m2121_write, NULL, NULL, NULL); + io_sethandler(0x0092, 0x0001, ps1_m2121_read, NULL, NULL, ps1_m2121_write, NULL, NULL, NULL); + io_sethandler(0x0094, 0x0001, ps1_m2121_read, NULL, NULL, ps1_m2121_write, NULL, NULL, NULL); + io_sethandler(0x00e0, 0x0002, ps1_m2121_read, NULL, NULL, ps1_m2121_write, NULL, NULL, NULL); + io_sethandler(0x0102, 0x0004, ps1_m2121_read, NULL, NULL, ps1_m2121_write, NULL, NULL, NULL); + io_sethandler(0x0190, 0x0001, ps1_m2121_read, NULL, NULL, ps1_m2121_write, NULL, NULL, NULL); + + rom_init(&ps1_high_rom, + "roms/ibmps1_2121/fc0000.bin", + 0xfc0000, + 0x40000, + 0x3ffff, + 0, + MEM_MAPPING_EXTERNAL); + ps1_190 = 0; + + lpt1_remove(); + lpt2_remove(); + lpt1_init(0x3bc); + + serial1_remove(); + serial2_remove(); + + mem_remap_top_384k(); +} diff --git a/src/ps1.h b/src/ps1.h new file mode 100644 index 000000000..4216fbc00 --- /dev/null +++ b/src/ps1.h @@ -0,0 +1,2 @@ +void ps1mb_init(); +void ps1mb_m2121_init(); diff --git a/src/resid-fp/AUTHORS b/src/resid-fp/AUTHORS new file mode 100644 index 000000000..cd2ca3fcc --- /dev/null +++ b/src/resid-fp/AUTHORS @@ -0,0 +1,4 @@ +Authors of reSID. + +Dag Lem: Designed and programmed complete emulation engine. +Antti S. Lankila: Support 6581 filter distortion, envelope & voice nonlinearities, output amp clipping effects. diff --git a/src/resid-fp/COPYING b/src/resid-fp/COPYING new file mode 100644 index 000000000..d60c31a97 --- /dev/null +++ b/src/resid-fp/COPYING @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/src/resid-fp/ChangeLog b/src/resid-fp/ChangeLog new file mode 100644 index 000000000..c12e828b9 --- /dev/null +++ b/src/resid-fp/ChangeLog @@ -0,0 +1,136 @@ +2008-12-05 Antti S. Lankila + + * Sync against V27 patch version. Filter updates described below. + + * Reduce Q maximum to 2.2 or so. This may still be slightly too much, + but it's hard to say exactly... + + * Arrange for about 3 dB boost of lowpass output that is independent + of state variable mixing or other feedback. This seems to produce + the right kind of sounds for songs like AMJ's Blasphemy. + + * Assume that bp is slightly louder than bp (= more distorted). + This seems to help against very large number of songs which sport + lead sounds and effects distorted in a smooth, bassy way. + + * Parameter tuneup. + +2008-10-31 Antti S. Lankila + + * Sync against V25 patch version. Filter updates described below. + + * Tweak filter algorithm to do some state variable mixing in the + 6581 code path. This corresponds with assumed output impedance of + the SID "amplifiers", and is separate effect to the output strip + backmixing. + + * Retire the V24 attempt of dynamically adjusting BP distortion + threshold. It doesn't really seem to work. + + * Increase Q value maximum to 2.5. This may be too much, but it sounds + fine to me. + + * JT's Star Ball was very distorted when played by V24. This related + to the hardclipping I had assumed to occur in the filter output amp, + but maybe that theory is incorrect. I now only add distortion to the + unfiltered voice path, but I'm not happy about it. + +2008-08-29 Antti S. Lankila + + * Optimized resampling to be about 2x faster through using aliasing + to increase passband width and hence reduce FIR length. + + * Fixed some valgrind warnings. + + * Added nuke_denormals() method to periodically flush these to zero, as + this can only be done for SSE registers by the FPU and we can't use + any in order to support CPUs older than P3. + + * Marco, Hannu and me developed a runtime switching system + that detects SSE from cpuinfo and calls some SSE routines when they + are compiled in and the CPU can support them. We lost only very + little performance, but gained compatibility to very, very old + hardware. + + * The old code for ST_lockup proved unnecessary, so it is now removed. + +2008-08-21 Antti S. Lankila + + * Fixed a bug where nonlinearity setting appeared to get lost, and + kenchis discovered further bugs in it. Oh well. + + * I removed a lot of code associated with the lower quality modes of + ReSID, and only left the 1 MHz clock routines. Analysis shows that the + filter code is a major culprit, but the digital side emulation is not + completely cheap, either. I already added some small hacks to optimize + it, and I now think about reinjecting pieces of those clocking modes + that run the analog parts with reduced accuracy. + + * I defined type4 filters based on equation of straight line. These are + characterized by parameters k and b, and the equation is + freq = k * fc. Strictly speaking, straight line is not 100 % + accurate, and a 2nd degree component would help, but based on + measurements against two of Trurl's 8580s, the maximum error + introduced using linear approximation is mere 3 %. + +2008-08-10 Antti S. Lankila + + * I ripped off Type1 definitions from the filter, and the spline.h + and PointPlotter were unnecessary and so removed. + + * I also added a bit of hardclipping in the output that seems to be + required to get Fred Gray's Break Thru. This might not occur so + strongly on all chips, so it should probably be added as a proper + tunable. For now, I just settled for a slight effect to collect + feedback. + +2008-07-15 Antti S. Lankila + + * This release is a bit slower than usual. The culprit is the changes in + voice.h where a new kinked-dac style calculation is used to simulate + the nonlinear shape of the waveform outputs. The cost of the new + calculation varies by song as I was lazy and only cached the result of + previous calculation, so speed depends on the pitch of the waveforms + and the precise waveform chosen. + + * exp() is back, but this time it is implemented as an integer + calculation according to Schraudolph's paper "A Fast, Compact + Approximation of the Exponential Function". Using near-proper exp() + simplified the distortion algorithm. I think it all sounds much better + now. + + * A new effect where I mix bp-hp and lp-bp together by their difference + to simulate a small resistor between them appears to improve SidRiders + and several other songs, largerly eliminating some types of hard + distortion sounds that do not occur on the chip. It also helped + Mechanicus. I am trying to understand where this term comes from... + +2008-07-09 Antti S. Lankila + + * I now have somewhat less arbitrary values for the distortion + tunables. They are now related to the relative signal levels in the + simulation. I'm still sorting out the particulars of the values I + ended up with ("why 128 instead of 256"). + +2008-03-02 Antti S. Lankila + + * Exposed the filter at sid.cc to callers through get_filter() + method, and fixed a few types. + +2008-02-19 Antti S. Lankila + + * For some reason ReSID code adjusted the external filter frequency + based on calculated passband, while in the real C64 the filter is + fixed to about 16 kHz. + +2008-02-06 Antti S. Lankila + + * I got interested to improve ReSID after chatting with Kevtris. He is + aiming to replicate the filter using analog hardware. He has the EE + experience that I have sorely lacked and made an infinitely valuable + contribution by telling me exactly how the distortion works. + +2004-06-11 Dag Lem + + * Version 0.16 released. (From this point forwards, read + ../resid/ChangeLog.) diff --git a/src/resid-fp/INSTALL b/src/resid-fp/INSTALL new file mode 100644 index 000000000..4573d6544 --- /dev/null +++ b/src/resid-fp/INSTALL @@ -0,0 +1,14 @@ +Unless you want to do anything fancy, just say: + +% ./configure +% make + +ReSID-FP is compiled with a C++ compiler, so if you wish to specify compiler +and compiler flags you must set CXX and CXXFLAGS, e.g.: +% CXX=g++ CXXFLAGS="-g -O" ./configure + +In addition to normal configure flags, you may specify +--disable-inline - Disable inlining of functions (for debugging/profiling) + +ReSID-FP makes no installable files. The libresid.a is linked to final +executable automatically. diff --git a/src/resid-fp/Makefile.am b/src/resid-fp/Makefile.am new file mode 100644 index 000000000..5af263229 --- /dev/null +++ b/src/resid-fp/Makefile.am @@ -0,0 +1,29 @@ +## Process this file with automake to create Makefile.in + +AR = @AR@ + +noinst_LIBRARIES = libresidfp.a + +libresidfp_a_SOURCES = sid.cc voice.cc wave.cc envelope.cc filter.cc extfilt.cc pot.cc version.cc convolve.cc $(noinst_DATA:.dat=.cc) + +BUILT_SOURCES = $(noinst_DATA:.dat=.cc) + +noinst_HEADERS = sid.h voice.h wave.h envelope.h filter.h extfilt.h pot.h + +noinst_DATA = wave6581_PST.dat wave6581_PS_.dat wave6581_P_T.dat wave6581__ST.dat wave8580_PST.dat wave8580_PS_.dat wave8580_P_T.dat wave8580__ST.dat + +noinst_SCRIPTS = samp2src.pl + +EXTRA_DIST = $(noinst_HEADERS) $(noinst_DATA) $(noinst_SCRIPTS) README.VICE convolve-sse.cc + +SUFFIXES = .dat + +.dat.cc: + $(PERL) $(srcdir)/samp2src.pl $* $< $(srcdir)/$@ + +if USE_SSE +convolve-sse.o: convolve-sse.cc + $(CXXCOMPILE) -msse -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< + +libresidfp_a_LIBADD = convolve-sse.o +endif diff --git a/src/resid-fp/Makefile.in b/src/resid-fp/Makefile.in new file mode 100644 index 000000000..5045f99a1 --- /dev/null +++ b/src/resid-fp/Makefile.in @@ -0,0 +1,557 @@ +# Makefile.in generated by automake 1.9.6 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005 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 = : +subdir = . +DIST_COMMON = README $(am__configure_deps) $(noinst_HEADERS) \ + $(srcdir)/../../depcomp $(srcdir)/../../install-sh \ + $(srcdir)/../../missing $(srcdir)/../../mkinstalldirs \ + $(srcdir)/Makefile.am $(srcdir)/Makefile.in \ + $(srcdir)/siddefs-fp.h.in $(top_srcdir)/configure AUTHORS \ + COPYING ChangeLog INSTALL NEWS +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/configure.in +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ + configure.lineno configure.status.lineno +mkinstalldirs = $(SHELL) $(top_srcdir)/../../mkinstalldirs +CONFIG_CLEAN_FILES = siddefs-fp.h +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +libresidfp_a_AR = $(AR) $(ARFLAGS) +@USE_SSE_TRUE@libresidfp_a_DEPENDENCIES = convolve-sse.o +am__objects_1 = wave6581_PST.$(OBJEXT) wave6581_PS_.$(OBJEXT) \ + wave6581_P_T.$(OBJEXT) wave6581__ST.$(OBJEXT) \ + wave8580_PST.$(OBJEXT) wave8580_PS_.$(OBJEXT) \ + wave8580_P_T.$(OBJEXT) wave8580__ST.$(OBJEXT) +am_libresidfp_a_OBJECTS = sid.$(OBJEXT) voice.$(OBJEXT) wave.$(OBJEXT) \ + envelope.$(OBJEXT) filter.$(OBJEXT) extfilt.$(OBJEXT) \ + pot.$(OBJEXT) version.$(OBJEXT) convolve.$(OBJEXT) \ + $(am__objects_1) +libresidfp_a_OBJECTS = $(am_libresidfp_a_OBJECTS) +SCRIPTS = $(noinst_SCRIPTS) +DEFAULT_INCLUDES = -I. -I$(srcdir) +depcomp = $(SHELL) $(top_srcdir)/../../depcomp +am__depfiles_maybe = depfiles +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +CXXLD = $(CXX) +CXXLINK = $(CXXLD) $(AM_CXXFLAGS) $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) \ + -o $@ +SOURCES = $(libresidfp_a_SOURCES) +DIST_SOURCES = $(libresidfp_a_SOURCES) +DATA = $(noinst_DATA) +HEADERS = $(noinst_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +distdir = $(PACKAGE)-$(VERSION) +top_distdir = $(distdir) +am__remove_distdir = \ + { test ! -d $(distdir) \ + || { find $(distdir) -type d ! -perm -200 -exec chmod u+w {} ';' \ + && rm -fr $(distdir); }; } +DIST_ARCHIVES = $(distdir).tar.gz +GZIP_ENV = --best +distuninstallcheck_listfiles = find . -type f -print +distcleancheck_listfiles = find . -type f -print +ACLOCAL = @ACLOCAL@ +AMDEP_FALSE = @AMDEP_FALSE@ +AMDEP_TRUE = @AMDEP_TRUE@ +AMTAR = @AMTAR@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CPPFLAGS = @CPPFLAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +GREP = @GREP@ +HAVE_EXPF_PROTOTYPE = @HAVE_EXPF_PROTOTYPE@ +HAVE_LOGF_PROTOTYPE = @HAVE_LOGF_PROTOTYPE@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +LDFLAGS = @LDFLAGS@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +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@ +PERL = @PERL@ +RANLIB = @RANLIB@ +RESID_HAVE_BOOL = @RESID_HAVE_BOOL@ +RESID_INLINE = @RESID_INLINE@ +RESID_USE_SSE = @RESID_USE_SSE@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +USE_SSE_FALSE = @USE_SSE_FALSE@ +USE_SSE_TRUE = @USE_SSE_TRUE@ +VERSION = @VERSION@ +ac_ct_CXX = @ac_ct_CXX@ +am__fastdepCXX_FALSE = @am__fastdepCXX_FALSE@ +am__fastdepCXX_TRUE = @am__fastdepCXX_TRUE@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build_alias = @build_alias@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +host_alias = @host_alias@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +noinst_LIBRARIES = libresidfp.a +libresidfp_a_SOURCES = sid.cc voice.cc wave.cc envelope.cc filter.cc extfilt.cc pot.cc version.cc convolve.cc $(noinst_DATA:.dat=.cc) +BUILT_SOURCES = $(noinst_DATA:.dat=.cc) +noinst_HEADERS = sid.h voice.h wave.h envelope.h filter.h extfilt.h pot.h +noinst_DATA = wave6581_PST.dat wave6581_PS_.dat wave6581_P_T.dat wave6581__ST.dat wave8580_PST.dat wave8580_PS_.dat wave8580_P_T.dat wave8580__ST.dat +noinst_SCRIPTS = samp2src.pl +EXTRA_DIST = $(noinst_HEADERS) $(noinst_DATA) $(noinst_SCRIPTS) README.VICE convolve-sse.cc +SUFFIXES = .dat +@USE_SSE_TRUE@libresidfp_a_LIBADD = convolve-sse.o +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .dat .cc .o .obj +am--refresh: + @: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + echo ' cd $(srcdir) && $(AUTOMAKE) --gnu '; \ + cd $(srcdir) && $(AUTOMAKE) --gnu \ + && exit 0; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu Makefile'; \ + cd $(top_srcdir) && \ + $(AUTOMAKE) --gnu Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + echo ' $(SHELL) ./config.status'; \ + $(SHELL) ./config.status;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + $(SHELL) ./config.status --recheck + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(srcdir) && $(AUTOCONF) +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) +siddefs-fp.h: $(top_builddir)/config.status $(srcdir)/siddefs-fp.h.in + cd $(top_builddir) && $(SHELL) ./config.status $@ + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) +libresidfp.a: $(libresidfp_a_OBJECTS) $(libresidfp_a_DEPENDENCIES) + -rm -f libresidfp.a + $(libresidfp_a_AR) libresidfp.a $(libresidfp_a_OBJECTS) $(libresidfp_a_LIBADD) + $(RANLIB) libresidfp.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/convolve.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/envelope.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/extfilt.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/filter.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pot.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sid.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/voice.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave6581_PST.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave6581_PS_.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave6581_P_T.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave6581__ST.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave8580_PST.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave8580_PS_.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave8580_P_T.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/wave8580__ST.Po@am__quote@ + +.cc.o: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ $<; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ if $(CXXCOMPILE) -MT $@ -MD -MP -MF "$(DEPDIR)/$*.Tpo" -c -o $@ `$(CYGPATH_W) '$<'`; \ +@am__fastdepCXX_TRUE@ then mv -f "$(DEPDIR)/$*.Tpo" "$(DEPDIR)/$*.Po"; else rm -f "$(DEPDIR)/$*.Tpo"; exit 1; fi +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` +uninstall-info-am: + +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: TAGS + +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; }'`; \ + if test -z "$(ETAGS_ARGS)$$tags$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$tags $$unique; \ + fi +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 + +distdir: $(DISTFILES) + $(am__remove_distdir) + mkdir $(distdir) + $(mkdir_p) $(distdir)/. $(distdir)/../.. + @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"; \ + $(mkdir_p) "$(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 + -find $(distdir) -type d ! -perm -777 -exec chmod a+rwx {} \; -o \ + ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -400 -exec chmod a+r {} \; -o \ + ! -type d ! -perm -444 -exec $(SHELL) $(install_sh) -c -m a+r {} {} \; \ + || chmod -R a+r $(distdir) +dist-gzip: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +dist-bzip2: distdir + tardir=$(distdir) && $(am__tar) | bzip2 -9 -c >$(distdir).tar.bz2 + $(am__remove_distdir) + +dist-tarZ: distdir + tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z + $(am__remove_distdir) + +dist-shar: distdir + shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz + $(am__remove_distdir) + +dist-zip: distdir + -rm -f $(distdir).zip + zip -rq $(distdir).zip $(distdir) + $(am__remove_distdir) + +dist dist-all: distdir + tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz + $(am__remove_distdir) + +# This target untars the dist file and tries a VPATH configuration. Then +# it guarantees that the distribution is self-contained by making another +# tarfile. +distcheck: dist + case '$(DIST_ARCHIVES)' in \ + *.tar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).tar.gz | $(am__untar) ;;\ + *.tar.bz2*) \ + bunzip2 -c $(distdir).tar.bz2 | $(am__untar) ;;\ + *.tar.Z*) \ + uncompress -c $(distdir).tar.Z | $(am__untar) ;;\ + *.shar.gz*) \ + GZIP=$(GZIP_ENV) gunzip -c $(distdir).shar.gz | unshar ;;\ + *.zip*) \ + unzip $(distdir).zip ;;\ + esac + chmod -R a-w $(distdir); chmod a+w $(distdir) + mkdir $(distdir)/_build + mkdir $(distdir)/_inst + chmod a-w $(distdir) + dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \ + && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \ + && cd $(distdir)/_build \ + && ../configure --srcdir=.. --prefix="$$dc_install_base" \ + $(DISTCHECK_CONFIGURE_FLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) \ + && $(MAKE) $(AM_MAKEFLAGS) dvi \ + && $(MAKE) $(AM_MAKEFLAGS) check \ + && $(MAKE) $(AM_MAKEFLAGS) install \ + && $(MAKE) $(AM_MAKEFLAGS) installcheck \ + && $(MAKE) $(AM_MAKEFLAGS) uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \ + distuninstallcheck \ + && chmod -R a-w "$$dc_install_base" \ + && ({ \ + (cd ../.. && umask 077 && mkdir "$$dc_destdir") \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \ + && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \ + distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \ + } || { rm -rf "$$dc_destdir"; exit 1; }) \ + && rm -rf "$$dc_destdir" \ + && $(MAKE) $(AM_MAKEFLAGS) dist \ + && rm -rf $(DIST_ARCHIVES) \ + && $(MAKE) $(AM_MAKEFLAGS) distcleancheck + $(am__remove_distdir) + @(echo "$(distdir) archives ready for distribution: "; \ + list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \ + sed -e '1{h;s/./=/g;p;x;}' -e '$${p;x;}' +distuninstallcheck: + @cd $(distuninstallcheck_dir) \ + && test `$(distuninstallcheck_listfiles) | wc -l` -le 1 \ + || { echo "ERROR: files left after uninstall:" ; \ + if test -n "$(DESTDIR)"; then \ + echo " (check DESTDIR support)"; \ + fi ; \ + $(distuninstallcheck_listfiles) ; \ + exit 1; } >&2 +distcleancheck: distclean + @if test '$(srcdir)' = . ; then \ + echo "ERROR: distcleancheck can only run from a VPATH build" ; \ + exit 1 ; \ + fi + @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \ + || { echo "ERROR: files left in build directory after distclean:" ; \ + $(distcleancheck_listfiles) ; \ + exit 1; } >&2 +check-am: all-am +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile $(LIBRARIES) $(SCRIPTS) $(DATA) $(HEADERS) +installdirs: +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +clean: clean-am + +clean-am: clean-generic clean-noinstLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-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 + -rm -f $(am__CONFIG_DISTCLEAN_FILES) + -rm -rf $(top_srcdir)/autom4te.cache + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-info-am + +.PHONY: CTAGS GTAGS all all-am am--refresh check check-am clean \ + clean-generic clean-noinstLIBRARIES ctags dist dist-all \ + dist-bzip2 dist-gzip dist-shar dist-tarZ dist-zip distcheck \ + distclean distclean-compile distclean-generic distclean-tags \ + distcleancheck distdir distuninstallcheck dvi dvi-am html \ + html-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 pdf pdf-am ps ps-am tags uninstall \ + uninstall-am uninstall-info-am + + +.dat.cc: + $(PERL) $(srcdir)/samp2src.pl $* $< $(srcdir)/$@ + +@USE_SSE_TRUE@convolve-sse.o: convolve-sse.cc +@USE_SSE_TRUE@ $(CXXCOMPILE) -msse -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$< +# 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/src/resid-fp/NEWS b/src/resid-fp/NEWS new file mode 100644 index 000000000..70b2d4f8e --- /dev/null +++ b/src/resid-fp/NEWS @@ -0,0 +1 @@ +See ChangeLog for information about new features. diff --git a/src/resid-fp/README b/src/resid-fp/README new file mode 100644 index 000000000..ac4f4275e --- /dev/null +++ b/src/resid-fp/README @@ -0,0 +1,79 @@ +Please refer to original ../resid/README file for general discussion what +ReSID is. + +This is ReSID-FP, a fork of ReSID that has been adapted to floating point +numbers. Some SSE assembly is used for vector convolutions when both the CPU +and compiler support it. In addition, some liberties have been taken in the +frequency region > 20 kHz which should be inaudible to humans. + +In the emulation front, several changes to the original ReSID (henceforth +classical ReSID) have been made. These changes are listed here: + +Waveforms: + +- Noise waveform control via test bit is now possible. + (Unknown: how long does it take for the noise bits to fade with test bit on?) + This is used in SounDemoN's Tamaking, Bojojoing, etc, and the patch to + implement it in ReSID is his. + +- Waveform 0, the frozen DAC, is emulated, which should make the new 8-bit + sample player routine work. + +- Envelope and waveform outputs contain approximation of the imperfect DACs + (Unknown: are there other significant effects that affect the analog waveform + before it goes into filter, which should be modelled?) + +- I changed voice DC offsets around for 6581 to better match my R4AR 3789. + +Envelope: + +- Performance work at envelope. Validation pending, should ensure that the new + code behaves 100% identically to the old one. + +Mixer: + +- Experimentally, a subtle negative offset is injected into the mixer through + ext-in pin. This part seems, however, physically incorrect and is likely + removed in the future. (The coupling capacitor external to the chip must + eliminate any DC offset, and the ext-in circuit inside the chip has nothing + that could generate offsets. In the meantime, this fix still helps 8580 + Netherworld to play more correctly.) + +- I removed the mixer_DC very subtle effect on 6581, as it already has 10x + more offsets elsewhere. + +Filter: + +- 6581 filter output contains approximation of the distortion effect +- 8580 filter output has bp flipped in phase with the other outputs +- 6581 resonance is slightly boosted. Potentially 8580 resonance needs to be + slightly stronger as well, as many songs show a bit more "punch" on the real + chip and one way to get more of that is increasing resonance. 10-20 % + increment is a practical maximum. + +The upshot of all this is that for i386/x86-64 hardware, ReSID-FP's more +complicated algorithms may not seem any more expensive than the original ReSID. +For high-quality modes, it is virtually certain that ReSID-FP is actually +faster. + +Meanwhile, emulation quality should be improved. If there are bugs, I'd like +to know about them. If the filter sounds wrong, I might be able to improve it, +too. + +Here are some problematic songs, to get a feel for what's left to do: + +- Markus Mueller: Mechanicus + * the distorted guitar effect is too distorted, but don't know how/why. + +- Galway: Wizball + * the initial lead punches through with too much distortion. The "toggle" + between the muffled and more intense sound is too hard, even if similar + things do occur on the chip. + +Undoubtedly, many more such examples will be found. However, samplings and such +are really valueable only if they can be made on a chip that I have modelled +for ReSID-FP. In practice I want to know about badly-playing chips, but might +conclude that it actually plays alright. At any event, information about sound +issues is welcome. + +alankila@bel.fi diff --git a/src/resid-fp/README.VICE b/src/resid-fp/README.VICE new file mode 100644 index 000000000..02072ce9e --- /dev/null +++ b/src/resid-fp/README.VICE @@ -0,0 +1,14 @@ +This version of reSID has been modified for use with VICE. It is based on the +work contained in the resid/ directory, with duplicate files removed. All +classes have been renamed with suffix FP to avoid link-time clashes with the +other RESID implementation. + +These files reuse some define terms also defined by resid. You should not mix +resid/* and resid-fp/* files in one compile unit, or the results are probably +invalid. + +In particular, libtool is not used to build the library, and there +might be some workarounds for various substandard compilers. + +Please get the original version if you want to use reSID in your own +project. diff --git a/src/resid-fp/aclocal.m4 b/src/resid-fp/aclocal.m4 new file mode 100644 index 000000000..aef181a6d --- /dev/null +++ b/src/resid-fp/aclocal.m4 @@ -0,0 +1,850 @@ +# generated automatically by aclocal 1.9.6 -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, +# 2005 Free Software Foundation, Inc. +# This file 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. + +# Copyright (C) 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file 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. + +# AM_AUTOMAKE_VERSION(VERSION) +# ---------------------------- +# Automake X.Y traces this macro to ensure aclocal.m4 has been +# generated from the m4 files accompanying Automake X.Y. +AC_DEFUN([AM_AUTOMAKE_VERSION], [am__api_version="1.9"]) + +# AM_SET_CURRENT_AUTOMAKE_VERSION +# ------------------------------- +# Call AM_AUTOMAKE_VERSION so it can be traced. +# This function is AC_REQUIREd by AC_INIT_AUTOMAKE. +AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION], + [AM_AUTOMAKE_VERSION([1.9.6])]) + +# AM_AUX_DIR_EXPAND -*- Autoconf -*- + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file 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. + +# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets +# $ac_aux_dir to `$srcdir/foo'. In other projects, it is set to +# `$srcdir', `$srcdir/..', or `$srcdir/../..'. +# +# Of course, Automake must honor this variable whenever it calls a +# tool from the auxiliary directory. The problem is that $srcdir (and +# therefore $ac_aux_dir as well) can be either absolute or relative, +# depending on how configure is run. This is pretty annoying, since +# it makes $ac_aux_dir quite unusable in subdirectories: in the top +# source directory, any form will work fine, but in subdirectories a +# relative path needs to be adjusted first. +# +# $ac_aux_dir/missing +# fails when called from a subdirectory if $ac_aux_dir is relative +# $top_srcdir/$ac_aux_dir/missing +# fails if $ac_aux_dir is absolute, +# fails when called from a subdirectory in a VPATH build with +# a relative $ac_aux_dir +# +# The reason of the latter failure is that $top_srcdir and $ac_aux_dir +# are both prefixed by $srcdir. In an in-source build this is usually +# harmless because $srcdir is `.', but things will broke when you +# start a VPATH build or use an absolute $srcdir. +# +# So we could use something similar to $top_srcdir/$ac_aux_dir/missing, +# iff we strip the leading $srcdir from $ac_aux_dir. That would be: +# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"` +# and then we would define $MISSING as +# MISSING="\${SHELL} $am_aux_dir/missing" +# This will work as long as MISSING is not called from configure, because +# unfortunately $(top_srcdir) has no meaning in configure. +# However there are other variables, like CC, which are often used in +# configure, and could therefore not use this "fixed" $ac_aux_dir. +# +# Another solution, used here, is to always expand $ac_aux_dir to an +# absolute PATH. The drawback is that using absolute paths prevent a +# configured tree to be moved without reconfiguration. + +AC_DEFUN([AM_AUX_DIR_EXPAND], +[dnl Rely on autoconf to set up CDPATH properly. +AC_PREREQ([2.50])dnl +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` +]) + +# AM_CONDITIONAL -*- Autoconf -*- + +# Copyright (C) 1997, 2000, 2001, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file 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. + +# serial 7 + +# AM_CONDITIONAL(NAME, SHELL-CONDITION) +# ------------------------------------- +# Define a conditional. +AC_DEFUN([AM_CONDITIONAL], +[AC_PREREQ(2.52)dnl + ifelse([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])], + [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl +AC_SUBST([$1_TRUE]) +AC_SUBST([$1_FALSE]) +if $2; then + $1_TRUE= + $1_FALSE='#' +else + $1_TRUE='#' + $1_FALSE= +fi +AC_CONFIG_COMMANDS_PRE( +[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then + AC_MSG_ERROR([[conditional "$1" was never defined. +Usually this means the macro was only invoked conditionally.]]) +fi])]) + + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file 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. + +# serial 8 + +# There are a few dirty hacks below to avoid letting `AC_PROG_CC' be +# written in clear, in which case automake, when reading aclocal.m4, +# will think it sees a *use*, and therefore will trigger all it's +# C support machinery. Also note that it means that autoscan, seeing +# CC etc. in the Makefile, will ask for an AC_PROG_CC use... + + +# _AM_DEPENDENCIES(NAME) +# ---------------------- +# See how the compiler implements dependency checking. +# NAME is "CC", "CXX", "GCJ", or "OBJC". +# We try a few techniques and use that to set a single cache variable. +# +# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was +# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular +# dependency, and given that the user is not expected to run this macro, +# just rely on AC_PROG_CC. +AC_DEFUN([_AM_DEPENDENCIES], +[AC_REQUIRE([AM_SET_DEPDIR])dnl +AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl +AC_REQUIRE([AM_MAKE_INCLUDE])dnl +AC_REQUIRE([AM_DEP_TRACK])dnl + +ifelse([$1], CC, [depcc="$CC" am_compiler_list=], + [$1], CXX, [depcc="$CXX" am_compiler_list=], + [$1], OBJC, [depcc="$OBJC" am_compiler_list='gcc3 gcc'], + [$1], GCJ, [depcc="$GCJ" am_compiler_list='gcc3 gcc'], + [depcc="$$1" am_compiler_list=]) + +AC_CACHE_CHECK([dependency style of $depcc], + [am_cv_$1_dependencies_compiler_type], +[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_$1_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_$1_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_$1_dependencies_compiler_type=none +fi +]) +AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type]) +AM_CONDITIONAL([am__fastdep$1], [ + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_$1_dependencies_compiler_type" = gcc3]) +]) + + +# AM_SET_DEPDIR +# ------------- +# Choose a directory name for dependency files. +# This macro is AC_REQUIREd in _AM_DEPENDENCIES +AC_DEFUN([AM_SET_DEPDIR], +[AC_REQUIRE([AM_SET_LEADING_DOT])dnl +AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl +]) + + +# AM_DEP_TRACK +# ------------ +AC_DEFUN([AM_DEP_TRACK], +[AC_ARG_ENABLE(dependency-tracking, +[ --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors]) +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi +AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno]) +AC_SUBST([AMDEPBACKSLASH]) +]) + +# Generate code to set up dependency tracking. -*- Autoconf -*- + +# Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file 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. + +#serial 3 + +# _AM_OUTPUT_DEPENDENCY_COMMANDS +# ------------------------------ +AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS], +[for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # So let's grep whole file. + if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then + dirpart=`AS_DIRNAME("$mf")` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`AS_DIRNAME(["$file"])` + AS_MKDIR_P([$dirpart/$fdir]) + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done +])# _AM_OUTPUT_DEPENDENCY_COMMANDS + + +# AM_OUTPUT_DEPENDENCY_COMMANDS +# ----------------------------- +# This macro should only be invoked once -- use via AC_REQUIRE. +# +# This code is only required when automatic dependency tracking +# is enabled. FIXME. This creates each `.P' file that we will +# need in order to bootstrap the dependency handling code. +AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS], +[AC_CONFIG_COMMANDS([depfiles], + [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS], + [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"]) +]) + +# Do all the work for Automake. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 +# Free Software Foundation, Inc. +# +# This file 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. + +# serial 12 + +# This macro actually does too much. Some checks are only needed if +# your package does certain things. But this isn't really a big deal. + +# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE]) +# AM_INIT_AUTOMAKE([OPTIONS]) +# ----------------------------------------------- +# The call with PACKAGE and VERSION arguments is the old style +# call (pre autoconf-2.50), which is being phased out. PACKAGE +# and VERSION should now be passed to AC_INIT and removed from +# the call to AM_INIT_AUTOMAKE. +# We support both call styles for the transition. After +# the next Automake release, Autoconf can make the AC_INIT +# arguments mandatory, and then we can depend on a new Autoconf +# release and drop the old call support. +AC_DEFUN([AM_INIT_AUTOMAKE], +[AC_PREREQ([2.58])dnl +dnl Autoconf wants to disallow AM_ names. We explicitly allow +dnl the ones we care about. +m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl +AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl +AC_REQUIRE([AC_PROG_INSTALL])dnl +# test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && + test -f $srcdir/config.status; then + AC_MSG_ERROR([source directory already configured; run "make distclean" there first]) +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi +AC_SUBST([CYGPATH_W]) + +# Define the identity of the package. +dnl Distinguish between old-style and new-style calls. +m4_ifval([$2], +[m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl + AC_SUBST([PACKAGE], [$1])dnl + AC_SUBST([VERSION], [$2])], +[_AM_SET_OPTIONS([$1])dnl + AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl + AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl + +_AM_IF_OPTION([no-define],, +[AC_DEFINE_UNQUOTED(PACKAGE, "$PACKAGE", [Name of package]) + AC_DEFINE_UNQUOTED(VERSION, "$VERSION", [Version number of package])])dnl + +# Some tools Automake needs. +AC_REQUIRE([AM_SANITY_CHECK])dnl +AC_REQUIRE([AC_ARG_PROGRAM])dnl +AM_MISSING_PROG(ACLOCAL, aclocal-${am__api_version}) +AM_MISSING_PROG(AUTOCONF, autoconf) +AM_MISSING_PROG(AUTOMAKE, automake-${am__api_version}) +AM_MISSING_PROG(AUTOHEADER, autoheader) +AM_MISSING_PROG(MAKEINFO, makeinfo) +AM_PROG_INSTALL_SH +AM_PROG_INSTALL_STRIP +AC_REQUIRE([AM_PROG_MKDIR_P])dnl +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +AC_REQUIRE([AC_PROG_AWK])dnl +AC_REQUIRE([AC_PROG_MAKE_SET])dnl +AC_REQUIRE([AM_SET_LEADING_DOT])dnl +_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])], + [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])], + [_AM_PROG_TAR([v7])])]) +_AM_IF_OPTION([no-dependencies],, +[AC_PROVIDE_IFELSE([AC_PROG_CC], + [_AM_DEPENDENCIES(CC)], + [define([AC_PROG_CC], + defn([AC_PROG_CC])[_AM_DEPENDENCIES(CC)])])dnl +AC_PROVIDE_IFELSE([AC_PROG_CXX], + [_AM_DEPENDENCIES(CXX)], + [define([AC_PROG_CXX], + defn([AC_PROG_CXX])[_AM_DEPENDENCIES(CXX)])])dnl +]) +]) + + +# When config.status generates a header, we must update the stamp-h file. +# This file resides in the same directory as the config header +# that is generated. The stamp files are numbered to have different names. + +# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the +# loop where config.status creates the headers, so we can generate +# our stamp files there. +AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK], +[# Compute $1's index in $config_headers. +_am_stamp_count=1 +for _am_header in $config_headers :; do + case $_am_header in + $1 | $1:* ) + break ;; + * ) + _am_stamp_count=`expr $_am_stamp_count + 1` ;; + esac +done +echo "timestamp for $1" >`AS_DIRNAME([$1])`/stamp-h[]$_am_stamp_count]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file 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. + +# AM_PROG_INSTALL_SH +# ------------------ +# Define $install_sh. +AC_DEFUN([AM_PROG_INSTALL_SH], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +install_sh=${install_sh-"$am_aux_dir/install-sh"} +AC_SUBST(install_sh)]) + +# Copyright (C) 2003, 2005 Free Software Foundation, Inc. +# +# This file 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. + +# serial 2 + +# Check whether the underlying file-system supports filenames +# with a leading dot. For instance MS-DOS doesn't. +AC_DEFUN([AM_SET_LEADING_DOT], +[rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null +AC_SUBST([am__leading_dot])]) + +# Check to see how 'make' treats includes. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file 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. + +# serial 3 + +# AM_MAKE_INCLUDE() +# ----------------- +# Check to see how make treats includes. +AC_DEFUN([AM_MAKE_INCLUDE], +[am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo done +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +AC_MSG_CHECKING([for style of include used by $am_make]) +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi +AC_SUBST([am__include]) +AC_SUBST([am__quote]) +AC_MSG_RESULT([$_am_result]) +rm -f confinc confmf +]) + +# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*- + +# Copyright (C) 1997, 1999, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file 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. + +# serial 4 + +# AM_MISSING_PROG(NAME, PROGRAM) +# ------------------------------ +AC_DEFUN([AM_MISSING_PROG], +[AC_REQUIRE([AM_MISSING_HAS_RUN]) +$1=${$1-"${am_missing_run}$2"} +AC_SUBST($1)]) + + +# AM_MISSING_HAS_RUN +# ------------------ +# Define MISSING if not defined so far and test if it supports --run. +# If it does, set am_missing_run to use it, otherwise, to nothing. +AC_DEFUN([AM_MISSING_HAS_RUN], +[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + AC_MSG_WARN([`missing' script is too old or missing]) +fi +]) + +# Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc. +# +# This file 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. + +# AM_PROG_MKDIR_P +# --------------- +# Check whether `mkdir -p' is supported, fallback to mkinstalldirs otherwise. +# +# Automake 1.8 used `mkdir -m 0755 -p --' to ensure that directories +# created by `make install' are always world readable, even if the +# installer happens to have an overly restrictive umask (e.g. 077). +# This was a mistake. There are at least two reasons why we must not +# use `-m 0755': +# - it causes special bits like SGID to be ignored, +# - it may be too restrictive (some setups expect 775 directories). +# +# Do not use -m 0755 and let people choose whatever they expect by +# setting umask. +# +# We cannot accept any implementation of `mkdir' that recognizes `-p'. +# Some implementations (such as Solaris 8's) are not thread-safe: if a +# parallel make tries to run `mkdir -p a/b' and `mkdir -p a/c' +# concurrently, both version can detect that a/ is missing, but only +# one can create it and the other will error out. Consequently we +# restrict ourselves to GNU make (using the --version option ensures +# this.) +AC_DEFUN([AM_PROG_MKDIR_P], +[if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then + # We used to keeping the `.' as first argument, in order to + # allow $(mkdir_p) to be used without argument. As in + # $(mkdir_p) $(somedir) + # where $(somedir) is conditionally defined. However this is wrong + # for two reasons: + # 1. if the package is installed by a user who cannot write `.' + # make install will fail, + # 2. the above comment should most certainly read + # $(mkdir_p) $(DESTDIR)$(somedir) + # so it does not work when $(somedir) is undefined and + # $(DESTDIR) is not. + # To support the latter case, we have to write + # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir), + # so the `.' trick is pointless. + mkdir_p='mkdir -p --' +else + # On NextStep and OpenStep, the `mkdir' command does not + # recognize any option. It will interpret all options as + # directories to create, and then abort because `.' already + # exists. + for d in ./-p ./--version; + do + test -d $d && rmdir $d + done + # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists. + if test -f "$ac_aux_dir/mkinstalldirs"; then + mkdir_p='$(mkinstalldirs)' + else + mkdir_p='$(install_sh) -d' + fi +fi +AC_SUBST([mkdir_p])]) + +# Helper functions for option handling. -*- Autoconf -*- + +# Copyright (C) 2001, 2002, 2003, 2005 Free Software Foundation, Inc. +# +# This file 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. + +# serial 3 + +# _AM_MANGLE_OPTION(NAME) +# ----------------------- +AC_DEFUN([_AM_MANGLE_OPTION], +[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])]) + +# _AM_SET_OPTION(NAME) +# ------------------------------ +# Set option NAME. Presently that only means defining a flag for this option. +AC_DEFUN([_AM_SET_OPTION], +[m4_define(_AM_MANGLE_OPTION([$1]), 1)]) + +# _AM_SET_OPTIONS(OPTIONS) +# ---------------------------------- +# OPTIONS is a space-separated list of Automake options. +AC_DEFUN([_AM_SET_OPTIONS], +[AC_FOREACH([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])]) + +# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET]) +# ------------------------------------------- +# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise. +AC_DEFUN([_AM_IF_OPTION], +[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])]) + +# Check to make sure that the build environment is sane. -*- Autoconf -*- + +# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005 +# Free Software Foundation, Inc. +# +# This file 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. + +# serial 4 + +# AM_SANITY_CHECK +# --------------- +AC_DEFUN([AM_SANITY_CHECK], +[AC_MSG_CHECKING([whether build environment is sane]) +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$[*]" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$[*]" != "X $srcdir/configure conftest.file" \ + && test "$[*]" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken +alias in your environment]) + fi + + test "$[2]" = conftest.file + ) +then + # Ok. + : +else + AC_MSG_ERROR([newly created file is older than distributed files! +Check your system clock]) +fi +AC_MSG_RESULT(yes)]) + +# Copyright (C) 2001, 2003, 2005 Free Software Foundation, Inc. +# +# This file 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. + +# AM_PROG_INSTALL_STRIP +# --------------------- +# One issue with vendor `install' (even GNU) is that you can't +# specify the program used to strip binaries. This is especially +# annoying in cross-compiling environments, where the build's strip +# is unlikely to handle the host's binaries. +# Fortunately install-sh will honor a STRIPPROG variable, so we +# always use install-sh in `make install-strip', and initialize +# STRIPPROG with the value of the STRIP variable (set by the user). +AC_DEFUN([AM_PROG_INSTALL_STRIP], +[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +dnl Don't test for $cross_compiling = yes, because it might be `maybe'. +if test "$cross_compiling" != no; then + AC_CHECK_TOOL([STRIP], [strip], :) +fi +INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" +AC_SUBST([INSTALL_STRIP_PROGRAM])]) + +# Check how to create a tarball. -*- Autoconf -*- + +# Copyright (C) 2004, 2005 Free Software Foundation, Inc. +# +# This file 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. + +# serial 2 + +# _AM_PROG_TAR(FORMAT) +# -------------------- +# Check how to create a tarball in format FORMAT. +# FORMAT should be one of `v7', `ustar', or `pax'. +# +# Substitute a variable $(am__tar) that is a command +# writing to stdout a FORMAT-tarball containing the directory +# $tardir. +# tardir=directory && $(am__tar) > result.tar +# +# Substitute a variable $(am__untar) that extract such +# a tarball read from stdin. +# $(am__untar) < result.tar +AC_DEFUN([_AM_PROG_TAR], +[# Always define AMTAR for backward compatibility. +AM_MISSING_PROG([AMTAR], [tar]) +m4_if([$1], [v7], + [am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -'], + [m4_case([$1], [ustar],, [pax],, + [m4_fatal([Unknown tar format])]) +AC_MSG_CHECKING([how to create a $1 tar archive]) +# Loop over all known methods to create a tar archive until one works. +_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none' +_am_tools=${am_cv_prog_tar_$1-$_am_tools} +# Do not fold the above two line into one, because Tru64 sh and +# Solaris sh will not grok spaces in the rhs of `-'. +for _am_tool in $_am_tools +do + case $_am_tool in + gnutar) + for _am_tar in tar gnutar gtar; + do + AM_RUN_LOG([$_am_tar --version]) && break + done + am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"' + am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"' + am__untar="$_am_tar -xf -" + ;; + plaintar) + # Must skip GNU tar: if it does not support --format= it doesn't create + # ustar tarball either. + (tar --version) >/dev/null 2>&1 && continue + am__tar='tar chf - "$$tardir"' + am__tar_='tar chf - "$tardir"' + am__untar='tar xf -' + ;; + pax) + am__tar='pax -L -x $1 -w "$$tardir"' + am__tar_='pax -L -x $1 -w "$tardir"' + am__untar='pax -r' + ;; + cpio) + am__tar='find "$$tardir" -print | cpio -o -H $1 -L' + am__tar_='find "$tardir" -print | cpio -o -H $1 -L' + am__untar='cpio -i -H $1 -d' + ;; + none) + am__tar=false + am__tar_=false + am__untar=false + ;; + esac + + # If the value was cached, stop now. We just wanted to have am__tar + # and am__untar set. + test -n "${am_cv_prog_tar_$1}" && break + + # tar/untar a dummy directory, and stop if the command works + rm -rf conftest.dir + mkdir conftest.dir + echo GrepMe > conftest.dir/file + AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar]) + rm -rf conftest.dir + if test -s conftest.tar; then + AM_RUN_LOG([$am__untar /dev/null 2>&1 && break + fi +done +rm -rf conftest.dir + +AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool]) +AC_MSG_RESULT([$am_cv_prog_tar_$1])]) +AC_SUBST([am__tar]) +AC_SUBST([am__untar]) +]) # _AM_PROG_TAR + diff --git a/src/resid-fp/configure b/src/resid-fp/configure new file mode 100644 index 000000000..35a9c8f7d --- /dev/null +++ b/src/resid-fp/configure @@ -0,0 +1,5955 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.61. +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +as_nl=' +' +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + +if test "x$CONFIG_SHELL" = x; then + if (eval ":") 2>/dev/null; then + as_have_required=yes +else + as_have_required=no +fi + + if test $as_have_required = yes && (eval ": +(as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=\$LINENO + as_lineno_2=\$LINENO + test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" && + test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; } +") 2> /dev/null; then + : +else + as_candidate_shells= + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + case $as_dir in + /*) + for as_base in sh bash ksh sh5; do + as_candidate_shells="$as_candidate_shells $as_dir/$as_base" + done;; + esac +done +IFS=$as_save_IFS + + + for as_shell in $as_candidate_shells $SHELL; do + # Try only shells that exist, to save several forks. + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { ("$as_shell") 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + +: +_ASEOF +}; then + CONFIG_SHELL=$as_shell + as_have_required=yes + if { "$as_shell" 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + +: +(as_func_return () { + (exit $1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = "$1" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test $exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; } + +_ASEOF +}; then + break +fi + +fi + + done + + if test "x$CONFIG_SHELL" != x; then + for as_var in BASH_ENV ENV + do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + done + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +fi + + + if test $as_have_required = no; then + echo This script requires a shell more modern than all the + echo shells that I found on your system. Please install a + echo modern shell, or manually run the script under such a + echo shell if you do have one. + { (exit 1); exit 1; } +fi + + +fi + +fi + + + +(eval "as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0") || { + echo No shell found that supports shell functions. + echo Please tell autoconf@gnu.org about your system, + echo including any error possibly output before this + echo message +} + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir +fi +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + + +exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Identity of this package. +PACKAGE_NAME= +PACKAGE_TARNAME= +PACKAGE_VERSION= +PACKAGE_STRING= +PACKAGE_BUGREPORT= + +ac_unique_file="sid.h" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='SHELL +PATH_SEPARATOR +PACKAGE_NAME +PACKAGE_TARNAME +PACKAGE_VERSION +PACKAGE_STRING +PACKAGE_BUGREPORT +exec_prefix +prefix +program_transform_name +bindir +sbindir +libexecdir +datarootdir +datadir +sysconfdir +sharedstatedir +localstatedir +includedir +oldincludedir +docdir +infodir +htmldir +dvidir +pdfdir +psdir +libdir +localedir +mandir +DEFS +ECHO_C +ECHO_N +ECHO_T +LIBS +build_alias +host_alias +target_alias +INSTALL_PROGRAM +INSTALL_SCRIPT +INSTALL_DATA +CYGPATH_W +PACKAGE +VERSION +ACLOCAL +AUTOCONF +AUTOMAKE +AUTOHEADER +MAKEINFO +install_sh +STRIP +INSTALL_STRIP_PROGRAM +mkdir_p +AWK +SET_MAKE +am__leading_dot +AMTAR +am__tar +am__untar +RESID_INLINE +CXX +CXXFLAGS +LDFLAGS +CPPFLAGS +ac_ct_CXX +EXEEXT +OBJEXT +DEPDIR +am__include +am__quote +AMDEP_TRUE +AMDEP_FALSE +AMDEPBACKSLASH +CXXDEPMODE +am__fastdepCXX_TRUE +am__fastdepCXX_FALSE +AR +RANLIB +PERL +CXXCPP +GREP +EGREP +USE_SSE_TRUE +USE_SSE_FALSE +RESID_HAVE_BOOL +RESID_USE_SSE +HAVE_LOGF_PROTOTYPE +HAVE_EXPF_PROTOTYPE +LIBOBJS +LTLIBOBJS' +ac_subst_files='' + ac_precious_vars='build_alias +host_alias +target_alias +CXX +CXXFLAGS +LDFLAGS +LIBS +CPPFLAGS +CCC +CXXCPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` + eval enable_$ac_feature=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` + eval enable_$ac_feature=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/[-.]/_/g'` + eval with_$ac_package=\$ac_optarg ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/[-.]/_/g'` + eval with_$ac_package=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute directory names. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; } +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + { echo "$as_me: error: Working directory cannot be determined" >&2 + { (exit 1); exit 1; }; } +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + { echo "$as_me: error: pwd does not report name of working directory" >&2 + { (exit 1); exit 1; }; } + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$0" || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || { echo "$as_me: error: $ac_msg" >&2 + { (exit 1); exit 1; }; } + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures this package to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/PACKAGE] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF + +Program names: + --program-prefix=PREFIX prepend PREFIX to installed program names + --program-suffix=SUFFIX append SUFFIX to installed program names + --program-transform-name=PROGRAM run sed PROGRAM on installed program names +_ACEOF +fi + +if test -n "$ac_init_help"; then + + cat <<\_ACEOF + +Optional Features: + --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no) + --enable-FEATURE[=ARG] include FEATURE [ARG=yes] + --enable-inline enable inlining of functions default=yes + --enable-sse enable the use of SSE default=yes + --disable-dependency-tracking speeds up one-time build + --enable-dependency-tracking do not reject slow dependency extractors + +Some influential environment variables: + CXX C++ compiler command + CXXFLAGS C++ compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CXXCPP C++ preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +configure +generated by GNU Autoconf 2.61 + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by $as_me, which was +generated by GNU Autoconf 2.61. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args '$ac_arg'" + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 +echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------------- ## +## File substitutions. ## +## ------------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -n "$CONFIG_SITE"; then + set x "$CONFIG_SITE" +elif test "x$prefix" != xNONE; then + set x "$prefix/share/config.site" "$prefix/etc/config.site" +else + set x "$ac_default_prefix/share/config.site" \ + "$ac_default_prefix/etc/config.site" +fi +shift +for ac_site_file +do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + + + + + + + + + + + + + + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +am__api_version="1.9" +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5 +echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;} + { (exit 1); exit 1; }; } +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +{ echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6; } +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done +IFS=$as_save_IFS + + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +{ echo "$as_me:$LINENO: checking whether build environment is sane" >&5 +echo $ECHO_N "checking whether build environment is sane... $ECHO_C" >&6; } +# Just in case +sleep 1 +echo timestamp > conftest.file +# Do `set' in a subshell so we don't clobber the current shell's +# arguments. Must try -L first in case configure is actually a +# symlink; some systems play weird games with the mod time of symlinks +# (eg FreeBSD returns the mod time of the symlink's containing +# directory). +if ( + set X `ls -Lt $srcdir/configure conftest.file 2> /dev/null` + if test "$*" = "X"; then + # -L didn't work. + set X `ls -t $srcdir/configure conftest.file` + fi + rm -f conftest.file + if test "$*" != "X $srcdir/configure conftest.file" \ + && test "$*" != "X conftest.file $srcdir/configure"; then + + # If neither matched, then we have a broken ls. This can happen + # if, for instance, CONFIG_SHELL is bash and it inherits a + # broken ls alias from the environment. This has actually + # happened. Such a system could not be considered "sane". + { { echo "$as_me:$LINENO: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&5 +echo "$as_me: error: ls -t appears to fail. Make sure there is not a broken +alias in your environment" >&2;} + { (exit 1); exit 1; }; } + fi + + test "$2" = conftest.file + ) +then + # Ok. + : +else + { { echo "$as_me:$LINENO: error: newly created file is older than distributed files! +Check your system clock" >&5 +echo "$as_me: error: newly created file is older than distributed files! +Check your system clock" >&2;} + { (exit 1); exit 1; }; } +fi +{ echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } +test "$program_prefix" != NONE && + program_transform_name="s&^&$program_prefix&;$program_transform_name" +# Use a double $ so make ignores it. +test "$program_suffix" != NONE && + program_transform_name="s&\$&$program_suffix&;$program_transform_name" +# Double any \ or $. echo might interpret backslashes. +# By default was `s,x,x', remove it if useless. +cat <<\_ACEOF >conftest.sed +s/[\\$]/&&/g;s/;s,x,x,$// +_ACEOF +program_transform_name=`echo $program_transform_name | sed -f conftest.sed` +rm -f conftest.sed + +# expand $ac_aux_dir to an absolute path +am_aux_dir=`cd $ac_aux_dir && pwd` + +test x"${MISSING+set}" = xset || MISSING="\${SHELL} $am_aux_dir/missing" +# Use eval to expand $SHELL +if eval "$MISSING --run true"; then + am_missing_run="$MISSING --run " +else + am_missing_run= + { echo "$as_me:$LINENO: WARNING: \`missing' script is too old or missing" >&5 +echo "$as_me: WARNING: \`missing' script is too old or missing" >&2;} +fi + +if mkdir -p --version . >/dev/null 2>&1 && test ! -d ./--version; then + # We used to keeping the `.' as first argument, in order to + # allow $(mkdir_p) to be used without argument. As in + # $(mkdir_p) $(somedir) + # where $(somedir) is conditionally defined. However this is wrong + # for two reasons: + # 1. if the package is installed by a user who cannot write `.' + # make install will fail, + # 2. the above comment should most certainly read + # $(mkdir_p) $(DESTDIR)$(somedir) + # so it does not work when $(somedir) is undefined and + # $(DESTDIR) is not. + # To support the latter case, we have to write + # test -z "$(somedir)" || $(mkdir_p) $(DESTDIR)$(somedir), + # so the `.' trick is pointless. + mkdir_p='mkdir -p --' +else + # On NextStep and OpenStep, the `mkdir' command does not + # recognize any option. It will interpret all options as + # directories to create, and then abort because `.' already + # exists. + for d in ./-p ./--version; + do + test -d $d && rmdir $d + done + # $(mkinstalldirs) is defined by Automake if mkinstalldirs exists. + if test -f "$ac_aux_dir/mkinstalldirs"; then + mkdir_p='$(mkinstalldirs)' + else + mkdir_p='$(install_sh) -d' + fi +fi + +for ac_prog in gawk mawk nawk awk +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_AWK+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$AWK"; then + ac_cv_prog_AWK="$AWK" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AWK="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +AWK=$ac_cv_prog_AWK +if test -n "$AWK"; then + { echo "$as_me:$LINENO: result: $AWK" >&5 +echo "${ECHO_T}$AWK" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$AWK" && break +done + +{ echo "$as_me:$LINENO: checking whether ${MAKE-make} sets \$(MAKE)" >&5 +echo $ECHO_N "checking whether ${MAKE-make} sets \$(MAKE)... $ECHO_C" >&6; } +set x ${MAKE-make}; ac_make=`echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'` +if { as_var=ac_cv_prog_make_${ac_make}_set; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.make <<\_ACEOF +SHELL = /bin/sh +all: + @echo '@@@%%%=$(MAKE)=@@@%%%' +_ACEOF +# GNU make sometimes prints "make[1]: Entering...", which would confuse us. +case `${MAKE-make} -f conftest.make 2>/dev/null` in + *@@@%%%=?*=@@@%%%*) + eval ac_cv_prog_make_${ac_make}_set=yes;; + *) + eval ac_cv_prog_make_${ac_make}_set=no;; +esac +rm -f conftest.make +fi +if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + SET_MAKE= +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + SET_MAKE="MAKE=${MAKE-make}" +fi + +rm -rf .tst 2>/dev/null +mkdir .tst 2>/dev/null +if test -d .tst; then + am__leading_dot=. +else + am__leading_dot=_ +fi +rmdir .tst 2>/dev/null + +# test to see if srcdir already configured +if test "`cd $srcdir && pwd`" != "`pwd`" && + test -f $srcdir/config.status; then + { { echo "$as_me:$LINENO: error: source directory already configured; run \"make distclean\" there first" >&5 +echo "$as_me: error: source directory already configured; run \"make distclean\" there first" >&2;} + { (exit 1); exit 1; }; } +fi + +# test whether we have cygpath +if test -z "$CYGPATH_W"; then + if (cygpath --version) >/dev/null 2>/dev/null; then + CYGPATH_W='cygpath -w' + else + CYGPATH_W=echo + fi +fi + + +# Define the identity of the package. + PACKAGE=resid + VERSION=0.16vice + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE "$PACKAGE" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define VERSION "$VERSION" +_ACEOF + +# Some tools Automake needs. + +ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"} + + +AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"} + + +AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"} + + +AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"} + + +MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"} + +install_sh=${install_sh-"$am_aux_dir/install-sh"} + +# Installed binaries are usually stripped using `strip' when the user +# run `make install-strip'. However `strip' might not be the right +# tool to use in cross-compilation environments, therefore Automake +# will honor the `STRIP' environment variable to overrule this program. +if test "$cross_compiling" != no; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args. +set dummy ${ac_tool_prefix}strip; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$STRIP"; then + ac_cv_prog_STRIP="$STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_STRIP="${ac_tool_prefix}strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +STRIP=$ac_cv_prog_STRIP +if test -n "$STRIP"; then + { echo "$as_me:$LINENO: result: $STRIP" >&5 +echo "${ECHO_T}$STRIP" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_STRIP"; then + ac_ct_STRIP=$STRIP + # Extract the first word of "strip", so it can be a program name with args. +set dummy strip; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_STRIP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_STRIP"; then + ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_STRIP="strip" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP +if test -n "$ac_ct_STRIP"; then + { echo "$as_me:$LINENO: result: $ac_ct_STRIP" >&5 +echo "${ECHO_T}$ac_ct_STRIP" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_STRIP" = x; then + STRIP=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + STRIP=$ac_ct_STRIP + fi +else + STRIP="$ac_cv_prog_STRIP" +fi + +fi +INSTALL_STRIP_PROGRAM="\${SHELL} \$(install_sh) -c -s" + +# We need awk for the "check" target. The system "awk" is bad on +# some platforms. +# Always define AMTAR for backward compatibility. + +AMTAR=${AMTAR-"${am_missing_run}tar"} + +am__tar='${AMTAR} chof - "$$tardir"'; am__untar='${AMTAR} xf -' + + + + + +LTVERSION=5:0:0 + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + +# Check whether --enable-inline was given. +if test "${enable_inline+set}" = set; then + enableval=$enable_inline; +fi + +# Check whether --enable-sse was given. +if test "${enable_sse+set}" = set; then + enableval=$enable_sse; +fi + + +if test "$enable_inline" != no; then + RESID_INLINE=inline +else + RESID_INLINE= +fi + + + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -z "$CXX"; then + if test -n "$CCC"; then + CXX=$CCC + else + if test -n "$ac_tool_prefix"; then + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + { echo "$as_me:$LINENO: result: $CXX" >&5 +echo "${ECHO_T}$CXX" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + { echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5 +echo "${ECHO_T}$ac_ct_CXX" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$ac_ct_CXX" && break +done + + if test "x$ac_ct_CXX" = x; then + CXX="g++" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + CXX=$ac_ct_CXX + fi +fi + + fi +fi +# Provide some information about the compiler. +echo "$as_me:$LINENO: checking for C++ compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (ac_try="$ac_compiler --version >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler --version >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -v >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -v >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -V >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -V >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ echo "$as_me:$LINENO: checking for C++ compiler default output file name" >&5 +echo $ECHO_N "checking for C++ compiler default output file name... $ECHO_C" >&6; } +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +# +# List of possible output files, starting from the most likely. +# The algorithm is not robust to junk in `.', hence go to wildcards (a.*) +# only as a last resort. b.out is created by i960 compilers. +ac_files='a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out' +# +# The IRIX 6 linker writes into existing files which may not be +# executable, retaining their permissions. Remove them first so a +# subsequent execution test works. +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { (ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi + +{ echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6; } +if test -z "$ac_file"; then + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C++ compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C++ compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext + +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ echo "$as_me:$LINENO: checking whether the C++ compiler works" >&5 +echo $ECHO_N "checking whether the C++ compiler works... $ECHO_C" >&6; } +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C++ compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C++ compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +{ echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6; } +{ echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6; } + +{ echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6; } +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +{ echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +{ echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6; } +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C++ compiler... $ECHO_C" >&6; } +if test "${ac_cv_cxx_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_compiler_gnu=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6; } +GXX=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +{ echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5 +echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6; } +if test "${ac_cv_prog_cxx_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_save_cxx_werror_flag=$ac_cxx_werror_flag + ac_cxx_werror_flag=yes + ac_cv_prog_cxx_g=no + CXXFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cxx_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + CXXFLAGS="" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cxx_werror_flag=$ac_save_cxx_werror_flag + CXXFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cxx_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_cxx_werror_flag=$ac_save_cxx_werror_flag +fi +{ echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cxx_g" >&6; } +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +DEPDIR="${am__leading_dot}deps" + +ac_config_commands="$ac_config_commands depfiles" + + +am_make=${MAKE-make} +cat > confinc << 'END' +am__doit: + @echo done +.PHONY: am__doit +END +# If we don't find an include directive, just comment out the code. +{ echo "$as_me:$LINENO: checking for style of include used by $am_make" >&5 +echo $ECHO_N "checking for style of include used by $am_make... $ECHO_C" >&6; } +am__include="#" +am__quote= +_am_result=none +# First try GNU make style include. +echo "include confinc" > confmf +# We grep out `Entering directory' and `Leaving directory' +# messages which can occur if `w' ends up in MAKEFLAGS. +# In particular we don't look at `^make:' because GNU make might +# be invoked under some other name (usually "gmake"), in which +# case it prints its new name instead of `make'. +if test "`$am_make -s -f confmf 2> /dev/null | grep -v 'ing directory'`" = "done"; then + am__include=include + am__quote= + _am_result=GNU +fi +# Now try BSD make style include. +if test "$am__include" = "#"; then + echo '.include "confinc"' > confmf + if test "`$am_make -s -f confmf 2> /dev/null`" = "done"; then + am__include=.include + am__quote="\"" + _am_result=BSD + fi +fi + + +{ echo "$as_me:$LINENO: result: $_am_result" >&5 +echo "${ECHO_T}$_am_result" >&6; } +rm -f confinc confmf + +# Check whether --enable-dependency-tracking was given. +if test "${enable_dependency_tracking+set}" = set; then + enableval=$enable_dependency_tracking; +fi + +if test "x$enable_dependency_tracking" != xno; then + am_depcomp="$ac_aux_dir/depcomp" + AMDEPBACKSLASH='\' +fi + + +if test "x$enable_dependency_tracking" != xno; then + AMDEP_TRUE= + AMDEP_FALSE='#' +else + AMDEP_TRUE='#' + AMDEP_FALSE= +fi + + + + +depcc="$CXX" am_compiler_list= + +{ echo "$as_me:$LINENO: checking dependency style of $depcc" >&5 +echo $ECHO_N "checking dependency style of $depcc... $ECHO_C" >&6; } +if test "${am_cv_CXX_dependencies_compiler_type+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then + # We make a subdir and do the tests there. Otherwise we can end up + # making bogus files that we don't know about and never remove. For + # instance it was reported that on HP-UX the gcc test will end up + # making a dummy file named `D' -- because `-MD' means `put the output + # in D'. + mkdir conftest.dir + # Copy depcomp to subdir because otherwise we won't find it if we're + # using a relative directory. + cp "$am_depcomp" conftest.dir + cd conftest.dir + # We will build objects and dependencies in a subdirectory because + # it helps to detect inapplicable dependency modes. For instance + # both Tru64's cc and ICC support -MD to output dependencies as a + # side effect of compilation, but ICC will put the dependencies in + # the current directory while Tru64 will put them in the object + # directory. + mkdir sub + + am_cv_CXX_dependencies_compiler_type=none + if test "$am_compiler_list" = ""; then + am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp` + fi + for depmode in $am_compiler_list; do + # Setup a source with many dependencies, because some compilers + # like to wrap large dependency lists on column 80 (with \), and + # we should not choose a depcomp mode which is confused by this. + # + # We need to recreate these files for each test, as the compiler may + # overwrite some of them when testing with obscure command lines. + # This happens at least with the AIX C compiler. + : > sub/conftest.c + for i in 1 2 3 4 5 6; do + echo '#include "conftst'$i'.h"' >> sub/conftest.c + # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with + # Solaris 8's {/usr,}/bin/sh. + touch sub/conftst$i.h + done + echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf + + case $depmode in + nosideeffect) + # after this tag, mechanisms are not by side-effect, so they'll + # only be used when explicitly requested + if test "x$enable_dependency_tracking" = xyes; then + continue + else + break + fi + ;; + none) break ;; + esac + # We check with `-c' and `-o' for the sake of the "dashmstdout" + # mode. It turns out that the SunPro C++ compiler does not properly + # handle `-M -o', and we need to detect this. + if depmode=$depmode \ + source=sub/conftest.c object=sub/conftest.${OBJEXT-o} \ + depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \ + $SHELL ./depcomp $depcc -c -o sub/conftest.${OBJEXT-o} sub/conftest.c \ + >/dev/null 2>conftest.err && + grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 && + grep sub/conftest.${OBJEXT-o} sub/conftest.Po > /dev/null 2>&1 && + ${MAKE-make} -s -f confmf > /dev/null 2>&1; then + # icc doesn't choke on unknown options, it will just issue warnings + # or remarks (even with -Werror). So we grep stderr for any message + # that says an option was ignored or not supported. + # When given -MP, icc 7.0 and 7.1 complain thusly: + # icc: Command line warning: ignoring option '-M'; no argument required + # The diagnosis changed in icc 8.0: + # icc: Command line remark: option '-MP' not supported + if (grep 'ignoring option' conftest.err || + grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else + am_cv_CXX_dependencies_compiler_type=$depmode + break + fi + fi + done + + cd .. + rm -rf conftest.dir +else + am_cv_CXX_dependencies_compiler_type=none +fi + +fi +{ echo "$as_me:$LINENO: result: $am_cv_CXX_dependencies_compiler_type" >&5 +echo "${ECHO_T}$am_cv_CXX_dependencies_compiler_type" >&6; } +CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type + + + +if + test "x$enable_dependency_tracking" != xno \ + && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then + am__fastdepCXX_TRUE= + am__fastdepCXX_FALSE='#' +else + am__fastdepCXX_TRUE='#' + am__fastdepCXX_FALSE= +fi + + + +if test x"$enable_sse" != "xno"; then + if test "$GXX" = yes; then + if test "$ac_test_CXXFLAGS" != set; then + CXXFLAGS="-g -Wall -O2 -msse" + { echo "$as_me:$LINENO: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5 +echo $ECHO_N "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works... $ECHO_C" >&6; } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +int test; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + MSSE="-msse" + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + MSSE="" + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi + fi +else + MSSE="" +fi + +if test "$GXX" = yes; then + if test "$ac_test_CXXFLAGS" != set; then + CXXFLAGS="-g -Wall -O2 $MSSE -fno-exceptions" + { echo "$as_me:$LINENO: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5 +echo $ECHO_N "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works... $ECHO_C" >&6; } + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +int test; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + NO_EXCEPTIONS="-fno-exceptions" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + NO_EXCEPTIONS="" + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi +fi + +if test "$GXX" = yes; then + if test "$ac_test_CXXFLAGS" != set; then + CXXFLAGS="-g -Wall -O2 $MSSE -fno-exceptions $NO_EXCEPTIONS -fno-pic" + { echo "$as_me:$LINENO: checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works" >&5 +echo $ECHO_N "checking whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works... $ECHO_C" >&6; } + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +int test; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + NO_PIC="-fno-pic" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + NO_PIC="" + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + fi +fi + +CXXFLAGS="-g -Wall -O2 $MSSE $NO_EXCEPTIONS $NO_PIC" +if test x"$MSSE" = "x-msse"; then + { echo "$as_me:$LINENO: checking if the xmmintrin.h include can be used" >&5 +echo $ECHO_N "checking if the xmmintrin.h include can be used... $ECHO_C" >&6; } + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +int +main () +{ +int test; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + MSSE="" + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + CXXFLAGS="-g -Wall -O2 $NO_EXCEPTIONS $NO_PIC" +fi + +# Extract the first word of "ar", so it can be a program name with args. +set dummy ar; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_AR+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$AR"; then + ac_cv_prog_AR="$AR" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_AR="ar" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + + test -z "$ac_cv_prog_AR" && ac_cv_prog_AR="ar" +fi +fi +AR=$ac_cv_prog_AR +if test -n "$AR"; then + { echo "$as_me:$LINENO: result: $AR" >&5 +echo "${ECHO_T}$AR" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { echo "$as_me:$LINENO: result: $RANLIB" >&5 +echo "${ECHO_T}$RANLIB" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 +echo "${ECHO_T}$ac_ct_RANLIB" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + +# Extract the first word of "perl", so it can be a program name with args. +set dummy perl; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_path_PERL+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + case $PERL in + [\\/]* | ?:[\\/]*) + ac_cv_path_PERL="$PERL" # Let the user override the test with a path. + ;; + *) + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_path_PERL="$as_dir/$ac_word$ac_exec_ext" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + + ;; +esac +fi +PERL=$ac_cv_path_PERL +if test -n "$PERL"; then + { echo "$as_me:$LINENO: result: $PERL" >&5 +echo "${ECHO_T}$PERL" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + + + + + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +{ echo "$as_me:$LINENO: checking how to run the C++ preprocessor" >&5 +echo $ECHO_N "checking how to run the C++ preprocessor... $ECHO_C" >&6; } +if test -z "$CXXCPP"; then + if test "${ac_cv_prog_CXXCPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CXXCPP needs to be expanded + for CXXCPP in "$CXX -E" "/lib/cpp" + do + ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CXXCPP=$CXXCPP + +fi + CXXCPP=$ac_cv_prog_CXXCPP +else + ac_cv_prog_CXXCPP=$CXXCPP +fi +{ echo "$as_me:$LINENO: result: $CXXCPP" >&5 +echo "${ECHO_T}$CXXCPP" >&6; } +ac_preproc_ok=false +for ac_cxx_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C++ preprocessor \"$CXXCPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C++ preprocessor \"$CXXCPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=cpp +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu + + +{ echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5 +echo $ECHO_N "checking for grep that handles long lines and -e... $ECHO_C" >&6; } +if test "${ac_cv_path_GREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Extract the first word of "grep ggrep" to use in msg output +if test -z "$GREP"; then +set dummy grep ggrep; ac_prog_name=$2 +if test "${ac_cv_path_GREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_path_GREP_found=false +# Loop through the user's path and test for each of PROGNAME-LIST +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue + # Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + ac_count=`expr $ac_count + 1` + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + + $ac_path_GREP_found && break 3 + done +done + +done +IFS=$as_save_IFS + + +fi + +GREP="$ac_cv_path_GREP" +if test -z "$GREP"; then + { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} + { (exit 1); exit 1; }; } +fi + +else + ac_cv_path_GREP=$GREP +fi + + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5 +echo "${ECHO_T}$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6; } +if test "${ac_cv_path_EGREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + # Extract the first word of "egrep" to use in msg output +if test -z "$EGREP"; then +set dummy egrep; ac_prog_name=$2 +if test "${ac_cv_path_EGREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_path_EGREP_found=false +# Loop through the user's path and test for each of PROGNAME-LIST +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue + # Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + ac_count=`expr $ac_count + 1` + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + + $ac_path_EGREP_found && break 3 + done +done + +done +IFS=$as_save_IFS + + +fi + +EGREP="$ac_cv_path_EGREP" +if test -z "$EGREP"; then + { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} + { (exit 1); exit 1; }; } +fi + +else + ac_cv_path_EGREP=$EGREP +fi + + + fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5 +echo "${ECHO_T}$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6; } +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_header_stdc=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + +fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_Header=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +{ echo "$as_me:$LINENO: checking for int" >&5 +echo $ECHO_N "checking for int... $ECHO_C" >&6; } +if test "${ac_cv_type_int+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +typedef int ac__type_new_; +int +main () +{ +if ((ac__type_new_ *) 0) + return 0; +if (sizeof (ac__type_new_)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_type_int=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_type_int=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_type_int" >&5 +echo "${ECHO_T}$ac_cv_type_int" >&6; } + +# The cast to long int works around a bug in the HP C Compiler +# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects +# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'. +# This bug is HP SR number 8606223364. +{ echo "$as_me:$LINENO: checking size of int" >&5 +echo $ECHO_N "checking size of int... $ECHO_C" >&6; } +if test "${ac_cv_sizeof_int+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test "$cross_compiling" = yes; then + # Depending upon the size, compute the lo and hi bounds. +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef int ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_lo=0 ac_mid=0 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef int ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=$ac_mid; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo=`expr $ac_mid + 1` + if test $ac_lo -le $ac_mid; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid + 1` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef int ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) < 0)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=-1 ac_mid=-1 + while :; do + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef int ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) >= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_lo=$ac_mid; break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_hi=`expr '(' $ac_mid ')' - 1` + if test $ac_mid -le $ac_hi; then + ac_lo= ac_hi= + break + fi + ac_mid=`expr 2 '*' $ac_mid` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo= ac_hi= +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +# Binary search between lo and hi bounds. +while test "x$ac_lo" != "x$ac_hi"; do + ac_mid=`expr '(' $ac_hi - $ac_lo ')' / 2 + $ac_lo` + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef int ac__type_sizeof_; +int +main () +{ +static int test_array [1 - 2 * !(((long int) (sizeof (ac__type_sizeof_))) <= $ac_mid)]; +test_array [0] = 0 + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_hi=$ac_mid +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_lo=`expr '(' $ac_mid ')' + 1` +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +done +case $ac_lo in +?*) ac_cv_sizeof_int=$ac_lo;; +'') if test "$ac_cv_type_int" = yes; then + { { echo "$as_me:$LINENO: error: cannot compute sizeof (int) +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute sizeof (int) +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } + else + ac_cv_sizeof_int=0 + fi ;; +esac +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + typedef int ac__type_sizeof_; +static long int longval () { return (long int) (sizeof (ac__type_sizeof_)); } +static unsigned long int ulongval () { return (long int) (sizeof (ac__type_sizeof_)); } +#include +#include +int +main () +{ + + FILE *f = fopen ("conftest.val", "w"); + if (! f) + return 1; + if (((long int) (sizeof (ac__type_sizeof_))) < 0) + { + long int i = longval (); + if (i != ((long int) (sizeof (ac__type_sizeof_)))) + return 1; + fprintf (f, "%ld\n", i); + } + else + { + unsigned long int i = ulongval (); + if (i != ((long int) (sizeof (ac__type_sizeof_)))) + return 1; + fprintf (f, "%lu\n", i); + } + return ferror (f) || fclose (f) != 0; + + ; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_sizeof_int=`cat conftest.val` +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +if test "$ac_cv_type_int" = yes; then + { { echo "$as_me:$LINENO: error: cannot compute sizeof (int) +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute sizeof (int) +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } + else + ac_cv_sizeof_int=0 + fi +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi +rm -f conftest.val +fi +{ echo "$as_me:$LINENO: result: $ac_cv_sizeof_int" >&5 +echo "${ECHO_T}$ac_cv_sizeof_int" >&6; } + + + +cat >>confdefs.h <<_ACEOF +#define SIZEOF_INT $ac_cv_sizeof_int +_ACEOF + + + +if test $ac_cv_sizeof_int -lt 4; then + { { echo "$as_me:$LINENO: error: only 32 bit or better CPUs are supported" >&5 +echo "$as_me: error: only 32 bit or better CPUs are supported" >&2;} + { (exit 1); exit 1; }; } +fi + +{ echo "$as_me:$LINENO: checking for working bool" >&5 +echo $ECHO_N "checking for working bool... $ECHO_C" >&6; } +if test "${ac_cv_cxx_bool+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + +bool flag; + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_cxx_bool=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_cxx_bool=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_cxx_bool" >&5 +echo "${ECHO_T}$ac_cv_cxx_bool" >&6; } + +if test $ac_cv_cxx_bool = no; then + RESID_HAVE_BOOL=0 +else + RESID_HAVE_BOOL=1 +fi + +if test x"$MSSE" = "x-msse"; then + RESID_USE_SSE=1 + + +if true; then + USE_SSE_TRUE= + USE_SSE_FALSE='#' +else + USE_SSE_TRUE='#' + USE_SSE_FALSE= +fi + +else + RESID_USE_SSE=0 + + +if false; then + USE_SSE_TRUE= + USE_SSE_FALSE='#' +else + USE_SSE_TRUE='#' + USE_SSE_FALSE= +fi + +fi + + + + + + + +for ac_func in logf expf +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +{ echo "$as_me:$LINENO: checking if the logf prototype is present" >&5 +echo $ECHO_N "checking if the logf prototype is present... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + #include +int +main () +{ +printf("%d",logf); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + HAVE_LOGF_PROTOTYPE=1 + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + HAVE_LOGF_PROTOTYPE=0 + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +{ echo "$as_me:$LINENO: checking if the expf prototype is present" >&5 +echo $ECHO_N "checking if the expf prototype is present... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + #include +int +main () +{ +printf("%d",expf); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_cxx_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + { echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + HAVE_EXPF_PROTOTYPE=1 + +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } + HAVE_EXPF_PROTOTYPE=0 + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + + + + +ac_config_files="$ac_config_files Makefile siddefs-fp.h" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 +echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + test "x$cache_file" != "x/dev/null" && + { echo "$as_me:$LINENO: updating cache $cache_file" >&5 +echo "$as_me: updating cache $cache_file" >&6;} + cat confcache >$cache_file + else + { echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5 +echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +# Transform confdefs.h into DEFS. +# Protect against shell expansion while executing Makefile rules. +# Protect against Makefile macro expansion. +# +# If the first sed substitution is executed (which looks for macros that +# take arguments), then branch to the quote section. Otherwise, +# look for a macro that doesn't take arguments. +ac_script=' +t clear +:clear +s/^[ ]*#[ ]*define[ ][ ]*\([^ (][^ (]*([^)]*)\)[ ]*\(.*\)/-D\1=\2/g +t quote +s/^[ ]*#[ ]*define[ ][ ]*\([^ ][^ ]*\)[ ]*\(.*\)/-D\1=\2/g +t quote +b any +:quote +s/[ `~#$^&*(){}\\|;'\''"<>?]/\\&/g +s/\[/\\&/g +s/\]/\\&/g +s/\$/$$/g +H +:any +${ + g + s/^\n// + s/\n/ /g + p +} +' +DEFS=`sed -n "$ac_script" confdefs.h` + + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + +if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"AMDEP\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"am__fastdepCXX\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${USE_SSE_TRUE}" && test -z "${USE_SSE_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"USE_SSE\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"USE_SSE\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi +if test -z "${USE_SSE_TRUE}" && test -z "${USE_SSE_FALSE}"; then + { { echo "$as_me:$LINENO: error: conditional \"USE_SSE\" was never defined. +Usually this means the macro was only invoked conditionally." >&5 +echo "$as_me: error: conditional \"USE_SSE\" was never defined. +Usually this means the macro was only invoked conditionally." >&2;} + { (exit 1); exit 1; }; } +fi + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +as_nl=' +' +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir +fi +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 + +# Save the log message, to keep $[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by $as_me, which was +generated by GNU Autoconf 2.61. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +# Files that config.status was made for. +config_files="$ac_config_files" +config_commands="$ac_config_commands" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + +Configuration files: +$config_files + +Configuration commands: +$config_commands + +Report bugs to ." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +config.status +configured by $0, generated by GNU Autoconf 2.61, + with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2006 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + echo "$ac_cs_version"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --he | --h | --help | --hel | -h ) + echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running CONFIG_SHELL=$SHELL $SHELL $0 "$ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + CONFIG_SHELL=$SHELL + export CONFIG_SHELL + exec $SHELL "$0"$ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +# +# INIT-COMMANDS +# +AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + "siddefs-fp.h") CONFIG_FILES="$CONFIG_FILES siddefs-fp.h" ;; + + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +# +# Set up the sed scripts for CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "$CONFIG_FILES"; then + +_ACEOF + + + +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + cat >conf$$subs.sed <<_ACEOF +SHELL!$SHELL$ac_delim +PATH_SEPARATOR!$PATH_SEPARATOR$ac_delim +PACKAGE_NAME!$PACKAGE_NAME$ac_delim +PACKAGE_TARNAME!$PACKAGE_TARNAME$ac_delim +PACKAGE_VERSION!$PACKAGE_VERSION$ac_delim +PACKAGE_STRING!$PACKAGE_STRING$ac_delim +PACKAGE_BUGREPORT!$PACKAGE_BUGREPORT$ac_delim +exec_prefix!$exec_prefix$ac_delim +prefix!$prefix$ac_delim +program_transform_name!$program_transform_name$ac_delim +bindir!$bindir$ac_delim +sbindir!$sbindir$ac_delim +libexecdir!$libexecdir$ac_delim +datarootdir!$datarootdir$ac_delim +datadir!$datadir$ac_delim +sysconfdir!$sysconfdir$ac_delim +sharedstatedir!$sharedstatedir$ac_delim +localstatedir!$localstatedir$ac_delim +includedir!$includedir$ac_delim +oldincludedir!$oldincludedir$ac_delim +docdir!$docdir$ac_delim +infodir!$infodir$ac_delim +htmldir!$htmldir$ac_delim +dvidir!$dvidir$ac_delim +pdfdir!$pdfdir$ac_delim +psdir!$psdir$ac_delim +libdir!$libdir$ac_delim +localedir!$localedir$ac_delim +mandir!$mandir$ac_delim +DEFS!$DEFS$ac_delim +ECHO_C!$ECHO_C$ac_delim +ECHO_N!$ECHO_N$ac_delim +ECHO_T!$ECHO_T$ac_delim +LIBS!$LIBS$ac_delim +build_alias!$build_alias$ac_delim +host_alias!$host_alias$ac_delim +target_alias!$target_alias$ac_delim +INSTALL_PROGRAM!$INSTALL_PROGRAM$ac_delim +INSTALL_SCRIPT!$INSTALL_SCRIPT$ac_delim +INSTALL_DATA!$INSTALL_DATA$ac_delim +CYGPATH_W!$CYGPATH_W$ac_delim +PACKAGE!$PACKAGE$ac_delim +VERSION!$VERSION$ac_delim +ACLOCAL!$ACLOCAL$ac_delim +AUTOCONF!$AUTOCONF$ac_delim +AUTOMAKE!$AUTOMAKE$ac_delim +AUTOHEADER!$AUTOHEADER$ac_delim +MAKEINFO!$MAKEINFO$ac_delim +install_sh!$install_sh$ac_delim +STRIP!$STRIP$ac_delim +INSTALL_STRIP_PROGRAM!$INSTALL_STRIP_PROGRAM$ac_delim +mkdir_p!$mkdir_p$ac_delim +AWK!$AWK$ac_delim +SET_MAKE!$SET_MAKE$ac_delim +am__leading_dot!$am__leading_dot$ac_delim +AMTAR!$AMTAR$ac_delim +am__tar!$am__tar$ac_delim +am__untar!$am__untar$ac_delim +RESID_INLINE!$RESID_INLINE$ac_delim +CXX!$CXX$ac_delim +CXXFLAGS!$CXXFLAGS$ac_delim +LDFLAGS!$LDFLAGS$ac_delim +CPPFLAGS!$CPPFLAGS$ac_delim +ac_ct_CXX!$ac_ct_CXX$ac_delim +EXEEXT!$EXEEXT$ac_delim +OBJEXT!$OBJEXT$ac_delim +DEPDIR!$DEPDIR$ac_delim +am__include!$am__include$ac_delim +am__quote!$am__quote$ac_delim +AMDEP_TRUE!$AMDEP_TRUE$ac_delim +AMDEP_FALSE!$AMDEP_FALSE$ac_delim +AMDEPBACKSLASH!$AMDEPBACKSLASH$ac_delim +CXXDEPMODE!$CXXDEPMODE$ac_delim +am__fastdepCXX_TRUE!$am__fastdepCXX_TRUE$ac_delim +am__fastdepCXX_FALSE!$am__fastdepCXX_FALSE$ac_delim +AR!$AR$ac_delim +RANLIB!$RANLIB$ac_delim +PERL!$PERL$ac_delim +CXXCPP!$CXXCPP$ac_delim +GREP!$GREP$ac_delim +EGREP!$EGREP$ac_delim +USE_SSE_TRUE!$USE_SSE_TRUE$ac_delim +USE_SSE_FALSE!$USE_SSE_FALSE$ac_delim +RESID_HAVE_BOOL!$RESID_HAVE_BOOL$ac_delim +RESID_USE_SSE!$RESID_USE_SSE$ac_delim +HAVE_LOGF_PROTOTYPE!$HAVE_LOGF_PROTOTYPE$ac_delim +HAVE_EXPF_PROTOTYPE!$HAVE_EXPF_PROTOTYPE$ac_delim +LIBOBJS!$LIBOBJS$ac_delim +LTLIBOBJS!$LTLIBOBJS$ac_delim +_ACEOF + + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 89; then + break + elif $ac_last_try; then + { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed` +if test -n "$ac_eof"; then + ac_eof=`echo "$ac_eof" | sort -nru | sed 1q` + ac_eof=`expr $ac_eof + 1` +fi + +cat >>$CONFIG_STATUS <<_ACEOF +cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b end +_ACEOF +sed ' +s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g +s/^/s,@/; s/!/@,|#_!!_#|/ +:n +t n +s/'"$ac_delim"'$/,g/; t +s/$/\\/; p +N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n +' >>$CONFIG_STATUS >$CONFIG_STATUS <<_ACEOF +:end +s/|#_!!_#|//g +CEOF$ac_eof +_ACEOF + + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/ +s/:*\${srcdir}:*/:/ +s/:*@srcdir@:*/:/ +s/^\([^=]*=[ ]*\):*/\1/ +s/:*$// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF +fi # test -n "$CONFIG_FILES" + + +for ac_tag in :F $CONFIG_FILES :C $CONFIG_COMMANDS +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5 +echo "$as_me: error: Invalid tag $ac_tag." >&2;} + { (exit 1); exit 1; }; };; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5 +echo "$as_me: error: cannot find input file: $ac_f" >&2;} + { (exit 1); exit 1; }; };; + esac + ac_file_inputs="$ac_file_inputs $ac_f" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input="Generated from "`IFS=: + echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure." + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + fi + + case $ac_tag in + *:-:* | *:-) cat >"$tmp/stdin";; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { as_dir="$ac_dir" + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 +echo "$as_me: error: cannot create directory $as_dir" >&2;} + { (exit 1); exit 1; }; }; } + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= + +case `sed -n '/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p +' $ac_file_inputs` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s&@configure_input@&$configure_input&;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +$ac_datarootdir_hack +" $ac_file_inputs | sed -f "$tmp/subs-1.sed" >$tmp/out + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&5 +echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&2;} + + rm -f "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out"; rm -f "$tmp/out";; + *) rm -f "$ac_file"; mv "$tmp/out" $ac_file;; + esac + ;; + + + :C) { echo "$as_me:$LINENO: executing $ac_file commands" >&5 +echo "$as_me: executing $ac_file commands" >&6;} + ;; + esac + + + case $ac_file$ac_mode in + "depfiles":C) test x"$AMDEP_TRUE" != x"" || for mf in $CONFIG_FILES; do + # Strip MF so we end up with the name of the file. + mf=`echo "$mf" | sed -e 's/:.*$//'` + # Check whether this is an Automake generated Makefile or not. + # We used to match only the files named `Makefile.in', but + # some people rename them; so instead we look at the file content. + # Grep'ing the first line is not enough: some people post-process + # each Makefile.in and add a new line on top of each file to say so. + # So let's grep whole file. + if grep '^#.*generated by automake' $mf > /dev/null 2>&1; then + dirpart=`$as_dirname -- "$mf" || +$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$mf" : 'X\(//\)[^/]' \| \ + X"$mf" : 'X\(//\)$' \| \ + X"$mf" : 'X\(/\)' \| . 2>/dev/null || +echo X"$mf" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + else + continue + fi + # Extract the definition of DEPDIR, am__include, and am__quote + # from the Makefile without running `make'. + DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"` + test -z "$DEPDIR" && continue + am__include=`sed -n 's/^am__include = //p' < "$mf"` + test -z "am__include" && continue + am__quote=`sed -n 's/^am__quote = //p' < "$mf"` + # When using ansi2knr, U may be empty or an underscore; expand it + U=`sed -n 's/^U = //p' < "$mf"` + # Find all dependency output files, they are included files with + # $(DEPDIR) in their names. We invoke sed twice because it is the + # simplest approach to changing $(DEPDIR) to its actual value in the + # expansion. + for file in `sed -n " + s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \ + sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g' -e 's/\$U/'"$U"'/g'`; do + # Make sure the directory exists. + test -f "$dirpart/$file" && continue + fdir=`$as_dirname -- "$file" || +$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$file" : 'X\(//\)[^/]' \| \ + X"$file" : 'X\(//\)$' \| \ + X"$file" : 'X\(/\)' \| . 2>/dev/null || +echo X"$file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { as_dir=$dirpart/$fdir + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 +echo "$as_me: error: cannot create directory $as_dir" >&2;} + { (exit 1); exit 1; }; }; } + # echo "creating $dirpart/$file" + echo '# dummy' > "$dirpart/$file" + done +done + ;; + + esac +done # for ac_tag + + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + diff --git a/src/resid-fp/configure.in b/src/resid-fp/configure.in new file mode 100644 index 000000000..f4b3b5731 --- /dev/null +++ b/src/resid-fp/configure.in @@ -0,0 +1,166 @@ +dnl Process this file with autoconf to produce a configure script. +AC_INIT(sid.h) + +dnl Use Automake +AM_INIT_AUTOMAKE(resid, 0.16vice) +LTVERSION=5:0:0 + +dnl Use C++ for tests. +AC_LANG_CPLUSPLUS + +dnl Enable inlining. +AC_ARG_ENABLE(inline, +[ --enable-inline enable inlining of functions [default=yes]]) +AC_ARG_ENABLE(sse, +[ --enable-sse enable the use of SSE [default=yes]]) + +if test "$enable_inline" != no; then + RESID_INLINE=inline +else + RESID_INLINE= +fi + +AC_SUBST(RESID_INLINE) + +dnl Checks for programs. +AC_PROG_CXX + +dnl Set CXXFLAGS for g++. Use -msse if supported. +if test x"$enable_sse" != "xno"; then + if test "$GXX" = yes; then + if test "$ac_test_CXXFLAGS" != set; then + CXXFLAGS="-g -Wall -O2 -msse" + AC_MSG_CHECKING([whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works]) + AC_TRY_COMPILE([], + [int test;], + [ AC_MSG_RESULT(yes) + MSSE="-msse" + ], + [ AC_MSG_RESULT(no) + MSSE="" + ]) + fi + fi +else + MSSE="" +fi + +dnl Set CXXFLAGS for g++. Use -fno-exceptions if supported. +if test "$GXX" = yes; then + if test "$ac_test_CXXFLAGS" != set; then + CXXFLAGS="-g -Wall -O2 $MSSE -fno-exceptions" + AC_MSG_CHECKING([whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works]) + AC_TRY_COMPILE([], + [int test;], + [ AC_MSG_RESULT(yes) + NO_EXCEPTIONS="-fno-exceptions" ], + [ AC_MSG_RESULT(no) + NO_EXCEPTIONS="" + ]) + fi +fi + +dnl Set CXXFLAGS for g++. Use -fno-pic if supported. +if test "$GXX" = yes; then + if test "$ac_test_CXXFLAGS" != set; then + CXXFLAGS="-g -Wall -O2 $MSSE -fno-exceptions $NO_EXCEPTIONS -fno-pic" + AC_MSG_CHECKING([whether the C++ compiler ($CXX $CXXFLAGS $LDFLAGS) works]) + AC_TRY_COMPILE([], + [int test;], + [ AC_MSG_RESULT(yes) + NO_PIC="-fno-pic" ], + [ AC_MSG_RESULT(no) + NO_PIC="" + ]) + fi +fi + +CXXFLAGS="-g -Wall -O2 $MSSE $NO_EXCEPTIONS $NO_PIC" +if test x"$MSSE" = "x-msse"; then + AC_MSG_CHECKING([if the xmmintrin.h include can be used]) + AC_TRY_COMPILE([#include ], + [int test;], + [ AC_MSG_RESULT(yes) + ], + [ AC_MSG_RESULT(no) + MSSE="" + ]) + CXXFLAGS="-g -Wall -O2 $NO_EXCEPTIONS $NO_PIC" +fi + +AC_CHECK_PROG(AR, ar, ar, ar) +AC_PROG_RANLIB +AC_PATH_PROG(PERL, perl) + +dnl Libtool + +dnl AC_DISABLE_SHARED +dnl AM_PROG_LIBTOOL +dnl AC_SUBST(LIBTOOL_DEPS) +dnl AC_SUBST(LTVERSION) + +dnl Checks for libraries. + +dnl Checks for header files. + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_CHECK_SIZEOF(int, 4) + +if test $ac_cv_sizeof_int -lt 4; then + AC_MSG_ERROR([only 32 bit or better CPUs are supported]) +fi + +AC_CACHE_CHECK([for working bool], ac_cv_cxx_bool, +[AC_TRY_COMPILE(, +[ +bool flag; +], +ac_cv_cxx_bool=yes, ac_cv_cxx_bool=no)]) + +if test $ac_cv_cxx_bool = no; then + RESID_HAVE_BOOL=0 +else + RESID_HAVE_BOOL=1 +fi + +if test x"$MSSE" = "x-msse"; then + RESID_USE_SSE=1 + AM_CONDITIONAL(USE_SSE, true) +else + RESID_USE_SSE=0 + AM_CONDITIONAL(USE_SSE, false) +fi + +AC_SUBST(RESID_HAVE_BOOL) +AC_SUBST(RESID_USE_SSE) + +dnl Checks for library functions. + +AC_CHECK_FUNCS(logf expf) + +AC_MSG_CHECKING([if the logf prototype is present]) +AC_TRY_COMPILE([#include + #include ], + [printf("%d",logf);], + [ AC_MSG_RESULT(yes) + HAVE_LOGF_PROTOTYPE=1 + ], + [ AC_MSG_RESULT(no) + HAVE_LOGF_PROTOTYPE=0 + ]) + +AC_MSG_CHECKING([if the expf prototype is present]) +AC_TRY_COMPILE([#include + #include ], + [printf("%d",expf);], + [ AC_MSG_RESULT(yes) + HAVE_EXPF_PROTOTYPE=1 + ], + [ AC_MSG_RESULT(no) + HAVE_EXPF_PROTOTYPE=0 + ]) + +AC_SUBST(HAVE_LOGF_PROTOTYPE) +AC_SUBST(HAVE_EXPF_PROTOTYPE) + +AC_OUTPUT(Makefile siddefs-fp.h) diff --git a/src/resid-fp/convolve-sse.cc b/src/resid-fp/convolve-sse.cc new file mode 100644 index 000000000..daf3979f2 --- /dev/null +++ b/src/resid-fp/convolve-sse.cc @@ -0,0 +1,76 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// --------------------------------------------------------------------------- +#include +#include "sid.h" + +#if (RESID_USE_SSE==1) + +#include + +float convolve_sse(const float *a, const float *b, int n) +{ + float out = 0.f; + __m128 out4 = { 0, 0, 0, 0 }; + + /* examine if we can use aligned loads on both pointers */ + int diff = (int) (a - b) & 0xf; + /* long cast is no-op for x86-32, but x86-64 gcc needs 64 bit intermediate + * to convince compiler we mean this. */ + unsigned int a_align = (unsigned int) (uintptr_t) a & 0xf; + + /* advance if necessary. We can't let n fall < 0, so no while (n --). */ + while (n > 0 && a_align != 0 && a_align != 16) { + out += (*(a ++)) * (*(b ++)); + --n; + a_align += 4; + } + + int n4 = n / 4; + if (diff == 0) { + for (int i = 0; i < n4; i ++) { + out4 = _mm_add_ps(out4, _mm_mul_ps(_mm_load_ps(a), _mm_load_ps(b))); + a += 4; + b += 4; + } + } else { + /* XXX loadu is 4x slower than load, at least. We could at 4x memory + * use prepare versions of b aligned for any a alignment. We could + * also issue aligned loads and shuffle the halves at each iteration. + * Initial results indicate only very small improvements. */ + for (int i = 0; i < n4; i ++) { + out4 = _mm_add_ps(out4, _mm_mul_ps(_mm_load_ps(a), _mm_loadu_ps(b))); + a += 4; + b += 4; + } + } + + out4 = _mm_add_ps(_mm_movehl_ps(out4, out4), out4); + out4 = _mm_add_ss(_mm_shuffle_ps(out4, out4, 1), out4); + float out_tmp; + _mm_store_ss(&out_tmp, out4); + out += out_tmp; + + n &= 3; + + while (n --) + out += (*(a ++)) * (*(b ++)); + + return out; +} +#endif diff --git a/src/resid-fp/convolve.cc b/src/resid-fp/convolve.cc new file mode 100644 index 000000000..b028ace86 --- /dev/null +++ b/src/resid-fp/convolve.cc @@ -0,0 +1,27 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// --------------------------------------------------------------------------- + +float convolve(const float *a, const float *b, int n) +{ + float out = 0.f; + while (n --) + out += (*(a ++)) * (*(b ++)); + return out; +} + diff --git a/src/resid-fp/envelope.cc b/src/resid-fp/envelope.cc new file mode 100644 index 000000000..5417adc43 --- /dev/null +++ b/src/resid-fp/envelope.cc @@ -0,0 +1,254 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// --------------------------------------------------------------------------- + +#define __ENVELOPE_CC__ +#include "envelope.h" + +// ---------------------------------------------------------------------------- +// Constructor. +// ---------------------------------------------------------------------------- +EnvelopeGeneratorFP::EnvelopeGeneratorFP() +{ + reset(); +} + +// ---------------------------------------------------------------------------- +// SID reset. +// ---------------------------------------------------------------------------- +void EnvelopeGeneratorFP::reset() +{ + envelope_counter = 0; + + attack = 0; + decay = 0; + sustain = 0; + release = 0; + + gate = 0; + + rate_counter = 0; + exponential_counter = 0; + exponential_counter_period = 1; + + state = RELEASE; + rate_period = rate_counter_period[release]; + hold_zero = true; +} + + +// Rate counter periods are calculated from the Envelope Rates table in +// the Programmer's Reference Guide. The rate counter period is the number of +// cycles between each increment of the envelope counter. +// The rates have been verified by sampling ENV3. +// +// The rate counter is a 16 bit register which is incremented each cycle. +// When the counter reaches a specific comparison value, the envelope counter +// is incremented (attack) or decremented (decay/release) and the +// counter is zeroed. +// +// NB! Sampling ENV3 shows that the calculated values are not exact. +// It may seem like most calculated values have been rounded (.5 is rounded +// down) and 1 has beed added to the result. A possible explanation for this +// is that the SID designers have used the calculated values directly +// as rate counter comparison values, not considering a one cycle delay to +// zero the counter. This would yield an actual period of comparison value + 1. +// +// The time of the first envelope count can not be exactly controlled, except +// possibly by resetting the chip. Because of this we cannot do cycle exact +// sampling and must devise another method to calculate the rate counter +// periods. +// +// The exact rate counter periods can be determined e.g. by counting the number +// of cycles from envelope level 1 to envelope level 129, and dividing the +// number of cycles by 128. CIA1 timer A and B in linked mode can perform +// the cycle count. This is the method used to find the rates below. +// +// To avoid the ADSR delay bug, sampling of ENV3 should be done using +// sustain = release = 0. This ensures that the attack state will not lower +// the current rate counter period. +// +// The ENV3 sampling code below yields a maximum timing error of 14 cycles. +// lda #$01 +// l1: cmp $d41c +// bne l1 +// ... +// lda #$ff +// l2: cmp $d41c +// bne l2 +// +// This yields a maximum error for the calculated rate period of 14/128 cycles. +// The described method is thus sufficient for exact calculation of the rate +// periods. +// +reg16 EnvelopeGeneratorFP::rate_counter_period[] = { + 9, // 2ms*1.0MHz/256 = 7.81 + 32, // 8ms*1.0MHz/256 = 31.25 + 63, // 16ms*1.0MHz/256 = 62.50 + 95, // 24ms*1.0MHz/256 = 93.75 + 149, // 38ms*1.0MHz/256 = 148.44 + 220, // 56ms*1.0MHz/256 = 218.75 + 267, // 68ms*1.0MHz/256 = 265.63 + 313, // 80ms*1.0MHz/256 = 312.50 + 392, // 100ms*1.0MHz/256 = 390.63 + 977, // 250ms*1.0MHz/256 = 976.56 + 1954, // 500ms*1.0MHz/256 = 1953.13 + 3126, // 800ms*1.0MHz/256 = 3125.00 + 3907, // 1 s*1.0MHz/256 = 3906.25 + 11720, // 3 s*1.0MHz/256 = 11718.75 + 19532, // 5 s*1.0MHz/256 = 19531.25 + 31251 // 8 s*1.0MHz/256 = 31250.00 +}; + + +// For decay and release, the clock to the envelope counter is sequentially +// divided by 1, 2, 4, 8, 16, 30, 1 to create a piece-wise linear approximation +// of an exponential. The exponential counter period is loaded at the envelope +// counter values 255, 93, 54, 26, 14, 6, 0. The period can be different for the +// same envelope counter value, depending on whether the envelope has been +// rising (attack -> release) or sinking (decay/release). +// +// Since it is not possible to reset the rate counter (the test bit has no +// influence on the envelope generator whatsoever) a method must be devised to +// do cycle exact sampling of ENV3 to do the investigation. This is possible +// with knowledge of the rate period for A=0, found above. +// +// The CPU can be synchronized with ENV3 by first synchronizing with the rate +// counter by setting A=0 and wait in a carefully timed loop for the envelope +// counter _not_ to change for 9 cycles. We can then wait for a specific value +// of ENV3 with another timed loop to fully synchronize with ENV3. +// +// At the first period when an exponential counter period larger than one +// is used (decay or relase), one extra cycle is spent before the envelope is +// decremented. The envelope output is then delayed one cycle until the state +// is changed to attack. Now one cycle less will be spent before the envelope +// is incremented, and the situation is normalized. +// The delay is probably caused by the comparison with the exponential counter, +// and does not seem to affect the rate counter. This has been verified by +// timing 256 consecutive complete envelopes with A = D = R = 1, S = 0, using +// CIA1 timer A and B in linked mode. If the rate counter is not affected the +// period of each complete envelope is +// (255 + 162*1 + 39*2 + 28*4 + 12*8 + 8*16 + 6*30)*32 = 756*32 = 32352 +// which corresponds exactly to the timed value divided by the number of +// complete envelopes. +// NB! This one cycle delay is not modeled. + + +// From the sustain levels it follows that both the low and high 4 bits of the +// envelope counter are compared to the 4-bit sustain value. +// This has been verified by sampling ENV3. +// +reg8 EnvelopeGeneratorFP::sustain_level[] = { + 0x00, + 0x11, + 0x22, + 0x33, + 0x44, + 0x55, + 0x66, + 0x77, + 0x88, + 0x99, + 0xaa, + 0xbb, + 0xcc, + 0xdd, + 0xee, + 0xff, +}; + + +// ---------------------------------------------------------------------------- +// Register functions. +// ---------------------------------------------------------------------------- +void EnvelopeGeneratorFP::writeCONTROL_REG(reg8 control) +{ + reg8 gate_next = control & 0x01; + + // The rate counter is never reset, thus there will be a delay before the + // envelope counter starts counting up (attack) or down (release). + + // Gate bit on: Start attack, decay, sustain. + if (!gate && gate_next) { + state = ATTACK; + update_rate_period(rate_counter_period[attack]); + + // Switching to attack state unlocks the zero freeze. + hold_zero = false; + } + // Gate bit off: Start release. + else if (gate && !gate_next) { + state = RELEASE; + update_rate_period(rate_counter_period[release]); + } + + gate = gate_next; +} + +void EnvelopeGeneratorFP::writeATTACK_DECAY(reg8 attack_decay) +{ + attack = (attack_decay >> 4) & 0x0f; + decay = attack_decay & 0x0f; + if (state == ATTACK) { + update_rate_period(rate_counter_period[attack]); + } + else if (state == DECAY_SUSTAIN) { + update_rate_period(rate_counter_period[decay]); + } +} + +void EnvelopeGeneratorFP::writeSUSTAIN_RELEASE(reg8 sustain_release) +{ + sustain = (sustain_release >> 4) & 0x0f; + release = sustain_release & 0x0f; + if (state == RELEASE) { + update_rate_period(rate_counter_period[release]); + } +} + +reg8 EnvelopeGeneratorFP::readENV() +{ + return output(); +} + +void EnvelopeGeneratorFP::update_rate_period(reg16 newperiod) +{ + rate_period = newperiod; + + /* The ADSR counter is XOR shift register with 0x7fff unique values. + * If the rate_period is adjusted to a value already seen in this cycle, + * the register will wrap around. This is known as the ADSR delay bug. + * + * To simplify the hot path calculation, we simulate this through observing + * that we add the 0x7fff cycle delay by changing the rate_counter variable + * directly. This takes care of the 99 % common case. However, playroutine + * could make multiple consequtive rate_period adjustments, in which case we + * need to cancel the previous adjustment. */ + + /* if the new period exeecds 0x7fff, we need to wrap */ + if (rate_period - rate_counter > 0x7fff) + rate_counter += 0x7fff; + + /* simulate 0x7fff wraparound, if the period-to-be-written + * is less than the current value. */ + if (rate_period <= rate_counter) + rate_counter -= 0x7fff; + + /* at this point it should be impossible for + * rate_counter >= rate_period. If it is, there is a bug... */ +} diff --git a/src/resid-fp/envelope.h b/src/resid-fp/envelope.h new file mode 100644 index 000000000..556e71a47 --- /dev/null +++ b/src/resid-fp/envelope.h @@ -0,0 +1,174 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// --------------------------------------------------------------------------- + +#ifndef __ENVELOPE_H__ +#define __ENVELOPE_H__ + +#include "siddefs-fp.h" + +// ---------------------------------------------------------------------------- +// A 15 bit counter is used to implement the envelope rates, in effect +// dividing the clock to the envelope counter by the currently selected rate +// period. +// In addition, another counter is used to implement the exponential envelope +// decay, in effect further dividing the clock to the envelope counter. +// The period of this counter is set to 1, 2, 4, 8, 16, 30 at the envelope +// counter values 255, 93, 54, 26, 14, 6, respectively. +// ---------------------------------------------------------------------------- +class EnvelopeGeneratorFP +{ +public: + EnvelopeGeneratorFP(); + + enum State { ATTACK, DECAY_SUSTAIN, RELEASE }; + + RESID_INLINE void clock(); + void reset(); + + void writeCONTROL_REG(reg8); + void writeATTACK_DECAY(reg8); + void writeSUSTAIN_RELEASE(reg8); + reg8 readENV(); + + // 8-bit envelope output. + RESID_INLINE reg8 output(); + +protected: + void update_rate_period(reg16 period); + + int rate_counter; + int rate_period; + reg8 exponential_counter; + reg8 exponential_counter_period; + reg8 envelope_counter; + bool hold_zero; + + reg4 attack; + reg4 decay; + reg4 sustain; + reg4 release; + + reg8 gate; + + State state; + + // Lookup table to convert from attack, decay, or release value to rate + // counter period. + static reg16 rate_counter_period[]; + + // The 16 selectable sustain levels. + static reg8 sustain_level[]; + +friend class SIDFP; +}; + + +// ---------------------------------------------------------------------------- +// SID clocking - 1 cycle. +// ---------------------------------------------------------------------------- +RESID_INLINE +void EnvelopeGeneratorFP::clock() +{ + if (++ rate_counter != rate_period) + return; + + rate_counter = 0; + + // The first envelope step in the attack state also resets the exponential + // counter. This has been verified by sampling ENV3. + // + if (state == ATTACK || ++exponential_counter == exponential_counter_period) + { + exponential_counter = 0; + + // Check whether the envelope counter is frozen at zero. + if (hold_zero) { + return; + } + + switch (state) { + case ATTACK: + // The envelope counter can flip from 0xff to 0x00 by changing state to + // release, then to attack. The envelope counter is then frozen at + // zero; to unlock this situation the state must be changed to release, + // then to attack. This has been verified by sampling ENV3. + // + ++envelope_counter &= 0xff; + if (envelope_counter == 0xff) { + state = DECAY_SUSTAIN; + update_rate_period(rate_counter_period[decay]); + } + break; + case DECAY_SUSTAIN: + if (envelope_counter != sustain_level[sustain]) { + --envelope_counter; + } + break; + case RELEASE: + // The envelope counter can flip from 0x00 to 0xff by changing state to + // attack, then to release. The envelope counter will then continue + // counting down in the release state. + // This has been verified by sampling ENV3. + // NB! The operation below requires two's complement integer. + // + --envelope_counter &= 0xff; + break; + } + + // Check for change of exponential counter period. + switch (envelope_counter) { + case 0xff: + exponential_counter_period = 1; + break; + case 0x5d: + exponential_counter_period = 2; + break; + case 0x36: + exponential_counter_period = 4; + break; + case 0x1a: + exponential_counter_period = 8; + break; + case 0x0e: + exponential_counter_period = 16; + break; + case 0x06: + exponential_counter_period = 30; + break; + case 0x00: + exponential_counter_period = 1; + + // When the envelope counter is changed to zero, it is frozen at zero. + // This has been verified by sampling ENV3. + hold_zero = true; + break; + } + } +} + +// ---------------------------------------------------------------------------- +// Read the envelope generator output. +// ---------------------------------------------------------------------------- +RESID_INLINE +reg8 EnvelopeGeneratorFP::output() +{ + return envelope_counter; +} + +#endif // not __ENVELOPE_H__ diff --git a/src/resid-fp/extfilt.cc b/src/resid-fp/extfilt.cc new file mode 100644 index 000000000..777a23ee3 --- /dev/null +++ b/src/resid-fp/extfilt.cc @@ -0,0 +1,94 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// --------------------------------------------------------------------------- + +#define __EXTFILT_CC__ +#include "extfilt.h" + +// ---------------------------------------------------------------------------- +// Constructor. +// ---------------------------------------------------------------------------- +ExternalFilterFP::ExternalFilterFP() +{ + reset(); + enable_filter(true); + set_chip_model(MOS6581FP); + set_clock_frequency(1e6f); + set_sampling_parameter(15915.6f); +} + + +// ---------------------------------------------------------------------------- +// Enable filter. +// ---------------------------------------------------------------------------- +void ExternalFilterFP::enable_filter(bool enable) +{ + enabled = enable; +} + +// ---------------------------------------------------------------------------- +// Setup of the external filter sampling parameters. +// ---------------------------------------------------------------------------- +void ExternalFilterFP::set_clock_frequency(float clock) +{ + clock_frequency = clock; + _set_sampling_parameter(); +} + +void ExternalFilterFP::set_sampling_parameter(float freq) +{ + pass_frequency = freq; + _set_sampling_parameter(); +} + +void ExternalFilterFP::_set_sampling_parameter() +{ + // Low-pass: R = 10kOhm, C = 1000pF; w0l = 1/RC = 1/(1e4*1e-9) = 100000 + // High-pass: R = 1kOhm, C = 10uF; w0h = 1/RC = 1/(1e3*1e-5) = 100 + w0hp = 100.f / clock_frequency; + w0lp = pass_frequency * 2.f * M_PI_f / clock_frequency; +} + +// ---------------------------------------------------------------------------- +// Set chip model. +// ---------------------------------------------------------------------------- +void ExternalFilterFP::set_chip_model(chip_model model) +{ + if (model == MOS6581FP) { + // Approximate the DC output level to be removed if the external + // filter is turned off. (0x800 - wave_zero + voice DC) * maxenv * voices + // - extin offset... + mixer_DC = (-0x600 + 0x800) * 0xff * 3 - 0x20000; + } + else { + // No DC offsets in the MOS8580. + mixer_DC = 0; + } +} + + +// ---------------------------------------------------------------------------- +// SID reset. +// ---------------------------------------------------------------------------- +void ExternalFilterFP::reset() +{ + // State of filter. + Vlp = 0; + Vhp = 0; + Vo = 0; +} diff --git a/src/resid-fp/extfilt.h b/src/resid-fp/extfilt.h new file mode 100644 index 000000000..b0e04d3b8 --- /dev/null +++ b/src/resid-fp/extfilt.h @@ -0,0 +1,120 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// --------------------------------------------------------------------------- + +#ifndef __EXTFILT_H__ +#define __EXTFILT_H__ + +#include + +#include "siddefs-fp.h" + +// ---------------------------------------------------------------------------- +// The audio output stage in a Commodore 64 consists of two STC networks, +// a low-pass filter with 3-dB frequency 16kHz followed by a high-pass +// filter with 3-dB frequency 16Hz (the latter provided an audio equipment +// input impedance of 1kOhm). +// The STC networks are connected with a BJT supposedly meant to act as +// a unity gain buffer, which is not really how it works. A more elaborate +// model would include the BJT, however DC circuit analysis yields BJT +// base-emitter and emitter-base impedances sufficiently low to produce +// additional low-pass and high-pass 3dB-frequencies in the order of hundreds +// of kHz. This calls for a sampling frequency of several MHz, which is far +// too high for practical use. +// ---------------------------------------------------------------------------- +class ExternalFilterFP +{ +public: + ExternalFilterFP(); + + void enable_filter(bool enable); + void set_sampling_parameter(float pass_freq); + void set_chip_model(chip_model model); + void set_clock_frequency(float); + + RESID_INLINE void clock(float Vi); + void reset(); + + // Audio output (20 bits). + RESID_INLINE float output(); + +private: + void _set_sampling_parameter(); + void nuke_denormals(); + + // Filter enabled. + bool enabled; + + // Maximum mixer DC offset. + float mixer_DC; + + // Relevant clocks + float clock_frequency, pass_frequency; + + // State of filters. + float Vlp; // lowpass + float Vhp; // highpass + float Vo; + + // Cutoff frequencies. + float w0lp; + float w0hp; + +friend class SIDFP; +}; + +// ---------------------------------------------------------------------------- +// SID clocking - 1 cycle. +// ---------------------------------------------------------------------------- +RESID_INLINE +void ExternalFilterFP::clock(float Vi) +{ + // This is handy for testing. + if (! enabled) { + // Remove maximum DC level since there is no filter to do it. + Vlp = Vhp = 0.f; + Vo = Vi - mixer_DC; + return; + } + + float dVlp = w0lp * (Vi - Vlp); + float dVhp = w0hp * (Vlp - Vhp); + Vo = Vlp - Vhp; + Vlp += dVlp; + Vhp += dVhp; +} + +// ---------------------------------------------------------------------------- +// Audio output (19.5 bits). +// ---------------------------------------------------------------------------- +RESID_INLINE +float ExternalFilterFP::output() +{ + return Vo; +} + +RESID_INLINE +void ExternalFilterFP::nuke_denormals() +{ + if (Vhp > -1e-12f && Vhp < 1e-12f) + Vhp = 0; + if (Vlp > -1e-12f && Vlp < 1e-12f) + Vlp = 0; +} + +#endif // not __EXTFILT_H__ diff --git a/src/resid-fp/filter.cc b/src/resid-fp/filter.cc new file mode 100644 index 000000000..c327fadec --- /dev/null +++ b/src/resid-fp/filter.cc @@ -0,0 +1,194 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// --------------------------------------------------------------------------- +// Filter distortion code written by Antti S. Lankila 2007 - 2008. + +#define __FILTER_CC__ +#include "filter.h" +#include "sid.h" + +#ifndef HAVE_LOGF_PROTOTYPE +extern float logf(float val); +#endif + +#ifndef HAVE_EXPF_PROTOTYPE +extern float expf(float val); +#endif + +#ifndef HAVE_LOGF +float logf(float val) +{ + return (float)log((double)val); +} +#endif + +#ifndef HAVE_EXPF +float expf(float val) +{ + return (float)exp((double)val); +} +#endif + +// ---------------------------------------------------------------------------- +// Constructor. +// ---------------------------------------------------------------------------- +FilterFP::FilterFP() +{ + model = (chip_model) 0; // neither 6581/8580; init time only + enable_filter(true); + /* approximate; sid.cc calls us when set_sampling_parameters() occurs. */ + set_clock_frequency(1e6f); + /* these parameters are a work-in-progress. */ + set_distortion_properties(2.5e-3f, 1536.f, 1e-4f); + /* sound similar to alankila6581r4ar3789 */ + set_type3_properties(1.40e6f, 1.47e8f, 1.0059f, 1.55e4f); + /* sound similar to trurl8580r5_3691 */ + set_type4_properties(6.55f, 20.f); + reset(); + set_chip_model(MOS6581FP); +} + + +// ---------------------------------------------------------------------------- +// Enable filter. +// ---------------------------------------------------------------------------- +void FilterFP::enable_filter(bool enable) +{ + enabled = enable; +} + + +// ---------------------------------------------------------------------------- +// Set chip model. +// ---------------------------------------------------------------------------- +void FilterFP::set_chip_model(chip_model model) +{ + this->model = model; + set_Q(); + set_w0(); +} + +/* dist_CT eliminates 1/x at hot spot */ +void FilterFP::set_clock_frequency(float clock) { + clock_frequency = clock; + calculate_helpers(); +} + +void FilterFP::set_distortion_properties(float r, float p, float cft) +{ + distortion_rate = r; + distortion_point = p; + /* baseresistance is used to determine material resistivity later */ + distortion_cf_threshold = cft; + calculate_helpers(); +} + +void FilterFP::set_type4_properties(float k, float b) +{ + type4_k = k; + type4_b = b; +} + +void FilterFP::set_type3_properties(float br, float o, float s, float mfr) +{ + type3_baseresistance = br; + type3_offset = o; + type3_steepness = -logf(s); /* s^x to e^(x*ln(s)), 1/e^x == e^-x. */ + type3_minimumfetresistance = mfr; +} + +void FilterFP::calculate_helpers() +{ + if (clock_frequency != 0.f) + distortion_CT = 1.f / (sidcaps_6581 * clock_frequency); + set_w0(); +} + +// ---------------------------------------------------------------------------- +// SID reset. +// ---------------------------------------------------------------------------- +void FilterFP::reset() +{ + fc = 0; + res = filt = voice3off = hp_bp_lp = 0; + vol = 0; + volf = Vhp = Vbp = Vlp = 0; + set_w0(); + set_Q(); +} + +// ---------------------------------------------------------------------------- +// Register functions. +// ---------------------------------------------------------------------------- +void FilterFP::writeFC_LO(reg8 fc_lo) +{ + fc = (fc & 0x7f8) | (fc_lo & 0x007); + set_w0(); +} + +void FilterFP::writeFC_HI(reg8 fc_hi) +{ + fc = ((fc_hi << 3) & 0x7f8) | (fc & 0x007); + set_w0(); +} + +void FilterFP::writeRES_FILT(reg8 res_filt) +{ + res = (res_filt >> 4) & 0x0f; + set_Q(); + + filt = res_filt & 0x0f; +} + +void FilterFP::writeMODE_VOL(reg8 mode_vol) +{ + voice3off = mode_vol & 0x80; + + hp_bp_lp = (mode_vol >> 4) & 0x07; + + vol = mode_vol & 0x0f; + volf = (float) vol / 15.f; +} + +// Set filter cutoff frequency. +void FilterFP::set_w0() +{ + if (model == MOS6581FP) { + /* div once by extra kinkiness because I fitted the type3 eq with that variant. */ + float type3_fc_kink = SIDFP::kinked_dac(fc, kinkiness, 11) / kinkiness; + type3_fc_kink_exp = type3_offset * expf(type3_fc_kink * type3_steepness); + if (distortion_rate != 0.f) { + type3_fc_distortion_offset_hp = (distortion_point - type3_fc_kink) * (0.5f) / distortion_rate; + type3_fc_distortion_offset_bp = type3_fc_distortion_offset_hp; + } + else { + type3_fc_distortion_offset_bp = 9e9f; + type3_fc_distortion_offset_hp = 9e9f; + } + } + if (model == MOS8580FP) { + type4_w0_cache = type4_w0(); + } +} + +// Set filter resonance. +void FilterFP::set_Q() +{ + float Q = res / 15.f; + _1_div_Q = 1.f / (0.707f + Q * 1.5f); +} diff --git a/src/resid-fp/filter.h b/src/resid-fp/filter.h new file mode 100644 index 000000000..13e6aa67e --- /dev/null +++ b/src/resid-fp/filter.h @@ -0,0 +1,383 @@ +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// --------------------------------------------------------------------------- +// Filter distortion code written by Antti S. Lankila 2007 - 2008. + +#ifndef __FILTER_H__ +#define __FILTER_H__ + +#include +#include "siddefs-fp.h" + +// ---------------------------------------------------------------------------- +// The SID filter is modeled with a two-integrator-loop biquadratic filter, +// which has been confirmed by Bob Yannes to be the actual circuit used in +// the SID chip. +// +// Measurements show that excellent emulation of the SID filter is achieved, +// except when high resonance is combined with high sustain levels. +// In this case the SID op-amps are performing less than ideally and are +// causing some peculiar behavior of the SID filter. This however seems to +// have more effect on the overall amplitude than on the color of the sound. +// +// The theory for the filter circuit can be found in "Microelectric Circuits" +// by Adel S. Sedra and Kenneth C. Smith. +// The circuit is modeled based on the explanation found there except that +// an additional inverter is used in the feedback from the bandpass output, +// allowing the summer op-amp to operate in single-ended mode. This yields +// inverted filter outputs with levels independent of Q, which corresponds with +// the results obtained from a real SID. +// +// We have been able to model the summer and the two integrators of the circuit +// to form components of an IIR filter. +// Vhp is the output of the summer, Vbp is the output of the first integrator, +// and Vlp is the output of the second integrator in the filter circuit. +// +// According to Bob Yannes, the active stages of the SID filter are not really +// op-amps. Rather, simple NMOS inverters are used. By biasing an inverter +// into its region of quasi-linear operation using a feedback resistor from +// input to output, a MOS inverter can be made to act like an op-amp for +// small signals centered around the switching threshold. +// +// Qualified guesses at SID filter schematics are depicted below. +// +// SID filter +// ---------- +// +// ----------------------------------------------- +// | | +// | ---Rq-- | +// | | | | +// | --------------|--R-----[A>--|--R-----[A>--| +// | | | | +// vi -----R1-- | | | +// +// vhp vbp vlp +// +// +// vi - input voltage +// vhp - highpass output +// vbp - bandpass output +// vlp - lowpass output +// [A> - op-amp +// R1 - summer resistor +// Rq - resistor array controlling resonance (4 resistors) +// R - NMOS FET voltage controlled resistor controlling cutoff frequency +// Rs - shunt resitor +// C - capacitor +// +// +// +// SID integrator +// -------------- +// +// V+ +// +// | +// | +// -----| +// | | +// | ||-- +// -|| +// ---C--- ||-> +// | | | +// |---Rs-----------|---- vo +// | | +// | ||-- +// vi ---- -----|------------|| +// | ^ | ||-> +// |___| | | +// ----- | | +// | | | +// |---R2-- | +// | +// R1 V- +// | +// | +// +// Vw +// +// ---------------------------------------------------------------------------- +class FilterFP +{ +public: + FilterFP(); + + void enable_filter(bool enable); + void set_chip_model(chip_model model); + void set_distortion_properties(float, float, float); + void set_type3_properties(float, float, float, float); + void set_type4_properties(float, float); + void set_clock_frequency(float); + + RESID_INLINE + float clock(float voice1, float voice2, float voice3, + float ext_in); + void reset(); + + // Write registers. + void writeFC_LO(reg8); + void writeFC_HI(reg8); + void writeRES_FILT(reg8); + void writeMODE_VOL(reg8); + +private: + void set_Q(); + void set_w0(); + float type3_w0(const float source, const float offset); + float type4_w0(); + void calculate_helpers(); + void nuke_denormals(); + + // Filter enabled. + bool enabled; + + // 6581/8580 filter model (XXX: we should specialize in separate classes) + chip_model model; + + // Filter cutoff frequency. + reg12 fc; + + // Filter resonance. + reg8 res; + + // Selects which inputs to route through filter. + reg8 filt; + + // Switch voice 3 off. + reg8 voice3off; + + // Highpass, bandpass, and lowpass filter modes. + reg8 hp_bp_lp; + + // Output master volume. + reg4 vol; + float volf; /* avoid integer-to-float conversion at output */ + + // clock + float clock_frequency; + + /* Distortion params for Type3 */ + float distortion_rate, distortion_point, distortion_cf_threshold; + + /* Type3 params. */ + float type3_baseresistance, type3_offset, type3_steepness, type3_minimumfetresistance; + + /* Type4 params */ + float type4_k, type4_b; + + // State of filter. + float Vhp, Vbp, Vlp; + + /* Resonance/Distortion/Type3/Type4 helpers. */ + float type4_w0_cache, _1_div_Q, type3_fc_kink_exp, distortion_CT, + type3_fc_distortion_offset_bp, type3_fc_distortion_offset_hp; + +friend class SIDFP; +}; + +// ---------------------------------------------------------------------------- +// Inline functions. +// The following functions are defined inline because they are called every +// time a sample is calculated. +// ---------------------------------------------------------------------------- + +/* kinkiness of DAC: + * some chips have more, some less. We should make this tunable. */ +const float kinkiness = 0.966f; +const float sidcaps_6581 = 470e-12f; +const float outputleveldifference_lp_bp = 1.4f; +const float outputleveldifference_bp_hp = 1.2f; + +RESID_INLINE +static float fastexp(float val) { + typedef union { + int i; + float f; + } conv; + + conv tmp; + + /* single precision fp has 1 + 8 + 23 bits, exponent bias is 127. + * It therefore follows that we need to shift left by 23 bits, and to + * calculate exp(x) instead of pow(2, x) we divide the power by ln(2). */ + const float a = (1 << 23) / M_LN2_f; + /* The other factor corrects for the exponent bias so that 2^0 = 1. */ + const float b = (1 << 23) * 127; + /* According to "A Fast, Compact Approximation of the Exponential Function" + * by Nicol N. Schraudolph, 60801.48 yields the minimum RMS error for the + * piecewise-linear approximation when using doubles (20 bits residual). + * We have 23 bits, so we scale this value by 8. */ + const float c = 60801.48f * 8.f + 0.5f; + + /* Parenthesis are important: C standard disallows folding subtraction. + * Unfortunately GCC appears to generate a write to memory rather than + * handle this conversion entirely in registers. */ + tmp.i = (int)(a * val + (b - c)); + return tmp.f; +} + +RESID_INLINE +float FilterFP::type3_w0(const float source, const float distoffset) +{ + /* The distortion appears to be the result of MOSFET entering saturation + * mode. The conductance of a FET is proportional to: + * + * ohmic = 2 * (Vgs - Vt) * Vds - Vds^2 + * saturation = (Vgs - Vt)^2 + * + * The FET switches to saturation mode when Vgs - Vt < Vds. + * + * In the circuit, the Vgs is mixed with the Vds signal, which gives + * (Vgs + Vds) / 2 as the gate voltage. Doing the substitutions we get: + * + * ohmic = 2 * ((Vgs + Vds) / 2 - Vt) * Vds - Vds^2 = (Vgs - Vt) * Vds + * saturation = ((Vgs + Vds) / 2 - Vt)^2 + * + * Therefore: once the Vds crosses a threshold given by the gate and + * threshold FET conductance begins to increase faster. The exact shape + * for this effect is a parabola. + * + * The scaling term here tries to match the FC control level with + * the signal level in simulation. On the chip, the FC control is + * biased by forcing its highest DAC bit in the 1 position, thus + * limiting the electrical range to half. Therefore one can guess that + * the real FC range is half of the full voice range. + * + * On the simulation, FC goes to 2047 and the voices to 4095 * 255. + * If the FC control was intact, then the scaling factor would be + * 1/512. (Simulation voices are 512 times "louder" intrinsically.) + * As the real chip's FC has reduced range, the scaling required to + * match levels is 1/256. */ + + float fetresistance = type3_fc_kink_exp; + if (source > distoffset) { + const float dist = source - distoffset; + fetresistance *= fastexp(dist * type3_steepness * distortion_rate); + } + const float dynamic_resistance = type3_minimumfetresistance + fetresistance; + + /* 2 parallel resistors */ + const float _1_div_resistance = (type3_baseresistance + dynamic_resistance) / (type3_baseresistance * dynamic_resistance); + /* 1.f / (clock * caps * resistance) */ + return distortion_CT * _1_div_resistance; +} + +RESID_INLINE +float FilterFP::type4_w0() +{ + const float freq = type4_k * fc + type4_b; + return 2.f * M_PI_f * freq / clock_frequency; +} + +// ---------------------------------------------------------------------------- +// SID clocking - 1 cycle. +// ---------------------------------------------------------------------------- +RESID_INLINE +float FilterFP::clock(float voice1, + float voice2, + float voice3, + float ext_in) +{ + /* Avoid denormal numbers by using small offsets from 0 */ + float Vi = 0.f, Vnf = 0.f, Vf = 0.f; + + // Route voices into or around filter. + ((filt & 1) ? Vi : Vnf) += voice1; + ((filt & 2) ? Vi : Vnf) += voice2; + // NB! Voice 3 is not silenced by voice3off if it is routed through + // the filter. + if (filt & 4) + Vi += voice3; + else if (! voice3off) + Vnf += voice3; + ((filt & 8) ? Vi : Vnf) += ext_in; + + if (! enabled) + return (Vnf - Vi) * volf; + + if (hp_bp_lp & 1) + Vf += Vlp; + if (hp_bp_lp & 2) + Vf += Vbp; + if (hp_bp_lp & 4) + Vf += Vhp; + + if (model == MOS6581FP) { + float diff1, diff2; + + Vhp = Vbp * _1_div_Q * (1.f/outputleveldifference_bp_hp) - Vlp * (1.f/outputleveldifference_bp_hp) - Vi * 0.5f; + + /* the input summer mixing, or something like it... */ + diff1 = (Vlp - Vbp) * distortion_cf_threshold; + diff2 = (Vhp - Vbp) * distortion_cf_threshold; + Vlp -= diff1; + Vbp += diff1; + Vbp += diff2; + Vhp -= diff2; + + /* Model output strip mixing. Doing it now that HP state + * variable modifying still makes some difference. + * (Phase error, though.) */ + if (hp_bp_lp & 1) + Vlp += (Vf + Vnf - Vlp) * distortion_cf_threshold; + if (hp_bp_lp & 2) + Vbp += (Vf + Vnf - Vbp) * distortion_cf_threshold; + if (hp_bp_lp & 4) + Vhp += (Vf + Vnf - Vhp) * distortion_cf_threshold; + + /* Simulating the exponential VCR that the FET block is... */ + Vlp -= Vbp * type3_w0(Vbp, type3_fc_distortion_offset_bp); + Vbp -= Vhp * type3_w0(Vhp, type3_fc_distortion_offset_hp) * outputleveldifference_bp_hp; + + /* Tuned based on Fred Gray's Break Thru. It is probably not a hard + * discontinuity but a saturation effect... */ + if (Vnf > 3.2e6f) + Vnf = 3.2e6f; + + Vf += Vnf + Vlp * (outputleveldifference_lp_bp - 1.f); + } else { + /* On the 8580, BP appears mixed in phase with the rest. */ + Vhp = -Vbp * _1_div_Q - Vlp - Vi; + Vlp += Vbp * type4_w0_cache; + Vbp += Vhp * type4_w0_cache; + + Vf += Vnf; + } + + return Vf * volf; +} + +RESID_INLINE +void FilterFP::nuke_denormals() +{ + /* We could use the flush-to-zero flag or denormals-are-zero on systems + * where compiling with -msse and -mfpmath=sse is acceptable. Since this + * doesn't include general VICE builds, we do this instead. */ + if (Vbp > -1e-12f && Vbp < 1e-12f) + Vbp = 0; + if (Vlp > -1e-12f && Vlp < 1e-12f) + Vlp = 0; +} + +#endif // not __FILTER_H__ diff --git a/src/resid-fp/pot.cc b/src/resid-fp/pot.cc new file mode 100644 index 000000000..4cd85a5c3 --- /dev/null +++ b/src/resid-fp/pot.cc @@ -0,0 +1,26 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// --------------------------------------------------------------------------- + +#include "pot.h" + +reg8 PotentiometerFP::readPOT() +{ + // NB! Not modeled. + return 0xff; +} diff --git a/src/resid-fp/pot.h b/src/resid-fp/pot.h new file mode 100644 index 000000000..e1deeabda --- /dev/null +++ b/src/resid-fp/pot.h @@ -0,0 +1,31 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// --------------------------------------------------------------------------- + +#ifndef __POT_H__ +#define __POT_H__ + +#include "siddefs-fp.h" + +class PotentiometerFP +{ +public: + reg8 readPOT(); +}; + +#endif diff --git a/src/resid-fp/samp2src.pl b/src/resid-fp/samp2src.pl new file mode 100644 index 000000000..fc6398382 --- /dev/null +++ b/src/resid-fp/samp2src.pl @@ -0,0 +1,65 @@ +#! /usr/bin/perl -w +# --------------------------------------------------------------------------- +# This file is part of reSID, a MOS6581 SID emulator engine. +# Copyright (C) 2004 Dag Lem +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# --------------------------------------------------------------------------- + +use strict; + +die("Usage: samp2src name data-in src-out\n") unless @ARGV == 3; +my ($name, $in, $out) = @ARGV; + +open(F, "<$in") or die($!); +local $/ = undef; +my $data = ; +close(F) or die($!); + +open(F, ">$out") or die($!); + +print F <<\EOF; +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// --------------------------------------------------------------------------- + +EOF + +print F "#include \"wave.h\"\n\nreg8 WaveformGeneratorFP::$name\[\] =\n{\n"; + +for (my $i = 0; $i < length($data); $i += 8) { + print F sprintf("/* 0x%03x: */ ", $i), map(sprintf(" 0x%02x,", $_), unpack("C*", substr($data, $i, 8))), "\n"; +} + +print F "};\n"; + +close(F) or die($!); + +exit(0); diff --git a/src/resid-fp/sid.cc b/src/resid-fp/sid.cc new file mode 100644 index 000000000..eda01ab2f --- /dev/null +++ b/src/resid-fp/sid.cc @@ -0,0 +1,944 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// --------------------------------------------------------------------------- + +#include "sid.h" +#include +#include + +extern float convolve(const float *a, const float *b, int n); +extern float convolve_sse(const float *a, const float *b, int n); + +enum host_cpu_feature { + HOST_CPU_MMX=1, HOST_CPU_SSE=2, HOST_CPU_SSE2=4, HOST_CPU_SSE3=8 +}; + +/* This code is appropriate for 32-bit and 64-bit x86 CPUs. */ +#if defined(__x86_64__) || defined(__i386__) || defined(_MSC_VER) + +struct cpu_x86_regs_s { + unsigned int eax; + unsigned int ebx; + unsigned int ecx; + unsigned int edx; +}; +typedef struct cpu_x86_regs_s cpu_x86_regs_t; + +static cpu_x86_regs_t get_cpuid_regs(unsigned int index) +{ + cpu_x86_regs_t retval; + +#if defined(_MSC_VER) /* MSVC assembly */ + __asm { + mov eax, [index] + cpuid + mov [retval.eax], eax + mov [retval.ebx], ebx + mov [retval.ecx], ecx + mov [retval.edx], edx + } +#else /* GNU assembly */ + asm("movl %1, %%eax; cpuid; movl %%eax, %0;" + : "=m" (retval.eax) + : "r" (index) + : "eax", "ebx", "ecx", "edx"); + asm("movl %1, %%eax; cpuid; movl %%ebx, %0;" + : "=m" (retval.ebx) + : "r" (index) + : "eax", "ebx", "ecx", "edx"); + asm("movl %1, %%eax; cpuid; movl %%ecx, %0;" + : "=m" (retval.ecx) + : "r" (index) + : "eax", "ebx", "ecx", "edx"); + asm("movl %1, %%eax; cpuid; movl %%edx, %0;" + : "=m" (retval.edx) + : "r" (index) + : "eax", "ebx", "ecx", "edx"); +#endif + + return retval; +} + +static int host_cpu_features_by_cpuid(void) +{ + cpu_x86_regs_t regs = get_cpuid_regs(1); + + int features = 0; + if (regs.edx & (1 << 23)) + features |= HOST_CPU_MMX; + if (regs.edx & (1 << 25)) + features |= HOST_CPU_SSE; + if (regs.edx & (1 << 26)) + features |= HOST_CPU_SSE2; + if (regs.ecx & (1 << 0)) + features |= HOST_CPU_SSE3; + + return features; +} + +static int host_cpu_features(void) +{ + static int features = 0; + static int features_detected = 0; +/* 32-bit only */ +#if defined(__i386__) || (defined(_MSC_VER) && defined(_WIN32)) + unsigned long temp1, temp2; +#endif + + if (features_detected) + return features; + features_detected = 1; + +#if defined(_MSC_VER) && defined(_WIN32) /* MSVC compatible assembly appropriate for 32-bit Windows */ + /* see if we are dealing with a cpu that has the cpuid instruction */ + __asm { + pushf + pop eax + mov [temp1], eax + xor eax, 0x200000 + push eax + popf + pushf + pop eax + mov [temp2], eax + push [temp1] + popf + } +#endif +#if defined(__i386__) /* GNU assembly */ + asm("pushfl; popl %%eax; movl %%eax, %0; xorl $0x200000, %%eax; pushl %%eax; popfl; pushfl; popl %%eax; movl %%eax, %1; pushl %0; popfl " + : "=r" (temp1), + "=r" (temp2) + : + : "eax"); +#endif +#if defined(__i386__) || (defined(_MSC_VER) && defined(_WIN32)) + temp1 &= 0x200000; + temp2 &= 0x200000; + if (temp1 == temp2) { + /* no cpuid support, so we can't test for SSE availability -> false */ + return 0; + } +#endif + + /* find the highest supported cpuid function, returned in %eax */ + if (get_cpuid_regs(0).eax < 1) { + /* no cpuid 1 function, we can't test for features -> no features */ + return 0; + } + + features = host_cpu_features_by_cpuid(); + return features; +} + +#else /* !__x86_64__ && !__i386__ && !_MSC_VER */ +static int host_cpu_features(void) +{ + return 0; +} +#endif + +float SIDFP::kinked_dac(const int x, const float nonlinearity, const int max) +{ + float value = 0.f; + + int bit = 1; + float weight = 1.f; + const float dir = 2.0f * nonlinearity; + for (int i = 0; i < max; i ++) { + if (x & bit) + value += weight; + bit <<= 1; + weight *= dir; + } + + return value / (weight / nonlinearity) * (1 << max); +} + +// ---------------------------------------------------------------------------- +// Constructor. +// ---------------------------------------------------------------------------- +SIDFP::SIDFP() +{ +#if (RESID_USE_SSE==1) + can_use_sse = (host_cpu_features() & HOST_CPU_SSE) != 0; +#else + can_use_sse = false; +#endif + + // Initialize pointers. + sample = 0; + fir = 0; + + voice[0].set_sync_source(&voice[2]); + voice[1].set_sync_source(&voice[0]); + voice[2].set_sync_source(&voice[1]); + + set_sampling_parameters(985248, SAMPLE_INTERPOLATE, 44100); + + bus_value = 0; + bus_value_ttl = 0; + + input(0); +} + + +// ---------------------------------------------------------------------------- +// Destructor. +// ---------------------------------------------------------------------------- +SIDFP::~SIDFP() +{ + delete[] sample; + delete[] fir; +} + + +// ---------------------------------------------------------------------------- +// Set chip model. +// ---------------------------------------------------------------------------- +void SIDFP::set_chip_model(chip_model model) +{ + for (int i = 0; i < 3; i++) { + voice[i].set_chip_model(model); + } + + filter.set_chip_model(model); + extfilt.set_chip_model(model); +} + +/* nonlinear DAC support, set 1 for 8580 / no effect, about 0.96 otherwise */ +void SIDFP::set_voice_nonlinearity(float nl) +{ + for (int i = 0; i < 3; i++) { + voice[i].set_nonlinearity(nl); + } +} + +// ---------------------------------------------------------------------------- +// SID reset. +// ---------------------------------------------------------------------------- +void SIDFP::reset() +{ + for (int i = 0; i < 3; i++) { + voice[i].reset(); + } + filter.reset(); + extfilt.reset(); + + bus_value = 0; + bus_value_ttl = 0; +} + + +// ---------------------------------------------------------------------------- +// Write 16-bit sample to audio input. +// NB! The caller is responsible for keeping the value within 16 bits. +// Note that to mix in an external audio signal, the signal should be +// resampled to 1MHz first to avoid sampling noise. +// ---------------------------------------------------------------------------- +void SIDFP::input(int sample) +{ + // Voice outputs are 20 bits. Scale up to match three voices in order + // to facilitate simulation of the MOS8580 "digi boost" hardware hack. + ext_in = (float) ( (sample << 4) * 3 ); +} + +float SIDFP::output() +{ + const float range = 1 << 15; + return extfilt.output() / (4095.f * 255.f * 3.f * 1.5f / range); +} + +// ---------------------------------------------------------------------------- +// Read registers. +// +// Reading a write only register returns the last byte written to any SID +// register. The individual bits in this value start to fade down towards +// zero after a few cycles. All bits reach zero within approximately +// $2000 - $4000 cycles. +// It has been claimed that this fading happens in an orderly fashion, however +// sampling of write only registers reveals that this is not the case. +// NB! This is not correctly modeled. +// The actual use of write only registers has largely been made in the belief +// that all SID registers are readable. To support this belief the read +// would have to be done immediately after a write to the same register +// (remember that an intermediate write to another register would yield that +// value instead). With this in mind we return the last value written to +// any SID register for $2000 cycles without modeling the bit fading. +// ---------------------------------------------------------------------------- +reg8 SIDFP::read(reg8 offset) +{ + switch (offset) { + case 0x19: + return potx.readPOT(); + case 0x1a: + return poty.readPOT(); + case 0x1b: + return voice[2].wave.readOSC(); + case 0x1c: + return voice[2].envelope.readENV(); + default: + return bus_value; + } +} + + +// ---------------------------------------------------------------------------- +// Write registers. +// ---------------------------------------------------------------------------- +void SIDFP::write(reg8 offset, reg8 value) +{ + bus_value = value; + bus_value_ttl = 0x4000; + + switch (offset) { + case 0x00: + voice[0].wave.writeFREQ_LO(value); + break; + case 0x01: + voice[0].wave.writeFREQ_HI(value); + break; + case 0x02: + voice[0].wave.writePW_LO(value); + break; + case 0x03: + voice[0].wave.writePW_HI(value); + break; + case 0x04: + voice[0].writeCONTROL_REG(value); + break; + case 0x05: + voice[0].envelope.writeATTACK_DECAY(value); + break; + case 0x06: + voice[0].envelope.writeSUSTAIN_RELEASE(value); + break; + case 0x07: + voice[1].wave.writeFREQ_LO(value); + break; + case 0x08: + voice[1].wave.writeFREQ_HI(value); + break; + case 0x09: + voice[1].wave.writePW_LO(value); + break; + case 0x0a: + voice[1].wave.writePW_HI(value); + break; + case 0x0b: + voice[1].writeCONTROL_REG(value); + break; + case 0x0c: + voice[1].envelope.writeATTACK_DECAY(value); + break; + case 0x0d: + voice[1].envelope.writeSUSTAIN_RELEASE(value); + break; + case 0x0e: + voice[2].wave.writeFREQ_LO(value); + break; + case 0x0f: + voice[2].wave.writeFREQ_HI(value); + break; + case 0x10: + voice[2].wave.writePW_LO(value); + break; + case 0x11: + voice[2].wave.writePW_HI(value); + break; + case 0x12: + voice[2].writeCONTROL_REG(value); + break; + case 0x13: + voice[2].envelope.writeATTACK_DECAY(value); + break; + case 0x14: + voice[2].envelope.writeSUSTAIN_RELEASE(value); + break; + case 0x15: + filter.writeFC_LO(value); + break; + case 0x16: + filter.writeFC_HI(value); + break; + case 0x17: + filter.writeRES_FILT(value); + break; + case 0x18: + filter.writeMODE_VOL(value); + break; + default: + break; + } +} + + +// ---------------------------------------------------------------------------- +// Constructor. +// ---------------------------------------------------------------------------- +SIDFP::State::State() +{ + int i; + + for (i = 0; i < 0x20; i++) { + sid_register[i] = 0; + } + + bus_value = 0; + bus_value_ttl = 0; + + for (i = 0; i < 3; i++) { + accumulator[i] = 0; + shift_register[i] = 0x7ffff8; + rate_counter[i] = 0; + rate_counter_period[i] = 9; + exponential_counter[i] = 0; + exponential_counter_period[i] = 1; + envelope_counter[i] = 0; + envelope_state[i] = EnvelopeGeneratorFP::RELEASE; + hold_zero[i] = true; + } +} + + +// ---------------------------------------------------------------------------- +// Read state. +// ---------------------------------------------------------------------------- +SIDFP::State SIDFP::read_state() +{ + State state; + int i, j; + + for (i = 0, j = 0; i < 3; i++, j += 7) { + WaveformGeneratorFP& wave = voice[i].wave; + EnvelopeGeneratorFP& envelope = voice[i].envelope; + state.sid_register[j + 0] = wave.freq & 0xff; + state.sid_register[j + 1] = wave.freq >> 8; + state.sid_register[j + 2] = wave.pw & 0xff; + state.sid_register[j + 3] = wave.pw >> 8; + state.sid_register[j + 4] = + (wave.waveform << 4) + | (wave.test ? 0x08 : 0) + | (wave.ring_mod ? 0x04 : 0) + | (wave.sync ? 0x02 : 0) + | (envelope.gate ? 0x01 : 0); + state.sid_register[j + 5] = (envelope.attack << 4) | envelope.decay; + state.sid_register[j + 6] = (envelope.sustain << 4) | envelope.release; + } + + state.sid_register[j++] = filter.fc & 0x007; + state.sid_register[j++] = filter.fc >> 3; + state.sid_register[j++] = (filter.res << 4) | filter.filt; + state.sid_register[j++] = + (filter.voice3off ? 0x80 : 0) + | (filter.hp_bp_lp << 4) + | filter.vol; + + // These registers are superfluous, but included for completeness. + for (; j < 0x1d; j++) { + state.sid_register[j] = read(j); + } + for (; j < 0x20; j++) { + state.sid_register[j] = 0; + } + + state.bus_value = bus_value; + state.bus_value_ttl = bus_value_ttl; + + for (i = 0; i < 3; i++) { + state.accumulator[i] = voice[i].wave.accumulator; + state.shift_register[i] = voice[i].wave.shift_register; + state.rate_counter[i] = voice[i].envelope.rate_counter; + state.rate_counter_period[i] = voice[i].envelope.rate_period; + state.exponential_counter[i] = voice[i].envelope.exponential_counter; + state.exponential_counter_period[i] = voice[i].envelope.exponential_counter_period; + state.envelope_counter[i] = voice[i].envelope.envelope_counter; + state.envelope_state[i] = voice[i].envelope.state; + state.hold_zero[i] = voice[i].envelope.hold_zero; + } + + return state; +} + + +// ---------------------------------------------------------------------------- +// Write state. +// ---------------------------------------------------------------------------- +void SIDFP::write_state(const State& state) +{ + int i; + + for (i = 0; i <= 0x18; i++) { + write(i, state.sid_register[i]); + } + + bus_value = state.bus_value; + bus_value_ttl = state.bus_value_ttl; + + for (i = 0; i < 3; i++) { + voice[i].wave.accumulator = state.accumulator[i]; + voice[i].wave.shift_register = state.shift_register[i]; + voice[i].envelope.rate_counter = state.rate_counter[i]; + voice[i].envelope.rate_period = state.rate_counter_period[i]; + voice[i].envelope.exponential_counter = state.exponential_counter[i]; + voice[i].envelope.exponential_counter_period = state.exponential_counter_period[i]; + voice[i].envelope.envelope_counter = state.envelope_counter[i]; + voice[i].envelope.state = state.envelope_state[i]; + voice[i].envelope.hold_zero = state.hold_zero[i]; + } +} + + +// ---------------------------------------------------------------------------- +// Enable filter. +// ---------------------------------------------------------------------------- +void SIDFP::enable_filter(bool enable) +{ + filter.enable_filter(enable); +} + + +// ---------------------------------------------------------------------------- +// Enable external filter. +// ---------------------------------------------------------------------------- +void SIDFP::enable_external_filter(bool enable) +{ + extfilt.enable_filter(enable); +} + + +// ---------------------------------------------------------------------------- +// I0() computes the 0th order modified Bessel function of the first kind. +// This function is originally from resample-1.5/filterkit.c by J. O. Smith. +// ---------------------------------------------------------------------------- +double SIDFP::I0(double x) +{ + // Max error acceptable in I0 could be 1e-6, which gives that 96 dB already. + // I'm overspecify these errors to get a beautiful FFT dump of the FIR. + const double I0e = 1e-10; + + double sum, u, halfx, temp; + int n; + + sum = u = n = 1; + halfx = x/2.0; + + do { + temp = halfx/n++; + u *= temp*temp; + sum += u; + } while (u >= I0e*sum); + + return sum; +} + + +// ---------------------------------------------------------------------------- +// Setting of SID sampling parameters. +// +// Use a clock freqency of 985248Hz for PAL C64, 1022730Hz for NTSC C64. +// The default end of passband frequency is pass_freq = 0.9*sample_freq/2 +// for sample frequencies up to ~ 44.1kHz, and 20kHz for higher sample +// frequencies. +// +// For resampling, the ratio between the clock frequency and the sample +// frequency is limited as follows: +// 125*clock_freq/sample_freq < 16384 +// E.g. provided a clock frequency of ~ 1MHz, the sample frequency can not +// be set lower than ~ 8kHz. A lower sample frequency would make the +// resampling code overfill its 16k sample ring buffer. +// +// The end of passband frequency is also limited: +// pass_freq <= 0.9*sample_freq/2 + +// E.g. for a 44.1kHz sampling rate the end of passband frequency is limited +// to slightly below 20kHz. This constraint ensures that the FIR table is +// not overfilled. +// ---------------------------------------------------------------------------- +bool SIDFP::set_sampling_parameters(float clock_freq, sampling_method method, + float sample_freq, float pass_freq) +{ + clock_frequency = clock_freq; + sampling = method; + + filter.set_clock_frequency(clock_freq); + extfilt.set_clock_frequency(clock_freq); + adjust_sampling_frequency(sample_freq); + + sample_offset = 0; + sample_prev = 0; + + // FIR initialization is only necessary for resampling. + if (method != SAMPLE_RESAMPLE_INTERPOLATE) + { + delete[] sample; + delete[] fir; + sample = 0; + fir = 0; + return true; + } + + const int bits = 16; + + if (pass_freq > 20000) + pass_freq = 20000; + if (2*pass_freq/sample_freq > 0.9) + pass_freq = 0.9f*sample_freq/2; + + // 16 bits -> -96dB stopband attenuation. + const double A = -20*log10(1.0/(1 << bits)); + + // For calculation of beta and N see the reference for the kaiserord + // function in the MATLAB Signal Processing Toolbox: + // http://www.mathworks.com/access/helpdesk/help/toolbox/signal/kaiserord.html + const double beta = 0.1102*(A - 8.7); + const double I0beta = I0(beta); + + double f_samples_per_cycle = sample_freq/clock_freq; + double f_cycles_per_sample = clock_freq/sample_freq; + + /* This code utilizes the fact that aliasing back to 20 kHz from + * sample_freq/2 is inaudible. This allows us to define a passband + * wider than normally. We might also consider aliasing back to pass_freq, + * but as this can be less than 20 kHz, it might become audible... */ + double aliasing_allowance = sample_freq / 2 - 20000; + if (aliasing_allowance < 0) + aliasing_allowance = 0; + + double transition_bandwidth = sample_freq/2 - pass_freq + aliasing_allowance; + { + /* Filter order according to Kaiser's paper. */ + + int N = (int) ((A - 7.95)/(2 * M_PI * 2.285 * transition_bandwidth/sample_freq) + 0.5); + N += N & 1; + + // The filter length is equal to the filter order + 1. + // The filter length must be an odd number (sinc is symmetric about x = 0). + fir_N = int(N*f_cycles_per_sample) + 1; + fir_N |= 1; + + // Check whether the sample ring buffer would overfill. + if (fir_N > RINGSIZE - 1) + return false; + + /* Error is bound by 1.234 / L^2 */ + fir_RES = (int) (sqrt(1.234 * (1 << bits)) / f_cycles_per_sample + 0.5); + } + + // Allocate memory for FIR tables. + delete[] fir; + fir = new float[fir_N*fir_RES]; + + // The cutoff frequency is midway through the transition band. + double wc = (pass_freq + transition_bandwidth/2) / sample_freq * M_PI * 2; + + // Calculate fir_RES FIR tables for linear interpolation. + for (int i = 0; i < fir_RES; i++) { + double j_offset = double(i)/fir_RES; + // Calculate FIR table. This is the sinc function, weighted by the + // Kaiser window. + for (int j = 0; j < fir_N; j ++) { + double jx = j - fir_N/2. - j_offset; + double wt = wc*jx/f_cycles_per_sample; + double temp = jx/(fir_N/2); + double Kaiser = + fabs(temp) <= 1 ? I0(beta*sqrt(1 - temp*temp))/I0beta : 0; + double sincwt = + fabs(wt) >= 1e-8 ? sin(wt)/wt : 1; + fir[i * fir_N + j] = (float) (f_samples_per_cycle*wc/M_PI*sincwt*Kaiser); + } + } + + // Allocate sample buffer. + if (!sample) { + sample = new float[RINGSIZE*2]; + } + // Clear sample buffer. + for (int j = 0; j < RINGSIZE*2; j++) { + sample[j] = 0; + } + sample_index = 0; + + return true; +} + +// ---------------------------------------------------------------------------- +// Adjustment of SID sampling frequency. +// +// In some applications, e.g. a C64 emulator, it can be desirable to +// synchronize sound with a timer source. This is supported by adjustment of +// the SID sampling frequency. +// +// NB! Adjustment of the sampling frequency may lead to noticeable shifts in +// frequency, and should only be used for interactive applications. Note also +// that any adjustment of the sampling frequency will change the +// characteristics of the resampling filter, since the filter is not rebuilt. +// ---------------------------------------------------------------------------- +void SIDFP::adjust_sampling_frequency(float sample_freq) +{ + cycles_per_sample = clock_frequency/sample_freq; +} + +void SIDFP::age_bus_value(cycle_count n) { + if (bus_value_ttl != 0) { + bus_value_ttl -= n; + if (bus_value_ttl <= 0) { + bus_value = 0; + bus_value_ttl = 0; + } + } +} + +// ---------------------------------------------------------------------------- +// SID clocking - 1 cycle. +// ---------------------------------------------------------------------------- +void SIDFP::clock() +{ + int i; + + // Clock amplitude modulators. + for (i = 0; i < 3; i++) { + voice[i].envelope.clock(); + } + + // Clock oscillators. + for (i = 0; i < 3; i++) { + voice[i].wave.clock(); + } + + // Synchronize oscillators. + for (i = 0; i < 3; i++) { + voice[i].wave.synchronize(); + } + + // Clock filter. + extfilt.clock(filter.clock(voice[0].output(), voice[1].output(), voice[2].output(), ext_in)); +} + +// ---------------------------------------------------------------------------- +// SID clocking with audio sampling. +// Fixpoint arithmetics is used. +// +// The example below shows how to clock the SID a specified amount of cycles +// while producing audio output: +// +// while (delta_t) { +// bufindex += sid.clock(delta_t, buf + bufindex, buflength - bufindex); +// write(dsp, buf, bufindex*2); +// bufindex = 0; +// } +// +// ---------------------------------------------------------------------------- +int SIDFP::clock(cycle_count& delta_t, short* buf, int n, int interleave) +{ + /* XXX I assume n is generally large enough for delta_t here... */ + age_bus_value(delta_t); + int res; + switch (sampling) { + default: + case SAMPLE_INTERPOLATE: + res = clock_interpolate(delta_t, buf, n, interleave); + break; + case SAMPLE_RESAMPLE_INTERPOLATE: + res = clock_resample_interpolate(delta_t, buf, n, interleave); + break; + } + + filter.nuke_denormals(); + extfilt.nuke_denormals(); + + return res; +} + +// ---------------------------------------------------------------------------- +// SID clocking with audio sampling - cycle based with linear sample +// interpolation. +// +// Here the chip is clocked every cycle. This yields higher quality +// sound since the samples are linearly interpolated, and since the +// external filter attenuates frequencies above 16kHz, thus reducing +// sampling noise. +// ---------------------------------------------------------------------------- +RESID_INLINE +int SIDFP::clock_interpolate(cycle_count& delta_t, short* buf, int n, + int interleave) +{ + int s = 0; + int i; + + for (;;) { + float next_sample_offset = sample_offset + cycles_per_sample; + int delta_t_sample = (int) next_sample_offset; + if (delta_t_sample > delta_t) { + break; + } + if (s >= n) { + return s; + } + for (i = 0; i < delta_t_sample - 1; i++) { + clock(); + } + if (i < delta_t_sample) { + sample_prev = output(); + clock(); + } + + delta_t -= delta_t_sample; + sample_offset = next_sample_offset - delta_t_sample; + + float sample_now = output(); + int v = (int)(sample_prev + (sample_offset * (sample_now - sample_prev))); + // Saturated arithmetics to guard against 16 bit sample overflow. + const int half = 1 << 15; + if (v >= half) { + v = half - 1; + } + else if (v < -half) { + v = -half; + } + buf[s++*interleave] = v; + sample_prev = sample_now; + } + + for (i = 0; i < delta_t - 1; i++) { + clock(); + } + if (i < delta_t) { + sample_prev = output(); + clock(); + } + sample_offset -= delta_t; + delta_t = 0; + return s; +} + +// ---------------------------------------------------------------------------- +// SID clocking with audio sampling - cycle based with audio resampling. +// +// This is the theoretically correct (and computationally intensive) audio +// sample generation. The samples are generated by resampling to the specified +// sampling frequency. The work rate is inversely proportional to the +// percentage of the bandwidth allocated to the filter transition band. +// +// This implementation is based on the paper "A Flexible Sampling-Rate +// Conversion Method", by J. O. Smith and P. Gosset, or rather on the +// expanded tutorial on the "Digital Audio Resampling Home Page": +// http://www-ccrma.stanford.edu/~jos/resample/ +// +// By building shifted FIR tables with samples according to the +// sampling frequency, this implementation dramatically reduces the +// computational effort in the filter convolutions, without any loss +// of accuracy. The filter convolutions are also vectorizable on +// current hardware. +// +// Further possible optimizations are: +// * An equiripple filter design could yield a lower filter order, see +// http://www.mwrf.com/Articles/ArticleID/7229/7229.html +// * The Convolution Theorem could be used to bring the complexity of +// convolution down from O(n*n) to O(n*log(n)) using the Fast Fourier +// Transform, see http://en.wikipedia.org/wiki/Convolution_theorem +// * Simply resampling in two steps can also yield computational +// savings, since the transition band will be wider in the first step +// and the required filter order is thus lower in this step. +// Laurent Ganier has found the optimal intermediate sampling frequency +// to be (via derivation of sum of two steps): +// 2 * pass_freq + sqrt [ 2 * pass_freq * orig_sample_freq +// * (dest_sample_freq - 2 * pass_freq) / dest_sample_freq ] +// +// NB! the result of right shifting negative numbers is really +// implementation dependent in the C++ standard. +// ---------------------------------------------------------------------------- +RESID_INLINE +int SIDFP::clock_resample_interpolate(cycle_count& delta_t, short* buf, int n, + int interleave) +{ + int s = 0; + + for (;;) { + float next_sample_offset = sample_offset + cycles_per_sample; + /* full clocks left to next sample */ + int delta_t_sample = (int) next_sample_offset; + if (delta_t_sample > delta_t || s >= n) + break; + + /* clock forward delta_t_sample samples */ + for (int i = 0; i < delta_t_sample; i++) { + clock(); + sample[sample_index] = sample[sample_index + RINGSIZE] = output(); + ++ sample_index; + sample_index &= RINGSIZE - 1; + } + delta_t -= delta_t_sample; + + /* Phase of the sample in terms of clock, [0 .. 1[. */ + sample_offset = next_sample_offset - (float) delta_t_sample; + + /* find the first of the nearest fir tables close to the phase */ + float fir_offset_rmd = sample_offset * fir_RES; + int fir_offset = (int) fir_offset_rmd; + /* [0 .. 1[ */ + fir_offset_rmd -= (float) fir_offset; + + /* find fir_N most recent samples, plus one extra in case the FIR wraps. */ + float* sample_start = sample + sample_index - fir_N + RINGSIZE - 1; + + float v1 = +#if (RESID_USE_SSE==1) + can_use_sse ? convolve_sse(sample_start, fir + fir_offset*fir_N, fir_N) : +#endif + convolve(sample_start, fir + fir_offset*fir_N, fir_N); + + // Use next FIR table, wrap around to first FIR table using + // previous sample. + if (++ fir_offset == fir_RES) { + fir_offset = 0; + ++ sample_start; + } + float v2 = +#if (RESID_USE_SSE==1) + can_use_sse ? convolve_sse(sample_start, fir + fir_offset*fir_N, fir_N) : +#endif + convolve(sample_start, fir + fir_offset*fir_N, fir_N); + + // Linear interpolation between the sinc tables yields good approximation + // for the exact value. + int v = (int) (v1 + fir_offset_rmd * (v2 - v1)); + + // Saturated arithmetics to guard against 16 bit sample overflow. + const int half = 1 << 15; + if (v >= half) { + v = half - 1; + } + else if (v < -half) { + v = -half; + } + + buf[s ++ * interleave] = v; + } + + /* clock forward delta_t samples */ + for (int i = 0; i < delta_t; i++) { + clock(); + sample[sample_index] = sample[sample_index + RINGSIZE] = output(); + ++ sample_index; + sample_index &= RINGSIZE - 1; + } + sample_offset -= (float) delta_t; + delta_t = 0; + return s; +} diff --git a/src/resid-fp/sid.h b/src/resid-fp/sid.h new file mode 100644 index 000000000..6dad2e0c4 --- /dev/null +++ b/src/resid-fp/sid.h @@ -0,0 +1,130 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// --------------------------------------------------------------------------- + +#ifndef __SID_FP_H__ +#define __SID_FP_H__ + +#include "siddefs-fp.h" +#include "voice.h" +#include "filter.h" +#include "extfilt.h" +#include "pot.h" + +class SIDFP +{ +public: + SIDFP(); + ~SIDFP(); + + static float kinked_dac(const int x, const float nonlinearity, const int bits); + bool sse_enabled() { return can_use_sse; } + + void set_chip_model(chip_model model); + FilterFP& get_filter() { return filter; } + void enable_filter(bool enable); + void enable_external_filter(bool enable); + bool set_sampling_parameters(float clock_freq, sampling_method method, + float sample_freq, float pass_freq = -1); + void adjust_sampling_frequency(float sample_freq); + void set_voice_nonlinearity(float nonlinearity); + + void clock(); + int clock(cycle_count& delta_t, short* buf, int n, int interleave = 1); + void reset(); + + // Read/write registers. + reg8 read(reg8 offset); + void write(reg8 offset, reg8 value); + + // Read/write state. + class State + { + public: + State(); + + char sid_register[0x20]; + + reg8 bus_value; + cycle_count bus_value_ttl; + + reg24 accumulator[3]; + reg24 shift_register[3]; + reg16 rate_counter[3]; + reg16 rate_counter_period[3]; + reg16 exponential_counter[3]; + reg16 exponential_counter_period[3]; + reg8 envelope_counter[3]; + EnvelopeGeneratorFP::State envelope_state[3]; + bool hold_zero[3]; + }; + + State read_state(); + void write_state(const State& state); + + // 16-bit input (EXT IN). + void input(int sample); + + // output in range -32768 .. 32767, not clipped (AUDIO OUT) + float output(); + +protected: + static double I0(double x); + RESID_INLINE int clock_interpolate(cycle_count& delta_t, short* buf, int n, + int interleave); + RESID_INLINE int clock_resample_interpolate(cycle_count& delta_t, short* buf, + int n, int interleave); + RESID_INLINE void age_bus_value(cycle_count); + + VoiceFP voice[3]; + FilterFP filter; + ExternalFilterFP extfilt; + PotentiometerFP potx; + PotentiometerFP poty; + + reg8 bus_value; + cycle_count bus_value_ttl; + + float clock_frequency; + + // External audio input. + float ext_in; + + enum { RINGSIZE = 16384 }; + + // Sampling variables. + sampling_method sampling; + float cycles_per_sample; + float sample_offset; + int sample_index; + int fir_N; + int fir_RES; + + // Linear interpolation helper + float sample_prev; + + // Ring buffer with overflow for contiguous storage of RINGSIZE samples. + float* sample; + + // FIR_RES filter tables (FIR_N*FIR_RES). + float* fir; + + bool can_use_sse; +}; + +#endif // not __SID_H__ diff --git a/src/resid-fp/siddefs-fp.h b/src/resid-fp/siddefs-fp.h new file mode 100644 index 000000000..1f3f72715 --- /dev/null +++ b/src/resid-fp/siddefs-fp.h @@ -0,0 +1,88 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 1999 Dag Lem +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// --------------------------------------------------------------------------- + +#ifndef __SIDDEFS_FP_H__ +#define __SIDDEFS_FP_H__ + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#define M_PI_f 3.14159265358979323846f +#else +#define M_PI_f ((float) M_PI) +#endif + +#ifndef M_LN2 +#define M_LN2 0.69314718055994530942 +#define M_LN2_f 0.69314718055994530942f +#else +#define M_LN2_f ((float) M_LN2) +#endif + +// Define bool, true, and false for C++ compilers that lack these keywords. +#define RESID_HAVE_BOOL 1 + +#if !RESID_HAVE_BOOL +typedef int bool; +const bool true = 1; +const bool false = 0; +#endif + +// We could have used the smallest possible data type for each SID register, +// however this would give a slower engine because of data type conversions. +// An int is assumed to be at least 32 bits (necessary in the types reg24, +// cycle_count, and sound_sample). GNU does not support 16-bit machines +// (GNU Coding Standards: Portability between CPUs), so this should be +// a valid assumption. + +typedef unsigned int reg4; +typedef unsigned int reg8; +typedef unsigned int reg12; +typedef unsigned int reg16; +typedef unsigned int reg24; + +typedef int cycle_count; + +enum chip_model { MOS6581FP=1, MOS8580FP }; + +enum sampling_method { SAMPLE_INTERPOLATE=1, SAMPLE_RESAMPLE_INTERPOLATE }; + +extern "C" +{ +#ifndef __VERSION_CC__ +extern const char* resid_version_string; +#else +const char* resid_version_string = VERSION; +#endif +} + +// Inlining on/off. +#define RESID_INLINE inline + +#if defined(__SSE__) || (defined(_MSC_VER) && (_MSC_VER >= 1300)) +#define RESID_USE_SSE 1 +#else +#define RESID_USE_SSE 0 +#endif + +#define HAVE_LOGF +#define HAVE_EXPF +#define HAVE_LOGF_PROTOTYPE +#define HAVE_EXPF_PROTOTYPE + +#endif // not __SIDDEFS_H__ diff --git a/src/resid-fp/siddefs-fp.h.in b/src/resid-fp/siddefs-fp.h.in new file mode 100644 index 000000000..ec44b3619 --- /dev/null +++ b/src/resid-fp/siddefs-fp.h.in @@ -0,0 +1,87 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 1999 Dag Lem +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// --------------------------------------------------------------------------- + +#ifndef __SIDDEFS_FP_H__ +#define __SIDDEFS_FP_H__ + +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#define M_PI_f 3.14159265358979323846f +#else +#define M_PI_f ((float) M_PI) +#endif + +#ifndef M_LN2 +#define M_LN2 0.69314718055994530942 +#define M_LN2_f 0.69314718055994530942f +#else +#define M_LN2_f ((float) M_LN2) +#endif + +// Define bool, true, and false for C++ compilers that lack these keywords. +#define RESID_HAVE_BOOL @RESID_HAVE_BOOL@ + +#if !RESID_HAVE_BOOL +typedef int bool; +const bool true = 1; +const bool false = 0; +#endif + +// We could have used the smallest possible data type for each SID register, +// however this would give a slower engine because of data type conversions. +// An int is assumed to be at least 32 bits (necessary in the types reg24, +// cycle_count, and sound_sample). GNU does not support 16-bit machines +// (GNU Coding Standards: Portability between CPUs), so this should be +// a valid assumption. + +typedef unsigned int reg4; +typedef unsigned int reg8; +typedef unsigned int reg12; +typedef unsigned int reg16; +typedef unsigned int reg24; + +typedef int cycle_count; + +enum chip_model { MOS6581FP=1, MOS8580FP }; + +enum sampling_method { SAMPLE_INTERPOLATE=1, SAMPLE_RESAMPLE_INTERPOLATE }; + +extern "C" +{ +#ifndef __VERSION_CC__ +extern const char* resid_version_string; +#else +const char* resid_version_string = VERSION; +#endif +} + +// Inlining on/off. +#define RESID_INLINE @RESID_INLINE@ + +#define RESID_USE_SSE @RESID_USE_SSE@ + +#if @HAVE_LOGF_PROTOTYPE@ +#define HAVE_LOGF_PROTOTYPE +#endif + +#if @HAVE_EXPF_PROTOTYPE@ +#define HAVE_EXPF_PROTOTYPE +#endif + +#endif // not __SIDDEFS_H__ diff --git a/src/resid-fp/version.cc b/src/resid-fp/version.cc new file mode 100644 index 000000000..fe9d4595f --- /dev/null +++ b/src/resid-fp/version.cc @@ -0,0 +1,21 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// --------------------------------------------------------------------------- + +#define __VERSION_CC__ +#include "siddefs-fp.h" diff --git a/src/resid-fp/voice.cc b/src/resid-fp/voice.cc new file mode 100644 index 000000000..18c36cc71 --- /dev/null +++ b/src/resid-fp/voice.cc @@ -0,0 +1,102 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// --------------------------------------------------------------------------- + +#define __VOICE_CC__ +#include "voice.h" +#include "sid.h" + +// ---------------------------------------------------------------------------- +// Constructor. +// ---------------------------------------------------------------------------- +VoiceFP::VoiceFP() +{ + nonlinearity = 1.f; + set_chip_model(MOS6581FP); +} + +/* Keep this at 1.f for 8580, there are no 6581-only codepaths in this file! */ +void VoiceFP::set_nonlinearity(float nl) +{ + nonlinearity = nl; + calculate_dac_tables(); +} + +// ---------------------------------------------------------------------------- +// Set chip model. +// ---------------------------------------------------------------------------- +void VoiceFP::set_chip_model(chip_model model) +{ + wave.set_chip_model(model); + + if (model == MOS6581FP) { + /* there is some level from each voice even if the env is down and osc + * is stopped. You can hear this by routing a voice into filter (filter + * should be kept disabled for this) as the master level changes. This + * tunable affects the volume of digis. */ + voice_DC = 0x800 * 0xff; + /* In 8580 the waveforms seem well centered, but on the 6581 there is some + * offset change as envelope grows, indicating that the waveforms are not + * perfectly centered. I estimate the value ~ 0x600 for my R4AR, and ReSID + * has used another measurement technique and got 0x380. */ + wave_zero = 0x600; + calculate_dac_tables(); + } + else { + /* 8580 is thought to be perfect, apart from small negative offset due to + * ext-in mixing, I think. */ + voice_DC = 0; + wave_zero = 0x800; + calculate_dac_tables(); + } +} + +void VoiceFP::calculate_dac_tables() +{ + int i; + for (i = 0; i < 256; i ++) + env_dac[i] = SIDFP::kinked_dac(i, nonlinearity, 8); + for (i = 0; i < 4096; i ++) + voice_dac[i] = SIDFP::kinked_dac(i, nonlinearity, 12) - wave_zero; +} + +// ---------------------------------------------------------------------------- +// Set sync source. +// ---------------------------------------------------------------------------- +void VoiceFP::set_sync_source(VoiceFP* source) +{ + wave.set_sync_source(&source->wave); +} + +// ---------------------------------------------------------------------------- +// Register functions. +// ---------------------------------------------------------------------------- +void VoiceFP::writeCONTROL_REG(reg8 control) +{ + wave.writeCONTROL_REG(control); + envelope.writeCONTROL_REG(control); +} + +// ---------------------------------------------------------------------------- +// SID reset. +// ---------------------------------------------------------------------------- +void VoiceFP::reset() +{ + wave.reset(); + envelope.reset(); +} diff --git a/src/resid-fp/voice.h b/src/resid-fp/voice.h new file mode 100644 index 000000000..3a9e3fc95 --- /dev/null +++ b/src/resid-fp/voice.h @@ -0,0 +1,73 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// --------------------------------------------------------------------------- + +#ifndef __VOICE_H__ +#define __VOICE_H__ + +#include "siddefs-fp.h" +#include "wave.h" +#include "envelope.h" + +class VoiceFP +{ +public: + VoiceFP(); + + void set_chip_model(chip_model model); + void set_sync_source(VoiceFP*); + void reset(); + + void writeCONTROL_REG(reg8); + + // Amplitude modulated waveform output. + // Range [-2048*255, 2047*255]. + RESID_INLINE float output(); + + void set_nonlinearity(float nl); +protected: + void calculate_dac_tables(); + + WaveformGeneratorFP wave; + EnvelopeGeneratorFP envelope; + + // Multiplying D/A DC offset. + float voice_DC, wave_zero, nonlinearity; + + float env_dac[256]; + float voice_dac[4096]; +friend class SIDFP; +}; + +// ---------------------------------------------------------------------------- +// Amplitude modulated waveform output. +// Ideal range [-2048*255, 2047*255]. +// ---------------------------------------------------------------------------- + +RESID_INLINE +float VoiceFP::output() +{ + unsigned int w = wave.output(); + unsigned int e = envelope.output(); + float _w = voice_dac[w]; + float _e = env_dac[e]; + + return _w * _e + voice_DC; +} + +#endif // not __VOICE_H__ diff --git a/src/resid-fp/wave.cc b/src/resid-fp/wave.cc new file mode 100644 index 000000000..018c4e2be --- /dev/null +++ b/src/resid-fp/wave.cc @@ -0,0 +1,151 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// --------------------------------------------------------------------------- + +#define __WAVE_CC__ +#include "wave.h" + +// ---------------------------------------------------------------------------- +// Constructor. +// ---------------------------------------------------------------------------- +WaveformGeneratorFP::WaveformGeneratorFP() +{ + sync_source = this; + + set_chip_model(MOS6581FP); + + reset(); +} + + +// ---------------------------------------------------------------------------- +// Set sync source. +// ---------------------------------------------------------------------------- +void WaveformGeneratorFP::set_sync_source(WaveformGeneratorFP* source) +{ + sync_source = source; + source->sync_dest = this; +} + + +// ---------------------------------------------------------------------------- +// Set chip model. +// ---------------------------------------------------------------------------- +void WaveformGeneratorFP::set_chip_model(chip_model model) +{ + if (model == MOS6581FP) { + wave__ST = wave6581__ST; + wave_P_T = wave6581_P_T; + wave_PS_ = wave6581_PS_; + wave_PST = wave6581_PST; + } + else { + wave__ST = wave8580__ST; + wave_P_T = wave8580_P_T; + wave_PS_ = wave8580_PS_; + wave_PST = wave8580_PST; + } +} + + +// ---------------------------------------------------------------------------- +// Register functions. +// ---------------------------------------------------------------------------- +void WaveformGeneratorFP::writeFREQ_LO(reg8 freq_lo) +{ + freq = (freq & 0xff00) | (freq_lo & 0x00ff); +} + +void WaveformGeneratorFP::writeFREQ_HI(reg8 freq_hi) +{ + freq = ((freq_hi << 8) & 0xff00) | (freq & 0x00ff); +} + +/* The original form was (acc >> 12) >= pw, where truth value is not affected + * by the contents of the low 12 bits. Therefore the lowest bits must be zero + * in the new formulation acc >= (pw << 12). */ +void WaveformGeneratorFP::writePW_LO(reg8 pw_lo) +{ + pw = (pw & 0xf00) | (pw_lo & 0x0ff); + pw_acc_scale = pw << 12; +} + +void WaveformGeneratorFP::writePW_HI(reg8 pw_hi) +{ + pw = ((pw_hi << 8) & 0xf00) | (pw & 0x0ff); + pw_acc_scale = pw << 12; +} + +void WaveformGeneratorFP::writeCONTROL_REG(reg8 control) +{ + waveform = (control >> 4) & 0x0f; + ring_mod = control & 0x04; + sync = control & 0x02; + + reg8 test_next = control & 0x08; + + /* SounDemoN found out that test bit can be used to control the noise + * register. Hear the result in Bojojoing.sid. */ + + // testbit set. invert bit 19 and write it to bit 1 + if (test_next && !test) { + accumulator = 0; + reg24 bit19 = (shift_register >> 19) & 1; + shift_register = (shift_register & 0x7ffffd) | ((bit19^1) << 1); + noise_overwrite_delay = 200000; /* 200 ms, probably too generous? */ + } + // Test bit cleared. + // The accumulator starts counting, and the shift register is reset to + // the value 0x7ffff8. + else if (!test_next && test) { + reg24 bit0 = ((shift_register >> 22) ^ (shift_register >> 17)) & 0x1; + shift_register <<= 1; + shift_register |= bit0; + } + // clear output bits of shift register if noise and other waveforms + // are selected simultaneously + if (waveform > 8) { + shift_register &= 0x7fffff^(1<<22)^(1<<20)^(1<<16)^(1<<13)^(1<<11)^(1<<7)^(1<<4)^(1<<2); + } + + test = test_next; + + /* update noise anyway, just in case the above paths triggered */ + noise_output_cached = outputN___(); +} + +reg8 WaveformGeneratorFP::readOSC() +{ + return output() >> 4; +} + +// ---------------------------------------------------------------------------- +// SID reset. +// ---------------------------------------------------------------------------- +void WaveformGeneratorFP::reset() +{ + accumulator = 0; + previous = 0; + shift_register = 0x7ffffc; + freq = 0; + pw = 0; + pw_acc_scale = 0; + test = 0; + writeCONTROL_REG(0); + msb_rising = false; +} diff --git a/src/resid-fp/wave.h b/src/resid-fp/wave.h new file mode 100644 index 000000000..07d229ba0 --- /dev/null +++ b/src/resid-fp/wave.h @@ -0,0 +1,457 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// --------------------------------------------------------------------------- + +#ifndef __WAVE_H__ +#define __WAVE_H__ + +#include "siddefs-fp.h" + +// ---------------------------------------------------------------------------- +// A 24 bit accumulator is the basis for waveform generation. FREQ is added to +// the lower 16 bits of the accumulator each cycle. +// The accumulator is set to zero when TEST is set, and starts counting +// when TEST is cleared. +// The noise waveform is taken from intermediate bits of a 23 bit shift +// register. This register is clocked by bit 19 of the accumulator. +// ---------------------------------------------------------------------------- +class WaveformGeneratorFP +{ +public: + WaveformGeneratorFP(); + + void set_sync_source(WaveformGeneratorFP*); + void set_chip_model(chip_model model); + + RESID_INLINE void clock(); + RESID_INLINE void synchronize(); + void reset(); + + void writeFREQ_LO(reg8); + void writeFREQ_HI(reg8); + void writePW_LO(reg8); + void writePW_HI(reg8); + void writeCONTROL_REG(reg8); + reg8 readOSC(); + + // 12-bit waveform output. + RESID_INLINE reg12 output(); + +protected: + const WaveformGeneratorFP* sync_source; + WaveformGeneratorFP* sync_dest; + + // Tell whether the accumulator MSB was set high on this cycle. + bool msb_rising; + + reg24 accumulator; + reg24 shift_register; + reg12 previous, noise_output_cached; + int noise_overwrite_delay; + + // Fout = (Fn*Fclk/16777216)Hz + reg16 freq; + // PWout = (PWn/40.95)%, also the same << 12 for direct comparison against acc + reg12 pw; reg24 pw_acc_scale; + + // The control register right-shifted 4 bits; used for output function + // table lookup. + reg8 waveform; + + // The remaining control register bits. + reg8 test; + reg8 ring_mod; + reg8 sync; + // The gate bit is handled by the EnvelopeGenerator. + + // 16 possible combinations of waveforms. + RESID_INLINE reg12 output___T(); + RESID_INLINE reg12 output__S_(); + RESID_INLINE reg12 output__ST(); + RESID_INLINE reg12 output_P__(); + RESID_INLINE reg12 output_P_T(); + RESID_INLINE reg12 output_PS_(); + RESID_INLINE reg12 output_PST(); + RESID_INLINE reg12 outputN___(); + RESID_INLINE reg12 outputN__T(); + RESID_INLINE reg12 outputN_S_(); + RESID_INLINE reg12 outputN_ST(); + RESID_INLINE reg12 outputNP__(); + RESID_INLINE reg12 outputNP_T(); + RESID_INLINE reg12 outputNPS_(); + RESID_INLINE reg12 outputNPST(); + + // Sample data for combinations of waveforms. + static reg8 wave6581__ST[]; + static reg8 wave6581_P_T[]; + static reg8 wave6581_PS_[]; + static reg8 wave6581_PST[]; + + static reg8 wave8580__ST[]; + static reg8 wave8580_P_T[]; + static reg8 wave8580_PS_[]; + static reg8 wave8580_PST[]; + + reg8* wave__ST; + reg8* wave_P_T; + reg8* wave_PS_; + reg8* wave_PST; + +friend class VoiceFP; +friend class SIDFP; +}; + +// ---------------------------------------------------------------------------- +// SID clocking - 1 cycle. +// ---------------------------------------------------------------------------- +RESID_INLINE +void WaveformGeneratorFP::clock() +{ + /* no digital operation if test bit is set. Only emulate analog fade. */ + if (test) { + if (noise_overwrite_delay != 0) { + if (-- noise_overwrite_delay == 0) { + shift_register |= 0x7ffffc; + noise_output_cached = outputN___(); + } + } + return; + } + + reg24 accumulator_prev = accumulator; + + // Calculate new accumulator value; + accumulator += freq; + accumulator &= 0xffffff; + + // Check whether the MSB became set high. This is used for synchronization. + msb_rising = !(accumulator_prev & 0x800000) && (accumulator & 0x800000); + + // Shift noise register once for each time accumulator bit 19 is set high. + if (!(accumulator_prev & 0x080000) && (accumulator & 0x080000)) { + reg24 bit0 = ((shift_register >> 22) ^ (shift_register >> 17)) & 0x1; + shift_register <<= 1; + // optimization: fall into the bit bucket + //shift_register &= 0x7fffff; + shift_register |= bit0; + + /* since noise changes relatively infrequently, we'll avoid the relatively + * expensive bit shuffling at output time. */ + noise_output_cached = outputN___(); + } + + // clear output bits of shift register if noise and other waveforms + // are selected simultaneously + if (waveform > 8) { + shift_register &= 0x7fffff^(1<<22)^(1<<20)^(1<<16)^(1<<13)^(1<<11)^(1<<7)^(1<<4)^(1<<2); + noise_output_cached = outputN___(); + } +} + +// ---------------------------------------------------------------------------- +// Synchronize oscillators. +// This must be done after all the oscillators have been clock()'ed since the +// oscillators operate in parallel. +// Note that the oscillators must be clocked exactly on the cycle when the +// MSB is set high for hard sync to operate correctly. See SID::clock(). +// ---------------------------------------------------------------------------- +RESID_INLINE +void WaveformGeneratorFP::synchronize() +{ + // A special case occurs when a sync source is synced itself on the same + // cycle as when its MSB is set high. In this case the destination will + // not be synced. This has been verified by sampling OSC3. + if (msb_rising && sync_dest->sync && !(sync && sync_source->msb_rising)) { + sync_dest->accumulator = 0; + } +} + + +// ---------------------------------------------------------------------------- +// Output functions. +// NB! The output from SID 8580 is delayed one cycle compared to SID 6581, +// this is not modeled. +// ---------------------------------------------------------------------------- + +// Triangle: +// The upper 12 bits of the accumulator are used. +// The MSB is used to create the falling edge of the triangle by inverting +// the lower 11 bits. The MSB is thrown away and the lower 11 bits are +// left-shifted (half the resolution, full amplitude). +// Ring modulation substitutes the MSB with MSB EOR sync_source MSB. +// +RESID_INLINE +reg12 WaveformGeneratorFP::output___T() +{ + reg24 msb = (ring_mod ? accumulator ^ sync_source->accumulator : accumulator) + & 0x800000; + return ((msb ? ~accumulator : accumulator) >> 11) & 0xfff; +} + +// Sawtooth: +// The output is identical to the upper 12 bits of the accumulator. +// +RESID_INLINE +reg12 WaveformGeneratorFP::output__S_() +{ + return accumulator >> 12; +} + +// Pulse: +// The upper 12 bits of the accumulator are used. +// These bits are compared to the pulse width register by a 12 bit digital +// comparator; output is either all one or all zero bits. +// NB! The output is actually delayed one cycle after the compare. +// This is not modeled. +// +// The test bit, when set to one, holds the pulse waveform output at 0xfff +// regardless of the pulse width setting. +// +RESID_INLINE +reg12 WaveformGeneratorFP::output_P__() +{ + return (test || accumulator >= pw_acc_scale) ? 0xfff : 0x000; +} + +// Noise: +// The noise output is taken from intermediate bits of a 23-bit shift register +// which is clocked by bit 19 of the accumulator. +// NB! The output is actually delayed 2 cycles after bit 19 is set high. +// This is not modeled. +// +// Operation: Calculate EOR result, shift register, set bit 0 = result. +// +// ----------------------->--------------------- +// | | +// ----EOR---- | +// | | | +// 2 2 2 1 1 1 1 1 1 1 1 1 1 | +// Register bits: 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 <--- +// | | | | | | | | +// OSC3 bits : 7 6 5 4 3 2 1 0 +// +// Since waveform output is 12 bits the output is left-shifted 4 times. +// +RESID_INLINE +reg12 WaveformGeneratorFP::outputN___() +{ + return + ((shift_register & 0x400000) >> 11) | + ((shift_register & 0x100000) >> 10) | + ((shift_register & 0x010000) >> 7) | + ((shift_register & 0x002000) >> 5) | + ((shift_register & 0x000800) >> 4) | + ((shift_register & 0x000080) >> 1) | + ((shift_register & 0x000010) << 1) | + ((shift_register & 0x000004) << 2); +} + +// Combined waveforms: +// By combining waveforms, the bits of each waveform are effectively short +// circuited. A zero bit in one waveform will result in a zero output bit +// (thus the infamous claim that the waveforms are AND'ed). +// However, a zero bit in one waveform will also affect the neighboring bits +// in the output. The reason for this has not been determined. +// +// Example: +// +// 1 1 +// Bit # 1 0 9 8 7 6 5 4 3 2 1 0 +// ----------------------- +// Sawtooth 0 0 0 1 1 1 1 1 1 0 0 0 +// +// Triangle 0 0 1 1 1 1 1 1 0 0 0 0 +// +// AND 0 0 0 1 1 1 1 1 0 0 0 0 +// +// Output 0 0 0 0 1 1 1 0 0 0 0 0 +// +// +// This behavior would be quite difficult to model exactly, since the SID +// in this case does not act as a digital state machine. Tests show that minor +// (1 bit) differences can actually occur in the output from otherwise +// identical samples from OSC3 when waveforms are combined. To further +// complicate the situation the output changes slightly with time (more +// neighboring bits are successively set) when the 12-bit waveform +// registers are kept unchanged. +// +// It is probably possible to come up with a valid model for the +// behavior, however this would be far too slow for practical use since it +// would have to be based on the mutual influence of individual bits. +// +// The output is instead approximated by using the upper bits of the +// accumulator as an index to look up the combined output in a table +// containing actual combined waveform samples from OSC3. +// These samples are 8 bit, so 4 bits of waveform resolution is lost. +// All OSC3 samples are taken with FREQ=0x1000, adding a 1 to the upper 12 +// bits of the accumulator each cycle for a sample period of 4096 cycles. +// +// Sawtooth+Triangle: +// The sawtooth output is used to look up an OSC3 sample. +// +// Pulse+Triangle: +// The triangle output is right-shifted and used to look up an OSC3 sample. +// The sample is output if the pulse output is on. +// The reason for using the triangle output as the index is to handle ring +// modulation. Only the first half of the sample is used, which should be OK +// since the triangle waveform has half the resolution of the accumulator. +// +// Pulse+Sawtooth: +// The sawtooth output is used to look up an OSC3 sample. +// The sample is output if the pulse output is on. +// +// Pulse+Sawtooth+Triangle: +// The sawtooth output is used to look up an OSC3 sample. +// The sample is output if the pulse output is on. +// +RESID_INLINE +reg12 WaveformGeneratorFP::output__ST() +{ + return wave__ST[output__S_()] << 4; +} + +RESID_INLINE +reg12 WaveformGeneratorFP::output_P_T() +{ + /* ring modulation does something odd with this waveform. But I don't know + * how to emulate it. */ + return (wave_P_T[output___T() >> 1] << 4) & output_P__(); +} + +RESID_INLINE +reg12 WaveformGeneratorFP::output_PS_() +{ + return (wave_PS_[output__S_()] << 4) & output_P__(); +} + +RESID_INLINE +reg12 WaveformGeneratorFP::output_PST() +{ + return (wave_PST[output__S_()] << 4) & output_P__(); +} + +// Combined waveforms including noise: +// All waveform combinations including noise output zero after a few cycles. +// NB! The effects of such combinations are not fully explored. It is claimed +// that the shift register may be filled with zeroes and locked up, which +// seems to be true. +// We have not attempted to model this behavior, suffice to say that +// there is very little audible output from waveform combinations including +// noise. We hope that nobody is actually using it. +// +RESID_INLINE +reg12 WaveformGeneratorFP::outputN__T() +{ + return 0; +} + +RESID_INLINE +reg12 WaveformGeneratorFP::outputN_S_() +{ + return 0; +} + +RESID_INLINE +reg12 WaveformGeneratorFP::outputN_ST() +{ + return 0; +} + +RESID_INLINE +reg12 WaveformGeneratorFP::outputNP__() +{ + return 0; +} + +RESID_INLINE +reg12 WaveformGeneratorFP::outputNP_T() +{ + return 0; +} + +RESID_INLINE +reg12 WaveformGeneratorFP::outputNPS_() +{ + return 0; +} + +RESID_INLINE +reg12 WaveformGeneratorFP::outputNPST() +{ + return 0; +} + +// ---------------------------------------------------------------------------- +// Select one of 16 possible combinations of waveforms. +// ---------------------------------------------------------------------------- +RESID_INLINE +reg12 WaveformGeneratorFP::output() +{ + switch (waveform) { + case 0x1: + previous = output___T(); + break; + case 0x2: + previous = output__S_(); + break; + case 0x3: + previous = output__ST(); + break; + case 0x4: + previous = output_P__(); + break; + case 0x5: + previous = output_P_T(); + break; + case 0x6: + previous = output_PS_(); + break; + case 0x7: + previous = output_PST(); + break; + case 0x8: + previous = noise_output_cached; + break; + case 0x9: + previous = outputN__T(); + break; + case 0xa: + previous = outputN_S_(); + break; + case 0xb: + previous = outputN_ST(); + break; + case 0xc: + previous = outputNP__(); + break; + case 0xd: + previous = outputNP_T(); + break; + case 0xe: + previous = outputNPS_(); + break; + case 0xf: + previous = outputNPST(); + break; + default: + break; + } + return previous; +} + +#endif // not __WAVE_H__ diff --git a/src/resid-fp/wave6581_PST.cc b/src/resid-fp/wave6581_PST.cc new file mode 100644 index 000000000..19d2126ef --- /dev/null +++ b/src/resid-fp/wave6581_PST.cc @@ -0,0 +1,536 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// --------------------------------------------------------------------------- + +#include "wave.h" + +reg8 WaveformGeneratorFP::wave6581_PST[] = +{ +/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x378: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, +/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x528: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x530: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x538: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x540: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x548: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x550: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x558: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x560: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x568: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x570: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x578: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x580: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x588: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x590: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x598: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x600: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x608: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x610: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x618: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x620: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x628: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x630: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x638: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x640: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x648: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x650: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x658: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x660: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x668: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x670: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x678: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x680: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x688: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x690: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x698: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x700: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x708: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x710: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x718: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x720: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x728: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x730: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x738: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x740: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x748: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x750: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x758: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x760: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x768: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x770: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x778: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x780: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x788: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x790: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x798: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, +/* 0x7f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, +/* 0x7f8: */ 0x00, 0x00, 0x00, 0x78, 0x78, 0x7e, 0x7f, 0x7f, +/* 0x800: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x808: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x810: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x818: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x820: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x828: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x830: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x838: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x840: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x848: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x850: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x858: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x860: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x868: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x870: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x878: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x880: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x888: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x890: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x898: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x900: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x908: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x910: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x918: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x920: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x928: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x930: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x938: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x940: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x948: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x950: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x958: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x960: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x968: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x970: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x978: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x980: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x988: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x990: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x998: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, +/* 0xc00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xea0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xea8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xeb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xeb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xec0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xec8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xed0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xed8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xee0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xee8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xef0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xef8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, +/* 0xff0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, +/* 0xff8: */ 0x00, 0x00, 0x00, 0x78, 0x78, 0x7e, 0x7f, 0x7f, +}; diff --git a/src/resid-fp/wave6581_PST.dat b/src/resid-fp/wave6581_PST.dat new file mode 100644 index 000000000..5afe75e22 Binary files /dev/null and b/src/resid-fp/wave6581_PST.dat differ diff --git a/src/resid-fp/wave6581_PS_.cc b/src/resid-fp/wave6581_PS_.cc new file mode 100644 index 000000000..bf133e542 --- /dev/null +++ b/src/resid-fp/wave6581_PS_.cc @@ -0,0 +1,536 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// --------------------------------------------------------------------------- + +#include "wave.h" + +reg8 WaveformGeneratorFP::wave6581_PS_[] = +{ +/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, +/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1f, +/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, +/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x378: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, +/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, +/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, +/* 0x3e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, +/* 0x3f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3f, +/* 0x3f8: */ 0x00, 0x30, 0x38, 0x3f, 0x3e, 0x3f, 0x3f, 0x3f, +/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, +/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x528: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x530: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x538: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x540: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x548: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x550: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x558: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x560: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x568: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x570: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x578: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, +/* 0x580: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x588: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x590: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x598: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, +/* 0x5c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, +/* 0x5e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, +/* 0x5f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x5f, +/* 0x5f8: */ 0x00, 0x40, 0x40, 0x5f, 0x5c, 0x5f, 0x5f, 0x5f, +/* 0x600: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x608: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x610: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x618: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x620: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x628: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x630: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x638: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x640: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x648: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x650: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x658: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x660: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x668: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x670: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x678: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, +/* 0x680: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x688: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x690: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x698: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x6b, +/* 0x6c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x6d, +/* 0x6e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x6e8: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x40, 0x6e, +/* 0x6f0: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x60, 0x60, 0x6f, +/* 0x6f8: */ 0x00, 0x60, 0x60, 0x6f, 0x60, 0x6f, 0x6f, 0x6f, +/* 0x700: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x708: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x710: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x718: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x720: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x728: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x730: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x738: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x60, 0x73, +/* 0x740: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x748: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x750: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x758: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x60, 0x60, 0x75, +/* 0x760: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0x768: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x76, +/* 0x770: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x77, +/* 0x778: */ 0x00, 0x70, 0x70, 0x77, 0x70, 0x77, 0x77, 0x77, +/* 0x780: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x788: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0x790: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0x798: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x79, +/* 0x7a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0x7a8: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x70, 0x70, 0x7a, +/* 0x7b0: */ 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x70, 0x7b, +/* 0x7b8: */ 0x40, 0x70, 0x70, 0x7b, 0x78, 0x7b, 0x7b, 0x7b, +/* 0x7c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, +/* 0x7c8: */ 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x70, 0x7c, +/* 0x7d0: */ 0x00, 0x00, 0x00, 0x70, 0x40, 0x70, 0x70, 0x7d, +/* 0x7d8: */ 0x40, 0x70, 0x78, 0x7d, 0x78, 0x7d, 0x7d, 0x7d, +/* 0x7e0: */ 0x00, 0x40, 0x40, 0x78, 0x60, 0x78, 0x78, 0x7e, +/* 0x7e8: */ 0x60, 0x78, 0x78, 0x7e, 0x7c, 0x7e, 0x7e, 0x7e, +/* 0x7f0: */ 0x70, 0x7c, 0x7c, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, +/* 0x7f8: */ 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, +/* 0x800: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x808: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x810: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x818: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x820: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x828: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x830: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x838: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x840: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x848: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x850: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x858: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x860: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x868: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x870: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x878: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x880: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x888: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x890: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x898: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, +/* 0x900: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x908: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x910: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x918: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x920: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x928: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x930: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x938: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x940: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x948: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x950: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x958: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x960: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x968: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x970: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x978: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x980: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x988: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x990: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x998: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x9c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x1f, +/* 0xa00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0xa80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xac0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2f, +/* 0xb00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, +/* 0xb80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, +/* 0xbc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, +/* 0xbe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, +/* 0xbf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x3f, +/* 0xbf8: */ 0x00, 0x30, 0x38, 0x3f, 0x3e, 0x3f, 0x3f, 0x3f, +/* 0xc00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0xc80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4f, +/* 0xd00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x57, +/* 0xd80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5b, +/* 0xdc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5d, +/* 0xde0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, +/* 0xdf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x5f, +/* 0xdf8: */ 0x00, 0x40, 0x40, 0x5f, 0x5c, 0x5f, 0x5f, 0x5f, +/* 0xe00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x67, +/* 0xe80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xea0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xea8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xeb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xeb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x6b, +/* 0xec0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xec8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xed0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xed8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x6d, +/* 0xee0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0xee8: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x40, 0x6e, +/* 0xef0: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x60, 0x60, 0x6f, +/* 0xef8: */ 0x00, 0x60, 0x60, 0x6f, 0x60, 0x6f, 0x6f, 0x6f, +/* 0xf00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0xf20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0xf30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0xf38: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x60, 0x73, +/* 0xf40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0xf50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0xf58: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x60, 0x60, 0x75, +/* 0xf60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0xf68: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x76, +/* 0xf70: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x77, +/* 0xf78: */ 0x00, 0x70, 0x70, 0x77, 0x70, 0x77, 0x77, 0x77, +/* 0xf80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0xf90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0xf98: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x79, +/* 0xfa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0xfa8: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x70, 0x70, 0x7a, +/* 0xfb0: */ 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x70, 0x7b, +/* 0xfb8: */ 0x40, 0x70, 0x70, 0x7b, 0x78, 0x7b, 0x7b, 0x7b, +/* 0xfc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x70, +/* 0xfc8: */ 0x00, 0x00, 0x00, 0x70, 0x00, 0x70, 0x70, 0x7c, +/* 0xfd0: */ 0x00, 0x00, 0x00, 0x70, 0x40, 0x70, 0x70, 0x7d, +/* 0xfd8: */ 0x40, 0x70, 0x78, 0x7d, 0x78, 0x7d, 0x7d, 0x7d, +/* 0xfe0: */ 0x00, 0x40, 0x40, 0x78, 0x60, 0x78, 0x78, 0x7e, +/* 0xfe8: */ 0x60, 0x78, 0x78, 0x7e, 0x7c, 0x7e, 0x7e, 0x7e, +/* 0xff0: */ 0x70, 0x7c, 0x7c, 0x7f, 0x7c, 0x7f, 0x7f, 0x7f, +/* 0xff8: */ 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, +}; diff --git a/src/resid-fp/wave6581_PS_.dat b/src/resid-fp/wave6581_PS_.dat new file mode 100644 index 000000000..ea2fb9c53 Binary files /dev/null and b/src/resid-fp/wave6581_PS_.dat differ diff --git a/src/resid-fp/wave6581_P_T.cc b/src/resid-fp/wave6581_P_T.cc new file mode 100644 index 000000000..30736169e --- /dev/null +++ b/src/resid-fp/wave6581_P_T.cc @@ -0,0 +1,536 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// --------------------------------------------------------------------------- + +#include "wave.h" + +reg8 WaveformGeneratorFP::wave6581_P_T[] = +{ +/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x38, 0x3f, +/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f8: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x40, 0x5f, +/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x378: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x60, 0x6f, +/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0x3b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0x3b8: */ 0x00, 0x00, 0x00, 0x60, 0x00, 0x60, 0x70, 0x77, +/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0x3d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x60, +/* 0x3d8: */ 0x00, 0x00, 0x00, 0x70, 0x40, 0x70, 0x70, 0x7b, +/* 0x3e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x70, +/* 0x3e8: */ 0x00, 0x40, 0x40, 0x70, 0x60, 0x70, 0x78, 0x7d, +/* 0x3f0: */ 0x00, 0x40, 0x60, 0x78, 0x60, 0x78, 0x78, 0x7e, +/* 0x3f8: */ 0x70, 0x7c, 0x7c, 0x7f, 0x7e, 0x7f, 0x7f, 0x7f, +/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x4e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x4f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x4f8: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x9f, +/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x528: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x530: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x538: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x540: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x548: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x550: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x558: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x560: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x568: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x570: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x578: */ 0x00, 0x80, 0x80, 0x80, 0x80, 0xa0, 0xa0, 0xaf, +/* 0x580: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x588: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x590: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x598: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x5a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, +/* 0x5b0: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xa0, +/* 0x5b8: */ 0x00, 0x80, 0x80, 0xa0, 0x80, 0xa0, 0xb0, 0xb7, +/* 0x5c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x5c8: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xa0, +/* 0x5d0: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xa0, +/* 0x5d8: */ 0x00, 0x80, 0x80, 0xa0, 0x80, 0xb0, 0xb0, 0xbb, +/* 0x5e0: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0xb0, +/* 0x5e8: */ 0x80, 0x80, 0x80, 0xb0, 0x80, 0xb0, 0xb8, 0xbd, +/* 0x5f0: */ 0x80, 0x80, 0x80, 0xb8, 0xa0, 0xb8, 0xb8, 0xbe, +/* 0x5f8: */ 0xa0, 0xb8, 0xbc, 0xbf, 0xbe, 0xbf, 0xbf, 0xbf, +/* 0x600: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x608: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x610: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x618: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x620: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x628: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x630: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x638: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0, +/* 0x640: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x648: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x650: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x658: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0xc0, +/* 0x660: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x668: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xc0, +/* 0x670: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xc0, +/* 0x678: */ 0x00, 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xcf, +/* 0x680: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x688: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x690: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x698: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xc0, +/* 0x6a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x6a8: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xc0, +/* 0x6b0: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0xc0, 0xc0, +/* 0x6b8: */ 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd0, 0xd7, +/* 0x6c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x6c8: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0xc0, 0xc0, +/* 0x6d0: */ 0x00, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xc0, +/* 0x6d8: */ 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xd0, 0xd0, 0xdb, +/* 0x6e0: */ 0x00, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xd0, +/* 0x6e8: */ 0x80, 0xc0, 0xc0, 0xd0, 0xc0, 0xd0, 0xd8, 0xdd, +/* 0x6f0: */ 0xc0, 0xc0, 0xc0, 0xd0, 0xc0, 0xd8, 0xd8, 0xde, +/* 0x6f8: */ 0xc0, 0xd8, 0xdc, 0xdf, 0xdc, 0xdf, 0xdf, 0xdf, +/* 0x700: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x708: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x710: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x718: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0xc0, 0xc0, 0xe0, +/* 0x720: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x728: */ 0x00, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xe0, +/* 0x730: */ 0x00, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xe0, +/* 0x738: */ 0x80, 0xc0, 0xc0, 0xe0, 0xc0, 0xe0, 0xe0, 0xe7, +/* 0x740: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0xc0, +/* 0x748: */ 0x00, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xe0, +/* 0x750: */ 0x00, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xe0, +/* 0x758: */ 0xc0, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xeb, +/* 0x760: */ 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, +/* 0x768: */ 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xed, +/* 0x770: */ 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe8, 0xe8, 0xee, +/* 0x778: */ 0xe0, 0xe8, 0xec, 0xef, 0xec, 0xef, 0xef, 0xef, +/* 0x780: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0xc0, +/* 0x788: */ 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xf0, +/* 0x790: */ 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, 0xe0, 0xf0, +/* 0x798: */ 0xc0, 0xe0, 0xe0, 0xf0, 0xe0, 0xf0, 0xf0, 0xf3, +/* 0x7a0: */ 0x80, 0xc0, 0xc0, 0xe0, 0xc0, 0xe0, 0xe0, 0xf0, +/* 0x7a8: */ 0xc0, 0xe0, 0xe0, 0xf0, 0xe0, 0xf0, 0xf0, 0xf5, +/* 0x7b0: */ 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf6, +/* 0x7b8: */ 0xf0, 0xf0, 0xf4, 0xf7, 0xf4, 0xf7, 0xf7, 0xf7, +/* 0x7c0: */ 0xc0, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, +/* 0x7c8: */ 0xe0, 0xe0, 0xe0, 0xf8, 0xf0, 0xf8, 0xf8, 0xf9, +/* 0x7d0: */ 0xe0, 0xf0, 0xf0, 0xf8, 0xf0, 0xf8, 0xf8, 0xfa, +/* 0x7d8: */ 0xf0, 0xf8, 0xf8, 0xfb, 0xf8, 0xfb, 0xfb, 0xfb, +/* 0x7e0: */ 0xe0, 0xf0, 0xf0, 0xf8, 0xf0, 0xf8, 0xfc, 0xfc, +/* 0x7e8: */ 0xf8, 0xfc, 0xfc, 0xfd, 0xfc, 0xfd, 0xfd, 0xfd, +/* 0x7f0: */ 0xf8, 0xfc, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +/* 0x7f8: */ 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +/* 0x800: */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, +/* 0x808: */ 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfc, 0xf8, +/* 0x810: */ 0xfd, 0xfd, 0xfd, 0xfc, 0xfd, 0xfc, 0xfc, 0xf8, +/* 0x818: */ 0xfc, 0xfc, 0xfc, 0xf0, 0xf8, 0xf0, 0xf0, 0xe0, +/* 0x820: */ 0xfb, 0xfb, 0xfb, 0xf8, 0xfb, 0xf8, 0xf8, 0xf0, +/* 0x828: */ 0xfa, 0xf8, 0xf8, 0xf0, 0xf8, 0xf0, 0xf0, 0xe0, +/* 0x830: */ 0xf9, 0xf8, 0xf8, 0xf0, 0xf8, 0xf0, 0xe0, 0xe0, +/* 0x838: */ 0xf0, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, 0xc0, 0xc0, +/* 0x840: */ 0xf7, 0xf7, 0xf7, 0xf4, 0xf7, 0xf4, 0xf0, 0xf0, +/* 0x848: */ 0xf6, 0xf0, 0xf0, 0xf0, 0xf0, 0xe0, 0xe0, 0xe0, +/* 0x850: */ 0xf5, 0xf0, 0xf0, 0xe0, 0xf0, 0xe0, 0xe0, 0xc0, +/* 0x858: */ 0xf0, 0xe0, 0xe0, 0xc0, 0xe0, 0xc0, 0xc0, 0x80, +/* 0x860: */ 0xf3, 0xf0, 0xf0, 0xe0, 0xf0, 0xe0, 0xe0, 0xc0, +/* 0x868: */ 0xf0, 0xe0, 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, +/* 0x870: */ 0xf0, 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80, +/* 0x878: */ 0xc0, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, +/* 0x880: */ 0xef, 0xef, 0xef, 0xec, 0xef, 0xec, 0xe8, 0xe0, +/* 0x888: */ 0xee, 0xe8, 0xe8, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, +/* 0x890: */ 0xed, 0xe8, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, +/* 0x898: */ 0xe0, 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80, +/* 0x8a0: */ 0xeb, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, 0xc0, 0xc0, +/* 0x8a8: */ 0xe0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x00, +/* 0x8b0: */ 0xe0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x00, +/* 0x8b8: */ 0xc0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0x8c0: */ 0xe7, 0xe0, 0xe0, 0xc0, 0xe0, 0xc0, 0xc0, 0x80, +/* 0x8c8: */ 0xe0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x00, +/* 0x8d0: */ 0xe0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x00, +/* 0x8d8: */ 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e0: */ 0xe0, 0xc0, 0xc0, 0x80, 0x80, 0x00, 0x00, 0x00, +/* 0x8e8: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f0: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x900: */ 0xdf, 0xdf, 0xdf, 0xdc, 0xdf, 0xdc, 0xd8, 0xc0, +/* 0x908: */ 0xde, 0xd8, 0xd8, 0xc0, 0xd8, 0xc0, 0xc0, 0xc0, +/* 0x910: */ 0xdd, 0xd8, 0xd0, 0xc0, 0xd0, 0xc0, 0xc0, 0x80, +/* 0x918: */ 0xd0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x00, +/* 0x920: */ 0xdb, 0xd0, 0xd0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, +/* 0x928: */ 0xc0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x00, +/* 0x930: */ 0xc0, 0xc0, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, +/* 0x938: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x940: */ 0xd7, 0xd0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, +/* 0x948: */ 0xc0, 0xc0, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0x950: */ 0xc0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0x958: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x960: */ 0xc0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0x968: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x970: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x978: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x980: */ 0xcf, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80, 0x00, +/* 0x988: */ 0xc0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0x990: */ 0xc0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0x998: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a0: */ 0xc0, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c0: */ 0xc0, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa00: */ 0xbf, 0xbf, 0xbf, 0xbe, 0xbf, 0xbc, 0xbc, 0xa0, +/* 0xa08: */ 0xbe, 0xbc, 0xb8, 0xa0, 0xb8, 0xa0, 0x80, 0x80, +/* 0xa10: */ 0xbd, 0xb8, 0xb0, 0x80, 0xb0, 0x80, 0x80, 0x80, +/* 0xa18: */ 0xb0, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, +/* 0xa20: */ 0xbb, 0xb0, 0xb0, 0x80, 0xa0, 0x80, 0x80, 0x00, +/* 0xa28: */ 0xa0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0xa30: */ 0xa0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0xa38: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa40: */ 0xb7, 0xb0, 0xa0, 0x80, 0xa0, 0x80, 0x80, 0x00, +/* 0xa48: */ 0xa0, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0xa50: */ 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa60: */ 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa80: */ 0xaf, 0xa0, 0xa0, 0x80, 0x80, 0x80, 0x80, 0x00, +/* 0xa88: */ 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa90: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa0: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac0: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb00: */ 0x9f, 0x90, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, +/* 0xb08: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb10: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb20: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb40: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb80: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc00: */ 0x7f, 0x7f, 0x7f, 0x7e, 0x7f, 0x7c, 0x7c, 0x70, +/* 0xc08: */ 0x7e, 0x7c, 0x78, 0x60, 0x78, 0x60, 0x60, 0x00, +/* 0xc10: */ 0x7d, 0x78, 0x78, 0x60, 0x70, 0x40, 0x40, 0x00, +/* 0xc18: */ 0x70, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc20: */ 0x7b, 0x78, 0x70, 0x40, 0x70, 0x40, 0x00, 0x00, +/* 0xc28: */ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc30: */ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc40: */ 0x77, 0x70, 0x70, 0x00, 0x60, 0x00, 0x00, 0x00, +/* 0xc48: */ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc50: */ 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc60: */ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc80: */ 0x6f, 0x60, 0x60, 0x00, 0x60, 0x00, 0x00, 0x00, +/* 0xc88: */ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc90: */ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd00: */ 0x5f, 0x58, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, +/* 0xd08: */ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe00: */ 0x3f, 0x3c, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xea0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xea8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xeb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xeb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xec0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xec8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xed0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xed8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xee0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xee8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xef0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xef8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xff0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xff8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; diff --git a/src/resid-fp/wave6581_P_T.dat b/src/resid-fp/wave6581_P_T.dat new file mode 100644 index 000000000..1cc8874da Binary files /dev/null and b/src/resid-fp/wave6581_P_T.dat differ diff --git a/src/resid-fp/wave6581__ST.cc b/src/resid-fp/wave6581__ST.cc new file mode 100644 index 000000000..d193550f2 --- /dev/null +++ b/src/resid-fp/wave6581__ST.cc @@ -0,0 +1,536 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// --------------------------------------------------------------------------- + +#include "wave.h" + +reg8 WaveformGeneratorFP::wave6581__ST[] = +{ +/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, +/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x378: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3f0: */ 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, +/* 0x3f8: */ 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x3f, 0x3f, +/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x528: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x530: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x538: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x540: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x548: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x550: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x558: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x560: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x568: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x570: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x578: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x580: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x588: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x590: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x598: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x5c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5f8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x1f, +/* 0x600: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x608: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x610: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x618: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x620: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x628: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x630: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x638: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x640: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x648: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x650: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x658: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x660: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x668: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x670: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x678: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x680: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x688: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x690: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x698: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x6c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0x700: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x708: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x710: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x718: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x720: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x728: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x730: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x738: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x740: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x748: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x750: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x758: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x760: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x768: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x770: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x778: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x780: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x788: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x790: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x798: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x7c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7e0: */ 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, +/* 0x7e8: */ 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, +/* 0x7f0: */ 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, +/* 0x7f8: */ 0x3e, 0x3e, 0x3f, 0x3f, 0x7f, 0x7f, 0x7f, 0x7f, +/* 0x800: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x808: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x810: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x818: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x820: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x828: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x830: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x838: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x840: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x848: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x850: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x858: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x860: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x868: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x870: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x878: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x880: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x888: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x890: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x898: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x8c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0x900: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x908: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x910: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x918: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x920: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x928: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x930: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x938: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x940: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x948: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x950: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x958: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x960: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x968: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x970: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x978: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x980: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x988: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x990: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x998: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x9c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, +/* 0xa00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0xa80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xac0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0xb00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xb40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0xb80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xbc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbf0: */ 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, +/* 0xbf8: */ 0x1e, 0x1e, 0x1e, 0x1e, 0x1f, 0x1f, 0x3f, 0x3f, +/* 0xc00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0xc80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xcc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0xd00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xd40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0xd80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xdc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x1f, +/* 0xe00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0xe80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xea0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xea8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xeb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xeb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xec0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xec8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xed0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xed8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xee0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xee8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xef0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xef8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0xf00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xf40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0xf80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xfc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfe0: */ 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, +/* 0xfe8: */ 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, +/* 0xff0: */ 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, +/* 0xff8: */ 0x3e, 0x3e, 0x3f, 0x3f, 0x7f, 0x7f, 0x7f, 0x7f, +}; diff --git a/src/resid-fp/wave6581__ST.dat b/src/resid-fp/wave6581__ST.dat new file mode 100644 index 000000000..2e5d9872c Binary files /dev/null and b/src/resid-fp/wave6581__ST.dat differ diff --git a/src/resid-fp/wave8580_PST.cc b/src/resid-fp/wave8580_PST.cc new file mode 100644 index 000000000..51ae21612 --- /dev/null +++ b/src/resid-fp/wave8580_PST.cc @@ -0,0 +1,536 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// --------------------------------------------------------------------------- + +#include "wave.h" + +reg8 WaveformGeneratorFP::wave8580_PST[] = +{ +/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x378: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, +/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x528: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x530: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x538: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x540: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x548: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x550: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x558: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x560: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x568: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x570: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x578: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x580: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x588: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x590: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x598: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x600: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x608: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x610: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x618: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x620: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x628: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x630: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x638: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x640: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x648: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x650: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x658: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x660: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x668: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x670: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x678: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x680: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x688: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x690: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x698: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x700: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x708: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x710: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x718: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x720: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x728: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x730: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x738: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x740: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x748: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x750: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x758: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x760: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x768: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x770: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x778: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x780: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x788: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x790: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x798: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x70, +/* 0x7f0: */ 0x60, 0x20, 0x70, 0x70, 0x70, 0x70, 0x70, 0x78, +/* 0x7f8: */ 0x78, 0x78, 0x7c, 0x7c, 0x7e, 0x7e, 0x7f, 0x7f, +/* 0x800: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x808: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x810: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x818: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x820: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x828: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x830: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x838: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x840: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x848: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x850: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x858: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x860: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x868: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x870: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x878: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x880: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x888: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x890: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x898: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x900: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x908: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x910: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x918: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x920: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x928: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x930: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x938: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x940: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x948: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x950: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x958: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x960: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x968: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x970: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x978: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x980: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x988: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x990: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x998: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x1e, 0x3f, +/* 0xc00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0xdf8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x8c, 0x9f, +/* 0xe00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, +/* 0xe40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, +/* 0xe60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, +/* 0xe68: */ 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xe70: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xe78: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xe80: */ 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x80, 0x80, +/* 0xe88: */ 0x80, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xe90: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xe98: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xea0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xea8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xeb0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xeb8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xec0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xec8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xed0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xed8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xee0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xee8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, 0xc0, +/* 0xef0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xef8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xcf, +/* 0xf00: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf08: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf10: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf18: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf20: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf28: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf30: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf38: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf40: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf48: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf50: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf58: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf60: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf68: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, +/* 0xf70: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf78: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe3, +/* 0xf80: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf88: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf90: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf98: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xfa0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xfa8: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xfb0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, +/* 0xfb8: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xfc0: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xfc8: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xfd0: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xfd8: */ 0xf0, 0xf0, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0xfe0: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0xfe8: */ 0xf8, 0xf8, 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, +/* 0xff0: */ 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfe, 0xfe, 0xfe, +/* 0xff8: */ 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; diff --git a/src/resid-fp/wave8580_PST.dat b/src/resid-fp/wave8580_PST.dat new file mode 100644 index 000000000..22706cf25 Binary files /dev/null and b/src/resid-fp/wave8580_PST.dat differ diff --git a/src/resid-fp/wave8580_PS_.cc b/src/resid-fp/wave8580_PS_.cc new file mode 100644 index 000000000..e33a2cee5 --- /dev/null +++ b/src/resid-fp/wave8580_PS_.cc @@ -0,0 +1,536 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// --------------------------------------------------------------------------- + +#include "wave.h" + +reg8 WaveformGeneratorFP::wave8580_PS_[] = +{ +/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, +/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, +/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x1f, +/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x0f, +/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x378: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, +/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, +/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3d, +/* 0x3e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3e, +/* 0x3f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, +/* 0x3f8: */ 0x00, 0x0c, 0x1c, 0x3f, 0x1e, 0x3f, 0x3f, 0x3f, +/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, +/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x528: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x530: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x538: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x540: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x548: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x550: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x558: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x560: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x568: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x570: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x578: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, +/* 0x580: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x588: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x590: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x598: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, +/* 0x5c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a, +/* 0x5e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5e, +/* 0x5f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x5f, +/* 0x5f8: */ 0x00, 0x00, 0x00, 0x5f, 0x0c, 0x5f, 0x5f, 0x5f, +/* 0x600: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x608: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x610: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x618: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x620: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x628: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x630: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x638: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x640: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x648: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x650: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x658: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x660: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x668: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x670: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x678: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x47, +/* 0x680: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x688: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x690: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x698: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x43, +/* 0x6c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, +/* 0x6e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6e, +/* 0x6f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6f, +/* 0x6f8: */ 0x00, 0x40, 0x40, 0x6f, 0x40, 0x6f, 0x6f, 0x6f, +/* 0x700: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x708: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x710: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x718: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x720: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x728: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x730: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x738: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x63, +/* 0x740: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x748: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x750: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x758: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x61, +/* 0x760: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x768: */ 0x00, 0x00, 0x00, 0x40, 0x00, 0x40, 0x40, 0x70, +/* 0x770: */ 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x70, +/* 0x778: */ 0x40, 0x60, 0x60, 0x77, 0x60, 0x77, 0x77, 0x77, +/* 0x780: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x788: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x790: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x60, +/* 0x798: */ 0x00, 0x40, 0x40, 0x60, 0x40, 0x60, 0x60, 0x79, +/* 0x7a0: */ 0x00, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x60, +/* 0x7a8: */ 0x40, 0x40, 0x40, 0x60, 0x60, 0x60, 0x60, 0x78, +/* 0x7b0: */ 0x40, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, +/* 0x7b8: */ 0x60, 0x70, 0x70, 0x78, 0x70, 0x79, 0x7b, 0x7b, +/* 0x7c0: */ 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x70, +/* 0x7c8: */ 0x60, 0x60, 0x60, 0x70, 0x60, 0x70, 0x70, 0x7c, +/* 0x7d0: */ 0x60, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x7c, +/* 0x7d8: */ 0x70, 0x78, 0x78, 0x7c, 0x78, 0x7c, 0x7c, 0x7d, +/* 0x7e0: */ 0x70, 0x78, 0x78, 0x78, 0x78, 0x78, 0x78, 0x7c, +/* 0x7e8: */ 0x78, 0x7c, 0x7c, 0x7e, 0x7c, 0x7e, 0x7e, 0x7e, +/* 0x7f0: */ 0x7c, 0x7c, 0x7c, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, +/* 0x7f8: */ 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0xff, +/* 0x800: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x808: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x810: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x818: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x820: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x828: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x830: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x838: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x840: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x848: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x850: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x858: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x860: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x868: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x870: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x878: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, +/* 0x880: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x888: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x890: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x898: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x8c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8f, +/* 0x900: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x908: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x910: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x918: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x920: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x928: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x930: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x938: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x940: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x948: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x950: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x958: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x960: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x968: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x970: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x978: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x87, +/* 0x980: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x988: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x990: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x998: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x83, +/* 0x9c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x8d, +/* 0x9e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x9e8: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0x8e, +/* 0x9f0: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x8f, +/* 0x9f8: */ 0x80, 0x80, 0x80, 0x9f, 0x80, 0x9f, 0x9f, 0x9f, +/* 0xa00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xa40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0xa70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0xa78: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0x87, +/* 0xa80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0xaa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0xab0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0xab8: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x83, +/* 0xac0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0xad0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, +/* 0xad8: */ 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, +/* 0xae0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xae8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x84, +/* 0xaf0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x87, +/* 0xaf8: */ 0x80, 0x80, 0x80, 0x87, 0x80, 0x8f, 0xaf, 0xaf, +/* 0xb00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0xb10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0xb18: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb20: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x80, 0x80, +/* 0xb28: */ 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb30: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb38: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x83, +/* 0xb40: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb48: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb50: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb58: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, +/* 0xb60: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb68: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xa0, +/* 0xb70: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xa0, +/* 0xb78: */ 0x80, 0x80, 0x80, 0xa0, 0x80, 0xa3, 0xb7, 0xb7, +/* 0xb80: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb88: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb90: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb98: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xb1, +/* 0xba0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xba8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xb0, +/* 0xbb0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xb0, +/* 0xbb8: */ 0x80, 0xa0, 0xa0, 0xb0, 0xa0, 0xb8, 0xb9, 0xbb, +/* 0xbc0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xa0, +/* 0xbc8: */ 0x80, 0x80, 0x80, 0xa0, 0x80, 0xa0, 0xa0, 0xb8, +/* 0xbd0: */ 0x80, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xb8, +/* 0xbd8: */ 0xa0, 0xb0, 0xb0, 0xb8, 0xb0, 0xbc, 0xbc, 0xbd, +/* 0xbe0: */ 0xa0, 0xb0, 0xb0, 0xb0, 0xb0, 0xb8, 0xb8, 0xbc, +/* 0xbe8: */ 0xb0, 0xb8, 0xb8, 0xbc, 0xb8, 0xbc, 0xbe, 0xbe, +/* 0xbf0: */ 0xb8, 0xbc, 0xbc, 0xbe, 0xbc, 0xbe, 0xbe, 0xbf, +/* 0xbf8: */ 0xbe, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, +/* 0xc00: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, +/* 0xc08: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, +/* 0xc10: */ 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc18: */ 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc20: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc28: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc30: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc38: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x81, +/* 0xc40: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc48: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc50: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc58: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc60: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc68: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc70: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc78: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc7, +/* 0xc80: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc88: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc90: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xc98: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xca0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xca8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xcb0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xcb8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, 0xc3, +/* 0xcc0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xcc8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, +/* 0xcd0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, +/* 0xcd8: */ 0x80, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xc1, +/* 0xce0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, +/* 0xce8: */ 0x80, 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xcf0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc7, +/* 0xcf8: */ 0xc0, 0xc0, 0xc0, 0xc7, 0xc0, 0xcf, 0xcf, 0xcf, +/* 0xd00: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xd08: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xd10: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xd18: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, +/* 0xd20: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xd28: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, +/* 0xd30: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, 0xc0, +/* 0xd38: */ 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc3, +/* 0xd40: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, +/* 0xd48: */ 0x80, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xc0, +/* 0xd50: */ 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xd58: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, +/* 0xd60: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xd68: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xd70: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xd78: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc1, 0xc7, 0xd7, +/* 0xd80: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xd88: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xd90: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xd98: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xda0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xda8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd0, +/* 0xdb0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd0, +/* 0xdb8: */ 0xc0, 0xc0, 0xc0, 0xd0, 0xc0, 0xd0, 0xd8, 0xdb, +/* 0xdc0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xdc8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd8, +/* 0xdd0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd8, +/* 0xdd8: */ 0xc0, 0xc0, 0xc0, 0xd8, 0xd0, 0xd8, 0xd8, 0xdd, +/* 0xde0: */ 0xc0, 0xc0, 0xc0, 0xd0, 0xc0, 0xd0, 0xd0, 0xdc, +/* 0xde8: */ 0xd0, 0xd8, 0xd8, 0xdc, 0xd8, 0xdc, 0xdc, 0xde, +/* 0xdf0: */ 0xd8, 0xdc, 0xdc, 0xde, 0xdc, 0xde, 0xde, 0xdf, +/* 0xdf8: */ 0xde, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, 0xdf, +/* 0xe00: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xe08: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xe10: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xe18: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xe20: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xe28: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xe30: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xe38: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe3, +/* 0xe40: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xe48: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xe50: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, +/* 0xe58: */ 0xc0, 0xc0, 0xc0, 0xe0, 0xc0, 0xe0, 0xe0, 0xe1, +/* 0xe60: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, +/* 0xe68: */ 0xc0, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xe70: */ 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xe78: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe1, 0xe3, 0xe7, +/* 0xe80: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, +/* 0xe88: */ 0xc0, 0xc0, 0xc0, 0xe0, 0xc0, 0xe0, 0xe0, 0xe0, +/* 0xe90: */ 0xc0, 0xc0, 0xc0, 0xe0, 0xc0, 0xe0, 0xe0, 0xe0, +/* 0xe98: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xea0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xea8: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xeb0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xeb8: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xeb, +/* 0xec0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xec8: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xed0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xed8: */ 0xe0, 0xe0, 0xe0, 0xe8, 0xe0, 0xe8, 0xe8, 0xed, +/* 0xee0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xec, +/* 0xee8: */ 0xe0, 0xe0, 0xe0, 0xec, 0xe8, 0xec, 0xec, 0xee, +/* 0xef0: */ 0xe8, 0xe8, 0xe8, 0xec, 0xec, 0xee, 0xee, 0xef, +/* 0xef8: */ 0xec, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, 0xef, +/* 0xf00: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf08: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf10: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf18: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, +/* 0xf20: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, +/* 0xf28: */ 0xe0, 0xe0, 0xe0, 0xf0, 0xe0, 0xf0, 0xf0, 0xf0, +/* 0xf30: */ 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xf38: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf3, +/* 0xf40: */ 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xf48: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xf50: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xf58: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf5, +/* 0xf60: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xf68: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf4, 0xf4, 0xf6, +/* 0xf70: */ 0xf0, 0xf0, 0xf0, 0xf4, 0xf0, 0xf4, 0xf6, 0xf7, +/* 0xf78: */ 0xf4, 0xf6, 0xf6, 0xf7, 0xf7, 0xf7, 0xf7, 0xf7, +/* 0xf80: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf8, +/* 0xf88: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf8, 0xf8, 0xf8, +/* 0xf90: */ 0xf0, 0xf0, 0xf0, 0xf8, 0xf0, 0xf8, 0xf8, 0xf8, +/* 0xf98: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf9, +/* 0xfa0: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0xfa8: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xfa, +/* 0xfb0: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xfb, +/* 0xfb8: */ 0xf8, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, 0xfb, 0xfb, +/* 0xfc0: */ 0xf8, 0xf8, 0xf8, 0xfc, 0xf8, 0xfc, 0xfc, 0xfc, +/* 0xfc8: */ 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, +/* 0xfd0: */ 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, +/* 0xfd8: */ 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, 0xfd, 0xfd, +/* 0xfe0: */ 0xfc, 0xfc, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +/* 0xfe8: */ 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +/* 0xff0: */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +/* 0xff8: */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; diff --git a/src/resid-fp/wave8580_PS_.dat b/src/resid-fp/wave8580_PS_.dat new file mode 100644 index 000000000..9a20a9eee Binary files /dev/null and b/src/resid-fp/wave8580_PS_.dat differ diff --git a/src/resid-fp/wave8580_P_T.cc b/src/resid-fp/wave8580_P_T.cc new file mode 100644 index 000000000..206a91728 --- /dev/null +++ b/src/resid-fp/wave8580_P_T.cc @@ -0,0 +1,536 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// --------------------------------------------------------------------------- + +#include "wave.h" + +reg8 WaveformGeneratorFP::wave8580_P_T[] = +{ +/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07, +/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f8: */ 0x00, 0x00, 0x00, 0x1c, 0x00, 0x3c, 0x3f, 0x3f, +/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x5e, 0x5f, +/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x378: */ 0x00, 0x00, 0x00, 0x40, 0x40, 0x60, 0x60, 0x6f, +/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, +/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, +/* 0x3b0: */ 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x40, 0x60, +/* 0x3b8: */ 0x40, 0x40, 0x60, 0x60, 0x60, 0x60, 0x70, 0x77, +/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, +/* 0x3c8: */ 0x40, 0x40, 0x40, 0x40, 0x40, 0x60, 0x60, 0x60, +/* 0x3d0: */ 0x40, 0x40, 0x40, 0x60, 0x60, 0x60, 0x60, 0x70, +/* 0x3d8: */ 0x60, 0x60, 0x60, 0x70, 0x70, 0x70, 0x78, 0x7b, +/* 0x3e0: */ 0x60, 0x60, 0x60, 0x70, 0x60, 0x70, 0x70, 0x70, +/* 0x3e8: */ 0x70, 0x70, 0x70, 0x78, 0x78, 0x78, 0x78, 0x7c, +/* 0x3f0: */ 0x78, 0x78, 0x78, 0x7c, 0x78, 0x7c, 0x7c, 0x7e, +/* 0x3f8: */ 0x7c, 0x7e, 0x7e, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, +/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, +/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x4d8: */ 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x4e0: */ 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x4e8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x4f0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x4f8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x8e, 0x9f, +/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, +/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x528: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0x80, +/* 0x530: */ 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x538: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x540: */ 0x00, 0x00, 0x00, 0x80, 0x00, 0x80, 0x80, 0x80, +/* 0x548: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x550: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x558: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x560: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x568: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x570: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x578: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xaf, +/* 0x580: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x588: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x590: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x598: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x5a0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x5a8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x5b0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x5b8: */ 0x80, 0x80, 0x80, 0xa0, 0xa0, 0xa0, 0xa0, 0xb7, +/* 0x5c0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x5c8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xa0, +/* 0x5d0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xa0, 0xa0, +/* 0x5d8: */ 0xa0, 0xa0, 0xa0, 0xb0, 0xa0, 0xb0, 0xb0, 0xbb, +/* 0x5e0: */ 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xb0, 0xb0, +/* 0x5e8: */ 0xa0, 0xb0, 0xb0, 0xb8, 0xb0, 0xb8, 0xb8, 0xbc, +/* 0x5f0: */ 0xb0, 0xb8, 0xb8, 0xb8, 0xb8, 0xbc, 0xbc, 0xbe, +/* 0x5f8: */ 0xbc, 0xbc, 0xbe, 0xbf, 0xbe, 0xbf, 0xbf, 0xbf, +/* 0x600: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x608: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x610: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x618: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x620: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x628: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x630: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x638: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, 0xc0, +/* 0x640: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x648: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x650: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, +/* 0x658: */ 0x80, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x660: */ 0x80, 0x80, 0x80, 0xc0, 0x80, 0xc0, 0xc0, 0xc0, +/* 0x668: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x670: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x678: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xcf, +/* 0x680: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xc0, 0xc0, +/* 0x688: */ 0xc0, 0x80, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x690: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x698: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x6a0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x6a8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x6b0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x6b8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd7, +/* 0x6c0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x6c8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x6d0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x6d8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd0, 0xd0, 0xd9, +/* 0x6e0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xd0, +/* 0x6e8: */ 0xc0, 0xd0, 0xd0, 0xd0, 0xd0, 0xd8, 0xd8, 0xdc, +/* 0x6f0: */ 0xd0, 0xd0, 0xd8, 0xd8, 0xd8, 0xdc, 0xdc, 0xde, +/* 0x6f8: */ 0xdc, 0xdc, 0xde, 0xdf, 0xde, 0xdf, 0xdf, 0xdf, +/* 0x700: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x708: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x710: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x718: */ 0xc0, 0xc0, 0xc0, 0xe0, 0xc0, 0xe0, 0xe0, 0xe0, +/* 0x720: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xe0, +/* 0x728: */ 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x730: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x738: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe7, +/* 0x740: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x748: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x750: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x758: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe8, +/* 0x760: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x768: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe8, 0xec, +/* 0x770: */ 0xe0, 0xe0, 0xe0, 0xe8, 0xe8, 0xe8, 0xec, 0xee, +/* 0x778: */ 0xec, 0xec, 0xec, 0xee, 0xee, 0xef, 0xef, 0xef, +/* 0x780: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x788: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, +/* 0x790: */ 0xe0, 0xe0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0x798: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0x7a0: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0x7a8: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf4, +/* 0x7b0: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf4, +/* 0x7b8: */ 0xf0, 0xf4, 0xf4, 0xf6, 0xf6, 0xf7, 0xf7, 0xf7, +/* 0x7c0: */ 0xf0, 0xf0, 0xf0, 0xf8, 0xf0, 0xf8, 0xf8, 0xf8, +/* 0x7c8: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0x7d0: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0x7d8: */ 0xf8, 0xf8, 0xf8, 0xfa, 0xfa, 0xfb, 0xfb, 0xfb, +/* 0x7e0: */ 0xf8, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, +/* 0x7e8: */ 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfd, 0xfd, 0xfd, +/* 0x7f0: */ 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +/* 0x7f8: */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +/* 0x800: */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +/* 0x808: */ 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfc, +/* 0x810: */ 0xfd, 0xfd, 0xfd, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, +/* 0x818: */ 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xf8, +/* 0x820: */ 0xfb, 0xfb, 0xfb, 0xfa, 0xfa, 0xf8, 0xf8, 0xf8, +/* 0x828: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0x830: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0x838: */ 0xf8, 0xf8, 0xf8, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0x840: */ 0xf7, 0xf7, 0xf7, 0xf6, 0xf6, 0xf4, 0xf4, 0xf0, +/* 0x848: */ 0xf4, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0x850: */ 0xf4, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0x858: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0x860: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0x868: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xe0, 0xe0, +/* 0x870: */ 0xf0, 0xf0, 0xf0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x878: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x880: */ 0xef, 0xef, 0xef, 0xee, 0xee, 0xec, 0xec, 0xe8, +/* 0x888: */ 0xee, 0xec, 0xe8, 0xe8, 0xe8, 0xe0, 0xe0, 0xe0, +/* 0x890: */ 0xec, 0xe8, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x898: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x8a0: */ 0xe8, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x8a8: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x8b0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x8b8: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x8c0: */ 0xe7, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x8c8: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0x8d0: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xc0, 0xc0, +/* 0x8d8: */ 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x8e0: */ 0xe0, 0xe0, 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x8e8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x8f0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x8f8: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x900: */ 0xdf, 0xdf, 0xdf, 0xde, 0xdf, 0xde, 0xdc, 0xdc, +/* 0x908: */ 0xde, 0xdc, 0xdc, 0xd8, 0xd8, 0xd8, 0xd0, 0xd0, +/* 0x910: */ 0xdc, 0xd8, 0xd8, 0xd0, 0xd0, 0xd0, 0xd0, 0xc0, +/* 0x918: */ 0xd0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x920: */ 0xd9, 0xd0, 0xd0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x928: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x930: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x938: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x940: */ 0xd7, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x948: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x950: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x958: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x960: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x968: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x970: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, +/* 0x978: */ 0xc0, 0xc0, 0xc0, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x980: */ 0xcf, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x988: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x990: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0x998: */ 0xc0, 0xc0, 0xc0, 0x80, 0xc0, 0x80, 0x80, 0x80, +/* 0x9a0: */ 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0x80, 0x80, +/* 0x9a8: */ 0xc0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x9b0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x9b8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x9c0: */ 0xc0, 0xc0, 0xc0, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x9c8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x9d0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x9d8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x9e0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x9e8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x9f0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0x9f8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa00: */ 0xbf, 0xbf, 0xbf, 0xbe, 0xbf, 0xbe, 0xbc, 0xbc, +/* 0xa08: */ 0xbe, 0xbc, 0xbc, 0xb8, 0xb8, 0xb8, 0xb8, 0xb0, +/* 0xa10: */ 0xbc, 0xb8, 0xb8, 0xb0, 0xb8, 0xb0, 0xb0, 0xb0, +/* 0xa18: */ 0xb0, 0xb0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, 0xa0, +/* 0xa20: */ 0xbb, 0xb0, 0xb0, 0xa0, 0xb0, 0xa0, 0xa0, 0xa0, +/* 0xa28: */ 0xa0, 0xa0, 0xa0, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa30: */ 0xa0, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa38: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa40: */ 0xb7, 0xb0, 0xa0, 0xa0, 0xa0, 0x80, 0x80, 0x80, +/* 0xa48: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa50: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa58: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa60: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa68: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa70: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa78: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa80: */ 0xaf, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa88: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa90: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xa98: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xaa0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xaa8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xab0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xab8: */ 0x80, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0xac0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xac8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, +/* 0xad0: */ 0x80, 0x80, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0xad8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae0: */ 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb00: */ 0x9f, 0x9e, 0x88, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb08: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb10: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xb18: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, +/* 0xb20: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, +/* 0xb28: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb30: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb40: */ 0x80, 0x80, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00, +/* 0xb48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb80: */ 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc00: */ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7e, 0x7e, 0x7c, +/* 0xc08: */ 0x7e, 0x7c, 0x7c, 0x78, 0x7c, 0x78, 0x78, 0x78, +/* 0xc10: */ 0x7c, 0x78, 0x78, 0x78, 0x78, 0x70, 0x70, 0x70, +/* 0xc18: */ 0x78, 0x70, 0x70, 0x60, 0x70, 0x60, 0x60, 0x60, +/* 0xc20: */ 0x7b, 0x78, 0x70, 0x70, 0x70, 0x60, 0x60, 0x60, +/* 0xc28: */ 0x70, 0x60, 0x60, 0x60, 0x60, 0x40, 0x40, 0x40, +/* 0xc30: */ 0x60, 0x60, 0x60, 0x40, 0x40, 0x40, 0x40, 0x40, +/* 0xc38: */ 0x40, 0x40, 0x40, 0x00, 0x40, 0x00, 0x00, 0x00, +/* 0xc40: */ 0x77, 0x70, 0x60, 0x60, 0x60, 0x60, 0x40, 0x40, +/* 0xc48: */ 0x60, 0x40, 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, +/* 0xc50: */ 0x40, 0x40, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc60: */ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc80: */ 0x6f, 0x64, 0x60, 0x40, 0x40, 0x00, 0x00, 0x00, +/* 0xc88: */ 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd00: */ 0x5f, 0x5e, 0x4c, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe00: */ 0x3f, 0x3f, 0x3e, 0x00, 0x1c, 0x00, 0x00, 0x00, +/* 0xe08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xea0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xea8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xeb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xeb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xec0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xec8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xed0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xed8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xee0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xee8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xef0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xef8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf00: */ 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xf98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xfe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xff0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xff8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +}; diff --git a/src/resid-fp/wave8580_P_T.dat b/src/resid-fp/wave8580_P_T.dat new file mode 100644 index 000000000..5423dd9ac Binary files /dev/null and b/src/resid-fp/wave8580_P_T.dat differ diff --git a/src/resid-fp/wave8580__ST.cc b/src/resid-fp/wave8580__ST.cc new file mode 100644 index 000000000..cfe583786 --- /dev/null +++ b/src/resid-fp/wave8580__ST.cc @@ -0,0 +1,536 @@ +// --------------------------------------------------------------------------- +// This file is part of reSID, a MOS6581 SID emulator engine. +// Copyright (C) 2004 Dag Lem +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// --------------------------------------------------------------------------- + +#include "wave.h" + +reg8 WaveformGeneratorFP::wave8580__ST[] = +{ +/* 0x000: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x008: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x010: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x018: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x020: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x028: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x030: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x038: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x040: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x048: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x050: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x058: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x060: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x068: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x070: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x078: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x080: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x088: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x090: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x098: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x0f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0x100: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x108: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x110: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x118: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x120: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x128: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x130: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x138: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x140: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x148: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x150: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x158: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x160: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x168: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x170: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x178: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x180: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x188: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x190: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x198: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x1f8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, +/* 0x200: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x208: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x210: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x218: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x220: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x228: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x230: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x238: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x240: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x248: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x250: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x258: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x260: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x268: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x270: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x278: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x280: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x288: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x290: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x298: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x2f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0x300: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x308: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x310: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x318: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x320: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x328: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x330: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x338: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x340: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x348: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x350: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x358: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x360: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x368: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x370: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x378: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x380: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x388: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x390: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x398: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x3c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x3f0: */ 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, +/* 0x3f8: */ 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, 0x1f, +/* 0x400: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x408: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x410: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x418: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x420: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x428: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x430: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x438: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x440: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x448: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x450: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x458: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x460: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x468: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x470: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x478: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x480: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x488: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x490: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x498: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x4f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0x500: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x508: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x510: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x518: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x520: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x528: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x530: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x538: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x540: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x548: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x550: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x558: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x560: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x568: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x570: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x578: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x580: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x588: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x590: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x598: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x5f8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x1f, +/* 0x600: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x608: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x610: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x618: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x620: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x628: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x630: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x638: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x640: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x648: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x650: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x658: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x660: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x668: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x670: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x678: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x680: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x688: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x690: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x698: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x6f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0x700: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x708: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x710: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x718: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x720: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x728: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x730: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x738: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x740: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x748: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x750: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x758: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x760: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x768: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x770: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x778: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x780: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x788: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x790: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x798: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0x7c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x7e0: */ 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, +/* 0x7e8: */ 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, 0x38, +/* 0x7f0: */ 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3c, 0x3e, +/* 0x7f8: */ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, +/* 0x800: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x808: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x810: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x818: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x820: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x828: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x830: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x838: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x840: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x848: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x850: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x858: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x860: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x868: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x870: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x878: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x880: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x888: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x890: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x898: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x8f8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0x900: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x908: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x910: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x918: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x920: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x928: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x930: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x938: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x940: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x948: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x950: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x958: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x960: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x968: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x970: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x978: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0x980: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x988: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x990: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x998: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9a8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9b8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9c8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9d8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9e8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0x9f8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x0f, 0x0f, +/* 0xa00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0xa80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xa98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaa8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xab8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xac8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xad8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xae8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xaf8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0xb00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0xb80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xb98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xba8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xbc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbe8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xbf0: */ 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, 0x1c, +/* 0xbf8: */ 0x1e, 0x1e, 0x1f, 0x1f, 0x1f, 0x1f, 0x3f, 0x3f, +/* 0xc00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0xc80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xc98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xca8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xce8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xcf8: */ 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x07, 0x07, +/* 0xd00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd78: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, +/* 0xd80: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd88: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd90: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xd98: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xda8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdb8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, +/* 0xdc0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdc8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdd8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xde8: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf0: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xdf8: */ 0x0e, 0x0e, 0x0e, 0x0e, 0x0f, 0x0f, 0x1f, 0x1f, +/* 0xe00: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe08: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe10: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe18: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe20: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe28: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe30: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe38: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe40: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe48: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe50: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe58: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe60: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe68: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe70: */ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +/* 0xe78: */ 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x83, 0x83, +/* 0xe80: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xe88: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xe90: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xe98: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xea0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xea8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xeb0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xeb8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xec0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xec8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xed0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xed8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xee0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xee8: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xef0: */ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, +/* 0xef8: */ 0x80, 0x80, 0x80, 0x80, 0x87, 0x87, 0x87, 0x8f, +/* 0xf00: */ 0xc0, 0xe0, 0xe0, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, +/* 0xf08: */ 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf10: */ 0xc0, 0xe0, 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf18: */ 0xe0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, +/* 0xf20: */ 0xc0, 0xe0, 0xe0, 0xc0, 0xc0, 0xe0, 0xe0, 0xe0, +/* 0xf28: */ 0xe0, 0xe0, 0xe0, 0xc0, 0xe0, 0xc0, 0xe0, 0xe0, +/* 0xf30: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf38: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf40: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf48: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf50: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf58: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf60: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf68: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf70: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, +/* 0xf78: */ 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe0, 0xe3, 0xe3, +/* 0xf80: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xf88: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xf90: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xf98: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xfa0: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xfa8: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xfb0: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, +/* 0xfb8: */ 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf1, +/* 0xfc0: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0xfc8: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0xfd0: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0xfd8: */ 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, 0xf8, +/* 0xfe0: */ 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, +/* 0xfe8: */ 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, 0xfc, +/* 0xff0: */ 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, +/* 0xff8: */ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, +}; diff --git a/src/resid-fp/wave8580__ST.dat b/src/resid-fp/wave8580__ST.dat new file mode 100644 index 000000000..f30002ceb Binary files /dev/null and b/src/resid-fp/wave8580__ST.dat differ diff --git a/src/resources.h b/src/resources.h new file mode 100644 index 000000000..b5c9bccc6 --- /dev/null +++ b/src/resources.h @@ -0,0 +1,139 @@ +#define IDM_FILE_RESET 40000 +#define IDM_FILE_HRESET 40001 +#define IDM_FILE_EXIT 40002 +#define IDM_FILE_RESET_CAD 40003 +#define IDM_DISC_A 40010 +#define IDM_DISC_B 40011 +#define IDM_EJECT_A 40012 +#define IDM_EJECT_B 40013 +#define IDM_HDCONF 40014 +#define IDM_CONFIG 40020 +#define IDM_CONFIG_LOAD 40021 +#define IDM_CONFIG_SAVE 40022 +#define IDM_STATUS 40030 +#define IDM_VID_RESIZE 40050 +#define IDM_VID_REMEMBER 40051 +#define IDM_VID_DDRAW 40060 +#define IDM_VID_D3D 40061 +#define IDM_VID_FULLSCREEN 40070 +#define IDM_VID_FS_FULL 40071 +#define IDM_VID_FS_43 40072 +#define IDM_VID_FS_SQ 40073 +#define IDM_VID_FS_INT 40074 +#define IDM_CDROM_ISO 40100 +#define IDM_CDROM_EMPTY 40200 +#define IDM_CDROM_REAL 40200 +#define IDM_CDROM_DISABLED 40300 + +#define IDC_COMBO1 1000 +#define IDC_COMBOVID 1001 +#define IDC_COMBO3 1002 +#define IDC_COMBO4 1003 +#define IDC_COMBO5 1004 +#define IDC_COMBO386 1005 +#define IDC_COMBO486 1006 +#define IDC_COMBOSND 1007 +#define IDC_COMBOCHC 1008 +#define IDC_COMBONET 1009 +#define IDC_COMBOCPUM 1060 +#define IDC_COMBOSPD 1061 +#define IDC_COMBODRA 1062 +#define IDC_COMBODRB 1063 +#define IDC_COMBOJOY 1064 +#define IDC_CHECK1 1010 +#define IDC_CHECK2 1011 +#define IDC_CHECK3 1012 +#define IDC_CHECK4 1013 +#define IDC_CHECKGUS 1014 +#define IDC_CHECKSSI 1015 +#define IDC_CHECKVOODOO 1016 +#define IDC_CHECKDYNAREC 1017 +#define IDC_STATIC 1020 +#define IDC_CHECKFORCE43 1021 +#define IDC_CHECKOVERSCAN 1022 +#define IDC_CHECKCBURST 1023 +#define IDC_CHECKBROWN 1024 +#define IDC_CHECKFLASH 1025 +#define IDC_CHECKSYNC 1026 +#define IDC_CHECKSERIAL 1027 +#define IDC_EDIT1 1030 +#define IDC_EDIT2 1031 +#define IDC_EDIT3 1032 +#define IDC_EDIT4 1033 +#define IDC_EDIT5 1034 +#define IDC_EDIT6 1035 +#define IDC_TEXT1 1040 +#define IDC_TEXT2 1041 +#define IDC_EDITC 1050 +#define IDC_CFILE 1051 +#define IDC_CNEW 1052 +#define IDC_EDITD 1053 +#define IDC_DFILE 1054 +#define IDC_DNEW 1055 +#define IDC_EJECTC 1056 +#define IDC_EJECTD 1057 +#define IDC_EDITE 1058 +#define IDC_EFILE 1059 +#define IDC_ENEW 1060 +#define IDC_EDITF 1061 +#define IDC_FFILE 1062 +#define IDC_FNEW 1063 +#define IDC_EJECTE 1064 +#define IDC_EJECTF 1065 +#define IDC_MEMSPIN 1070 +#define IDC_MEMTEXT 1071 +#define IDC_CHDD 1080 +#define IDC_CCDROM 1081 +#define IDC_DHDD 1082 +#define IDC_DCDROM 1083 +#define IDC_EHDD 1084 +#define IDC_ECDROM 1085 +#define IDC_FHDD 1086 +#define IDC_FCDROM 1087 +#define IDC_GCDROM 1088 +#define IDC_HCDROM 1089 +#define IDC_STEXT1 1100 +#define IDC_STEXT2 1101 +#define IDC_STEXT3 1102 +#define IDC_STEXT4 1103 +#define IDC_STEXT5 1104 +#define IDC_STEXT6 1105 +#define IDC_STEXT7 1106 +#define IDC_STEXT8 1107 +#define IDC_STEXT_DEVICE 1108 +#define IDC_TEXT_MB 1120 + +#define IDC_EDIT_C_SPT 1200 +#define IDC_EDIT_C_HPC 1201 +#define IDC_EDIT_C_CYL 1202 +#define IDC_EDIT_D_SPT 1203 +#define IDC_EDIT_D_HPC 1204 +#define IDC_EDIT_D_CYL 1205 +#define IDC_EDIT_E_SPT 1206 +#define IDC_EDIT_E_HPC 1207 +#define IDC_EDIT_E_CYL 1208 +#define IDC_EDIT_F_SPT 1209 +#define IDC_EDIT_F_HPC 1210 +#define IDC_EDIT_F_CYL 1211 +#define IDC_TEXT_C_SIZE 1220 +#define IDC_TEXT_D_SIZE 1221 +#define IDC_TEXT_E_SIZE 1222 +#define IDC_TEXT_F_SIZE 1223 +#define IDC_EDIT_C_FN 1230 +#define IDC_EDIT_D_FN 1231 +#define IDC_EDIT_E_FN 1232 +#define IDC_EDIT_F_FN 1233 + +#define IDC_CONFIGUREVID 1200 +#define IDC_CONFIGURESND 1201 +#define IDC_CONFIGUREVOODOO 1202 +#define IDC_CONFIGURENET 1203 +#define IDC_JOY1 1210 +#define IDC_JOY2 1211 +#define IDC_JOY3 1212 +#define IDC_JOY4 1213 + +#define IDC_CONFIG_BASE 1200 + +#define WM_RESETD3D WM_USER +#define WM_LEAVEFULLSCREEN WM_USER + 1 diff --git a/src/rom.c b/src/rom.c new file mode 100644 index 000000000..a820a6d0a --- /dev/null +++ b/src/rom.c @@ -0,0 +1,125 @@ +#include +#include +#include "ibm.h" +#include "mem.h" +#include "rom.h" + +FILE *romfopen(char *fn, char *mode) +{ + char s[512]; + strcpy(s, pcempath); + put_backslash(s); + strcat(s, fn); + return fopen(s, mode); +} + +int rom_present(char *fn) +{ + FILE *f; + char s[512]; + + strcpy(s, pcempath); + put_backslash(s); + strcat(s, fn); + f = fopen(s, "rb"); + if (f) + { + fclose(f); + return 1; + } + return 0; +} + +static uint8_t rom_read(uint32_t addr, void *p) +{ + rom_t *rom = (rom_t *)p; +// pclog("rom_read : %08x %08x %02x\n", addr, rom->mask, rom->rom[addr & rom->mask]); + return rom->rom[addr & rom->mask]; +} +uint16_t rom_readw(uint32_t addr, void *p) +{ + rom_t *rom = (rom_t *)p; +// pclog("rom_readw: %08x %08x %04x\n", addr, rom->mask, *(uint16_t *)&rom->rom[addr & rom->mask]); + return *(uint16_t *)&rom->rom[addr & rom->mask]; +} +uint32_t rom_readl(uint32_t addr, void *p) +{ + rom_t *rom = (rom_t *)p; +// pclog("rom_readl: %08x %08x %08x\n", addr, rom->mask, *(uint32_t *)&rom->rom[addr & rom->mask]); + return *(uint32_t *)&rom->rom[addr & rom->mask]; +} + +int rom_init(rom_t *rom, char *fn, uint32_t address, int size, int mask, int file_offset, uint32_t flags) +{ + FILE *f = romfopen(fn, "rb"); + + if (!f) + { + pclog("ROM image not found : %s\n", fn); + return -1; + } + + rom->rom = malloc(size); + fseek(f, file_offset, SEEK_SET); + fread(rom->rom, size, 1, f); + fclose(f); + + rom->mask = mask; + + mem_mapping_add(&rom->mapping, address, size, rom_read, + rom_readw, + rom_readl, + mem_write_null, + mem_write_nullw, + mem_write_nulll, + rom->rom, + flags, + rom); + + return 0; +} + +int rom_init_interleaved(rom_t *rom, char *fn_low, char *fn_high, uint32_t address, int size, int mask, int file_offset, uint32_t flags) +{ + FILE *f_low = romfopen(fn_low, "rb"); + FILE *f_high = romfopen(fn_high, "rb"); + int c; + + if (!f_low || !f_high) + { + if (!f_low) + pclog("ROM image not found : %s\n", fn_low); + else + fclose(f_low); + if (!f_high) + pclog("ROM image not found : %s\n", fn_high); + else + fclose(f_high); + return -1; + } + + rom->rom = malloc(size); + fseek(f_low, file_offset, SEEK_SET); + fseek(f_high, file_offset, SEEK_SET); + for (c = 0; c < size; c += 2) + { + rom->rom[c] = getc(f_low); + rom->rom[c + 1] = getc(f_high); + } + fclose(f_high); + fclose(f_low); + + rom->mask = mask; + + mem_mapping_add(&rom->mapping, address, size, rom_read, + rom_readw, + rom_readl, + mem_write_null, + mem_write_nullw, + mem_write_nulll, + rom->rom, + flags, + rom); + + return 0; +} diff --git a/src/rom.h b/src/rom.h new file mode 100644 index 000000000..f63d63202 --- /dev/null +++ b/src/rom.h @@ -0,0 +1,12 @@ +FILE *romfopen(char *fn, char *mode); +int rom_present(char *fn); + +typedef struct rom_t +{ + uint8_t *rom; + uint32_t mask; + mem_mapping_t mapping; +} rom_t; + +int rom_init(rom_t *rom, char *fn, uint32_t address, int size, int mask, int file_offset, uint32_t flags); +int rom_init_interleaved(rom_t *rom, char *fn_low, char *fn_high, uint32_t address, int size, int mask, int file_offset, uint32_t flags); diff --git a/src/scat.c b/src/scat.c new file mode 100644 index 000000000..44c4e9080 --- /dev/null +++ b/src/scat.c @@ -0,0 +1,495 @@ +/*This is the chipset used in the Award 286 clone model*/ +#include "ibm.h" +#include "io.h" +#include "scat.h" +#include "mem.h" + +static uint8_t scat_regs[256]; +static int scat_index; +static uint8_t scat_port_92 = 0; +static uint8_t scat_ems_reg_2xA = 0; +static mem_mapping_t scat_mapping[32]; +static mem_mapping_t scat_high_mapping[16]; +static scat_t scat_stat[32]; +static uint32_t scat_xms_bound; +static mem_mapping_t scat_shadowram_mapping; +static mem_mapping_t scat_512k_clip_mapping; + +void scat_shadow_state_update() +{ + int i, val, val2; + + // TODO - Segment A000 to BFFF shadow ram enable features and ROM enable features should be implemented later. + for (i = 8; i < 24; i++) + { + val = ((scat_regs[SCAT_SHADOW_RAM_ENABLE_1 + (i >> 3)] >> (i & 7)) & 1) ? MEM_READ_INTERNAL : MEM_READ_EXTERNAL; + if (i < 8) + { + val |= ((scat_regs[SCAT_SHADOW_RAM_ENABLE_1 + (i >> 3)] >> (i & 7)) & 1) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTERNAL; + } + else + { + if ((scat_regs[SCAT_RAM_WRITE_PROTECT] >> ((i - 8) >> 1)) & 1) + { + val |= MEM_WRITE_DISABLED; + } + else + { + val |= ((scat_regs[SCAT_SHADOW_RAM_ENABLE_1 + (i >> 3)] >> (i & 7)) & 1) ? MEM_WRITE_INTERNAL : MEM_WRITE_EXTERNAL; + } + mem_set_mem_state((i + 40) << 14, 0x4000, val); + } + } + + flushmmucache(); +} + +void scat_set_xms_bound(uint8_t val) +{ + uint32_t max_xms_size = (mem_size >= 16384) ? 0xFC0000 : mem_size << 10; + + switch (val) + { + case 1: + scat_xms_bound = 0x100000; + break; + case 2: + scat_xms_bound = 0x140000; + break; + case 3: + scat_xms_bound = 0x180000; + break; + case 4: + scat_xms_bound = 0x200000; + break; + case 5: + scat_xms_bound = 0x300000; + break; + case 6: + scat_xms_bound = 0x400000; + break; + case 7: + scat_xms_bound = 0x600000; + break; + case 8: + scat_xms_bound = 0x800000; + break; + case 9: + scat_xms_bound = 0xA00000; + break; + case 10: + scat_xms_bound = 0xC00000; + break; + case 11: + scat_xms_bound = 0xE00000; + break; + default: + scat_xms_bound = (mem_size >= 16384 ? 0xFC0000 : mem_size << 10); + break; + } + + if ((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) == 3) + { + if (val != 1) + { + mem_mapping_enable(&scat_shadowram_mapping); + if (val == 0) + scat_xms_bound = 0x160000; + } + else + { + mem_mapping_disable(&scat_shadowram_mapping); + } + pclog("Set XMS bound(%02X) = %06X(%dKbytes for EMS access)\n", val, scat_xms_bound, (0x160000 - scat_xms_bound) >> 10); + if (scat_xms_bound > 0x100000) + mem_set_mem_state(0x100000, scat_xms_bound - 0x100000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + if (scat_xms_bound < 0x160000) + mem_set_mem_state(scat_xms_bound, 0x160000 - scat_xms_bound, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + else + { + if (scat_xms_bound > max_xms_size) + scat_xms_bound = max_xms_size; + pclog("Set XMS bound(%02X) = %06X(%dKbytes for EMS access)\n", val, scat_xms_bound, ((mem_size << 10) - scat_xms_bound) >> 10); + if (scat_xms_bound > 0x100000) + mem_set_mem_state(0x100000, scat_xms_bound - 0x100000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + if (scat_xms_bound < (mem_size << 10)) + mem_set_mem_state(scat_xms_bound, (mem_size << 10) - scat_xms_bound, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } +} + +uint32_t get_scat_addr(uint32_t addr, scat_t *p) +{ + if (p && (scat_regs[SCAT_EMS_CONTROL] & 0x80) && (p->regs_2x9 & 0x80)) + { + addr = (addr & 0x3fff) | (((p->regs_2x9 & 3) << 8) | p->regs_2x8) << 14; + } + else if (p == NULL && mem_size < 2048 && ((scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) > 7)) + addr &= 0x7FFFF; + if ((scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x40) == 0 && (scat_regs[SCAT_DRAM_CONFIGURATION] & 0x0F) == 3 && addr >= 0x100000) + addr -= 0x60000; + + return addr; +} + +void scat_write(uint16_t port, uint8_t val, void *priv) +{ + uint8_t scat_reg_valid = 0, scat_shadow_update = 0, index; + uint32_t base_addr, virt_addr; + + switch (port) + { + case 0x22: + scat_index = val; + break; + + case 0x23: + switch (scat_index) + { + case SCAT_CLOCK_CONTROL: + case SCAT_PERIPHERAL_CONTROL: + case SCAT_EMS_CONTROL: + scat_reg_valid = 1; + break; + case SCAT_POWER_MANAGEMENT: + val &= 0x40; // TODO - Only use AUX parity disable bit for this version. Other bits should be implemented later. + scat_reg_valid = 1; + break; + case SCAT_DRAM_CONFIGURATION: + if((scat_regs[SCAT_EXTENDED_BOUNDARY] & 0x40) == 0) + { + if((val & 0x0F) == 3) + { + mem_mapping_enable(&scat_shadowram_mapping); + } + else + { + mem_mapping_disable(&scat_shadowram_mapping); + } + if(mem_size < 2048) + { + if ((val & 0x0F) > 7) mem_mapping_enable(&scat_512k_clip_mapping); + else mem_mapping_disable(&scat_512k_clip_mapping); + } + } + flushmmucache(); + scat_reg_valid = 1; + break; + case SCAT_EXTENDED_BOUNDARY: + scat_set_xms_bound(val & 0x0f); + mem_set_mem_state(0x40000, 0x60000, (val & 0x20) ? MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL : MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + flushmmucache(); + scat_reg_valid = 1; + break; + case SCAT_ROM_ENABLE: + case SCAT_RAM_WRITE_PROTECT: + case SCAT_SHADOW_RAM_ENABLE_1: + case SCAT_SHADOW_RAM_ENABLE_2: + case SCAT_SHADOW_RAM_ENABLE_3: + scat_reg_valid = 1; + scat_shadow_update = 1; + break; + default: + break; + } + if (scat_reg_valid) + scat_regs[scat_index] = val; + if (scat_shadow_update) + scat_shadow_state_update(); + pclog("Write SCAT Register %02X to %02X at %04X:%04X\n", scat_index, val, CS, cpu_state.pc); + break; + + case 0x92: + if ((mem_a20_alt ^ val) & 2) + { + mem_a20_alt = val & 2; + mem_a20_recalc(); + } + if ((~scat_port_92 & val) & 1) + { + softresetx86(); + } + scat_port_92 = val; + break; + + case 0x208: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == 0x40) + { + pclog("Write SCAT EMS Control Port %04X to %02X at %04X:%04X\n", port, val, CS, cpu_state.pc); + index = scat_ems_reg_2xA & 0x1F; + scat_stat[index].regs_2x8 = val; + } + break; + case 0x209: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == 0x40) + { + pclog("Write SCAT EMS Control Port %04X to %02X at %04X:%04X\n", port, val, CS, cpu_state.pc); + index = scat_ems_reg_2xA & 0x1F; + scat_stat[index].regs_2x9 = val; + base_addr = (index + 16) << 14; + if(index >= 24) + base_addr += 0x30000; + + if (val & 0x80) + { + virt_addr = (((scat_stat[index].regs_2x9 & 3) << 8) | scat_stat[index].regs_2x8) << 14; + mem_mapping_enable(&scat_mapping[index]); + mem_mapping_set_exec(&scat_mapping[index], ram + get_scat_addr(virt_addr, &scat_stat[index])); + pclog("Map page %d(address %05X) to address %06X\n", scat_ems_reg_2xA & 0x1f, base_addr, virt_addr); + } + else + { + mem_mapping_disable(&scat_mapping[index]); + pclog("Unmap page %d(address %06X)\n", scat_ems_reg_2xA & 0x1f, base_addr); + } + + if (scat_ems_reg_2xA & 0x80) + { + scat_ems_reg_2xA = (scat_ems_reg_2xA & 0xe0) | ((scat_ems_reg_2xA + 1) & 0x1f); + } + } + break; + case 0x20A: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == 0x40) + { + pclog("Write SCAT EMS Control Port %04X to %02X at %04X:%04X\n", port, val, CS, cpu_state.pc); + scat_ems_reg_2xA = val; + } + break; + + case 0x218: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == 0x41) + { + pclog("Write SCAT EMS Control Port %04X to %02X at %04X:%04X\n", port, val, CS, cpu_state.pc); + index = scat_ems_reg_2xA & 0x1F; + scat_stat[index].regs_2x8 = val; + } + break; + case 0x219: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == 0x41) + { + pclog("Write SCAT EMS Control Port %04X to %02X at %04X:%04X\n", port, val, CS, cpu_state.pc); + index = scat_ems_reg_2xA & 0x1F; + scat_stat[index].regs_2x9 = val; + base_addr = (index + 16) << 14; + if (index >= 24) + base_addr += 0x30000; + + if (val & 0x80) + { + virt_addr = (((scat_stat[index].regs_2x9 & 3) << 8) | scat_stat[index].regs_2x8) << 14; + mem_mapping_enable(&scat_mapping[index]); + mem_mapping_set_exec(&scat_mapping[index], ram + get_scat_addr(virt_addr, &scat_stat[index])); + pclog("Map page %d(address %05X) to address %06X\n", scat_ems_reg_2xA & 0x1f, base_addr, virt_addr); + } + else + { + mem_mapping_disable(&scat_mapping[index]); + pclog("Unmap page %d(address %05X)\n", scat_ems_reg_2xA & 0x1f, base_addr); + } + + if (scat_ems_reg_2xA & 0x80) + { + scat_ems_reg_2xA = (scat_ems_reg_2xA & 0xe0) | ((scat_ems_reg_2xA + 1) & 0x1f); + } + } + break; + case 0x21A: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == 0x41) + { + pclog("Write SCAT EMS Control Port %04X to %02X at %04X:%04X\n", port, val, CS, cpu_state.pc); + scat_ems_reg_2xA = val; + } + break; + } +} + +uint8_t scat_read(uint16_t port, void *priv) +{ + uint8_t val = 0xff, index; + switch (port) + { + case 0x23: + switch (scat_index) + { + case SCAT_MISCELLANEOUS_STATUS: + val = (scat_regs[scat_index] & 0xbf) | ((scat_port_92 & 2) << 5); + break; + default: + val = scat_regs[scat_index]; + break; + } + pclog("Read SCAT Register %02X at %04X:%04X\n", scat_index, CS, cpu_state.pc); + break; + + case 0x92: + val = scat_port_92; + break; + + case 0x208: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == 0x40) + { + pclog("Read SCAT EMS Control Port %04X at %04X:%04X\n", port, CS, cpu_state.pc); + index = scat_ems_reg_2xA & 0x1F; + val = scat_stat[index].regs_2x8; + } + break; + case 0x209: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == 0x40) + { + pclog("Read SCAT EMS Control Port %04X at %04X:%04X\n", port, CS, cpu_state.pc); + index = scat_ems_reg_2xA & 0x1F; + val = scat_stat[index].regs_2x9; + } + break; + case 0x20A: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == 0x40) + { + pclog("Read SCAT EMS Control Port %04X at %04X:%04X\n", port, CS, cpu_state.pc); + val = scat_ems_reg_2xA; + } + break; + + case 0x218: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == 0x41) + { + pclog("Read SCAT EMS Control Port %04X at %04X:%04X\n", port, CS, cpu_state.pc); + index = scat_ems_reg_2xA & 0x1F; + val = scat_stat[index].regs_2x8; + } + break; + case 0x219: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == 0x41) + { + pclog("Read SCAT EMS Control Port %04X at %04X:%04X\n", port, CS, cpu_state.pc); + index = scat_ems_reg_2xA & 0x1F; + val = scat_stat[index].regs_2x9; + } + break; + case 0x21A: + if ((scat_regs[SCAT_EMS_CONTROL] & 0x41) == 0x41) + { + pclog("Read SCAT EMS Control Port %04X at %04X:%04X\n", port, CS, cpu_state.pc); + val = scat_ems_reg_2xA; + } + break; + } + return val; +} + +uint8_t mem_read_scatems(uint32_t addr, void *priv) +{ + uint8_t val = 0xff; + scat_t *stat = (scat_t *)priv; + + addr = get_scat_addr(addr, stat); + if (addr < (mem_size << 10)) + val = mem_read_ram(addr, priv); + + return val; +} +uint16_t mem_read_scatemsw(uint32_t addr, void *priv) +{ + uint16_t val = 0xffff; + scat_t *stat = (scat_t *)priv; + + addr = get_scat_addr(addr, stat); + if (addr < (mem_size << 10)) + val = mem_read_ramw(addr, priv); + + return val; +} +uint32_t mem_read_scatemsl(uint32_t addr, void *priv) +{ + uint32_t val = 0xffffffff; + scat_t *stat = (scat_t *)priv; + + addr = get_scat_addr(addr, stat); + if (addr < (mem_size << 10)) + val = mem_read_raml(addr, priv); + + return val; +} + +void mem_write_scatems(uint32_t addr, uint8_t val, void *priv) +{ + scat_t *stat = (scat_t *)priv; + + addr = get_scat_addr(addr, stat); + if (addr < (mem_size << 10)) + mem_write_ram(addr, val, priv); +} +void mem_write_scatemsw(uint32_t addr, uint16_t val, void *priv) +{ + scat_t *stat = (scat_t *)priv; + + addr = get_scat_addr(addr, stat); + if (addr < (mem_size << 10)) + mem_write_ramw(addr, val, priv); +} +void mem_write_scatemsl(uint32_t addr, uint32_t val, void *priv) +{ + scat_t *stat = (scat_t *)priv; + + addr = get_scat_addr(addr, stat); + if (addr < (mem_size << 10)) + mem_write_raml(addr, val, priv); +} + +void scat_init() +{ + int i; + + io_sethandler(0x0022, 0x0002, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); + io_sethandler(0x0092, 0x0001, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); + io_sethandler(0x0208, 0x0003, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); + io_sethandler(0x0218, 0x0003, scat_read, NULL, NULL, scat_write, NULL, NULL, NULL); + + for (i = 0; i < 256; i++) + { + scat_regs[i] = 0xff; + } + + scat_regs[SCAT_DMA_WAIT_STATE_CONTROL] = 0; + scat_regs[SCAT_VERSION] = 10; + scat_regs[SCAT_CLOCK_CONTROL] = 2; + scat_regs[SCAT_PERIPHERAL_CONTROL] = 0x80; + scat_regs[SCAT_MISCELLANEOUS_STATUS] = 0x37; + scat_regs[SCAT_POWER_MANAGEMENT] = 0; + scat_regs[SCAT_ROM_ENABLE] = 0xC0; + scat_regs[SCAT_RAM_WRITE_PROTECT] = 0; + scat_regs[SCAT_SHADOW_RAM_ENABLE_1] = 0; + scat_regs[SCAT_SHADOW_RAM_ENABLE_2] = 0; + scat_regs[SCAT_SHADOW_RAM_ENABLE_3] = 0; + scat_regs[SCAT_DRAM_CONFIGURATION] = 2; + scat_regs[SCAT_EXTENDED_BOUNDARY] = 0; + scat_regs[SCAT_EMS_CONTROL] = 0; + + for (i = 0; i < 32; i++) + { + scat_stat[i].regs_2x8 = 0xff; + scat_stat[i].regs_2x9 = 0x03; + mem_mapping_add(&scat_mapping[i], (i + (i >= 24 ? 28 : 16)) << 14, 0x04000, mem_read_scatems, mem_read_scatemsw, mem_read_scatemsl, mem_write_scatems, mem_write_scatemsw, mem_write_scatemsl, ram + ((i + (i >= 24 ? 28 : 16)) << 14), 0, &scat_stat[i]); + mem_mapping_disable(&scat_mapping[i]); + } + + // TODO - Only normal CPU accessing address FF0000 to FFFFFF mapped to ROM. Normal CPU accessing address FC0000 to FEFFFF map to ROM should be implemented later. + for (i = 12; i < 16; i++) + { + mem_mapping_add(&scat_high_mapping[i], (i << 14) + 0xFC0000, 0x04000, mem_read_bios, mem_read_biosw, mem_read_biosl, mem_write_null, mem_write_nullw, mem_write_nulll, rom + (i << 14), 0, NULL); + } + + if (mem_size == 1024) + { + mem_mapping_add(&scat_shadowram_mapping, 0x100000, 0x60000, mem_read_scatems, mem_read_scatemsw, mem_read_scatemsl, mem_write_scatems, mem_write_scatemsw, mem_write_scatemsl, ram + 0xA0000, MEM_MAPPING_INTERNAL, NULL); + } + + // Need to RAM 512kb clipping emulation if only 256KB or 64KB modules installed in memory bank. + // TODO - 512KB clipping should be applied all RAM refer. + mem_mapping_add(&scat_512k_clip_mapping, 0x80000, 0x20000, mem_read_scatems, mem_read_scatemsw, mem_read_scatemsl, mem_write_scatems, mem_write_scatemsw, mem_write_scatemsl, ram, MEM_MAPPING_INTERNAL, NULL); + mem_mapping_disable(&scat_512k_clip_mapping); + // --- + + scat_set_xms_bound(0); + scat_shadow_state_update(); +} diff --git a/src/scat.h b/src/scat.h new file mode 100644 index 000000000..1fee0cee3 --- /dev/null +++ b/src/scat.h @@ -0,0 +1,22 @@ +#define SCAT_DMA_WAIT_STATE_CONTROL 0x01 +#define SCAT_VERSION 0x40 +#define SCAT_CLOCK_CONTROL 0x41 +#define SCAT_PERIPHERAL_CONTROL 0x44 +#define SCAT_MISCELLANEOUS_STATUS 0x45 +#define SCAT_POWER_MANAGEMENT 0x46 +#define SCAT_ROM_ENABLE 0x48 +#define SCAT_RAM_WRITE_PROTECT 0x49 +#define SCAT_SHADOW_RAM_ENABLE_1 0x4A +#define SCAT_SHADOW_RAM_ENABLE_2 0x4B +#define SCAT_SHADOW_RAM_ENABLE_3 0x4C +#define SCAT_DRAM_CONFIGURATION 0x4D +#define SCAT_EXTENDED_BOUNDARY 0x4E +#define SCAT_EMS_CONTROL 0x4F + +typedef struct scat_t +{ + uint8_t regs_2x8; + uint8_t regs_2x9; +} scat_t; + +void scat_init(); diff --git a/src/scsi_cmds.h b/src/scsi_cmds.h new file mode 100644 index 000000000..c27351c3c --- /dev/null +++ b/src/scsi_cmds.h @@ -0,0 +1,90 @@ +/* ATAPI/SCSI Commands */ +#define TEST_UNIT_READY 0x00 +#define REQUEST_SENSE 0x03 +#define READ_6 0x08 +#define INQUIRY 0x12 +#define MODE_SELECT 0x15 +#define MODE_SENSE 0x1a /*actually MODE_SENSE_6 but I want to match QEMU's scheme*/ +#define START_STOP 0x1b /*LOAD_UNLOAD is the same*/ +#define ALLOW_MEDIUM_REMOVAL 0x1e +#define READ_CAPACITY_10 0x25 +#define READ_10 0x28 +#define SEEK_10 0x2b +#define READ_SUBCHANNEL 0x42 /*unimplemented on QEMU, so I came up with this name for this command*/ +#define READ_TOC 0x43 +#define READ_HEADER 0x44 /*unimplemented on QEMU, so I came up with this name for this command*/ +#define PLAY_AUDIO_10 0x45 +#define GET_CONFIGURATION 0x46 +#define PLAY_AUDIO_MSF 0x47 +#define GET_EVENT_NOTIFICATION 0x4a +#define PAUSE_RESUME 0x4b +#define STOP_PLAY_SCAN 0x4e +#define READ_DISC_INFORMATION 0x51 +#define MODE_SELECT_10 0x55 +#define MODE_SENSE_10 0x5a +#define PLAY_AUDIO_12 0xa5 /*deprecated*/ +#define READ_12 0xa8 +#define READ_DVD_STRUCTURE 0xad +#define SET_CD_SPEED 0xbb +#define MECHANISM_STATUS 0xbd +#define READ_CD 0xbe +#define SEND_DVD_STRUCTURE 0xbf + +/* SCSI Sense Keys */ +#define SENSE_NONE 0 +#define SENSE_NOT_READY 2 +#define SENSE_ILLEGAL_REQUEST 5 +#define SENSE_UNIT_ATTENTION 6 + +/* SCSI Additional Sense Codes */ +#define ASC_ILLEGAL_OPCODE 0x20 +#define ASC_INV_FIELD_IN_CMD_PACKET 0x24 +#define ASC_MEDIUM_MAY_HAVE_CHANGED 0x28 +#define ASC_MEDIUM_NOT_PRESENT 0x3a + +/* Mode page codes for mode sense/set */ +#define GPMODE_R_W_ERROR_PAGE 0x01 +#define GPMODE_CDROM_PAGE 0x0d +#define GPMODE_CDROM_AUDIO_PAGE 0x0e +#define GPMODE_CAPABILITIES_PAGE 0x2a +#define GPMODE_ALL_PAGES 0x3f + +/* + * SCSI Status codes +*/ +#define GOOD 0x00 +#define CHECK_CONDITION 0x02 +#define CONDITION_GOOD 0x04 +#define BUSY 0x08 +#define INTERMEDIATE_GOOD 0x10 +#define INTERMEDIATE_C_GOOD 0x14 +#define RESERVATION_CONFLICT 0x18 +#define COMMAND_TERMINATED 0x22 +#define TASK_SET_FULL 0x28 +#define ACA_ACTIVE 0x30 +#define TASK_ABORTED 0x40 + +#define STATUS_MASK 0x3e + +/* Event notification classes for GET EVENT STATUS NOTIFICATION */ +#define GESN_NO_EVENTS 0 +#define GESN_OPERATIONAL_CHANGE 1 +#define GESN_POWER_MANAGEMENT 2 +#define GESN_EXTERNAL_REQUEST 3 +#define GESN_MEDIA 4 +#define GESN_MULTIPLE_HOSTS 5 +#define GESN_DEVICE_BUSY 6 + +/* Event codes for MEDIA event status notification */ +#define MEC_NO_CHANGE 0 +#define MEC_EJECT_REQUESTED 1 +#define MEC_NEW_MEDIA 2 +#define MEC_MEDIA_REMOVAL 3 /* only for media changers */ +#define MEC_MEDIA_CHANGED 4 /* only for media changers */ +#define MEC_BG_FORMAT_COMPLETED 5 /* MRW or DVD+RW b/g format completed */ +#define MEC_BG_FORMAT_RESTARTED 6 /* MRW or DVD+RW b/g format restarted */ +#define MS_TRAY_OPEN 1 +#define MS_MEDIA_PRESENT 2 + +#define CHECK_READY 2 +#define ALLOW_UA 1 \ No newline at end of file diff --git a/src/serial.c b/src/serial.c new file mode 100644 index 000000000..2280ed129 --- /dev/null +++ b/src/serial.c @@ -0,0 +1,292 @@ +#include "ibm.h" +#include "io.h" +#include "mouse.h" +#include "pic.h" +#include "serial.h" +#include "timer.h" + +enum +{ + SERIAL_INT_LSR = 1, + SERIAL_INT_RECEIVE = 2, + SERIAL_INT_TRANSMIT = 4, + SERIAL_INT_MSR = 8 +}; + +SERIAL serial1, serial2; + +int mousepos=-1; +int mousedelay; + +void serial_reset() +{ + serial1.iir = serial1.ier = serial1.lcr = 0; + serial2.iir = serial2.ier = serial2.lcr = 0; + mousedelay = 0; + serial1.fifo_read = serial1.fifo_write = 0; + serial2.fifo_read = serial2.fifo_write = 0; +} + +void serial_update_ints(SERIAL *serial) +{ + int stat = 0; + + serial->iir = 1; + + if ((serial->ier & 4) && (serial->int_status & SERIAL_INT_LSR)) /*Line status interrupt*/ + { + stat = 1; + serial->iir = 6; + } + else if ((serial->ier & 1) && (serial->int_status & SERIAL_INT_RECEIVE)) /*Recieved data available*/ + { + stat = 1; + serial->iir = 4; + } + else if ((serial->ier & 2) && (serial->int_status & SERIAL_INT_TRANSMIT)) /*Transmit data empty*/ + { + stat = 1; + serial->iir = 2; + } + else if ((serial->ier & 8) && (serial->int_status & SERIAL_INT_MSR)) /*Modem status interrupt*/ + { + stat = 1; + serial->iir = 0; + } + + if (stat && ((serial->mctrl & 8) || PCJR)) + picintlevel(1 << serial->irq); + else + picintc(1 << serial->irq); +} + +void serial_write_fifo(SERIAL *serial, uint8_t dat) +{ +// pclog("serial_write_fifo %02X\n", serial->lsr); + serial->fifo[serial->fifo_write] = dat; + serial->fifo_write = (serial->fifo_write + 1) & 0xFF; + if (!(serial->lsr & 1)) + { + serial->lsr |= 1; + serial->int_status |= SERIAL_INT_RECEIVE; + serial_update_ints(serial); + } +} + +uint8_t serial_read_fifo(SERIAL *serial) +{ + if (serial->fifo_read != serial->fifo_write) + { + serial->dat = serial->fifo[serial->fifo_read]; + serial->fifo_read = (serial->fifo_read + 1) & 0xFF; + } + return serial->dat; +} + +void serial_write(uint16_t addr, uint8_t val, void *p) +{ + SERIAL *serial = (SERIAL *)p; +// pclog("Write serial %03X %02X %04X:%04X\n",addr,val,CS,pc); + switch (addr&7) + { + case 0: + if (serial->lcr & 0x80) + { + serial->dlab1 = val; + return; + } + serial->thr = val; + serial->lsr |= 0x20; + serial->int_status |= SERIAL_INT_TRANSMIT; + serial_update_ints(serial); + if (serial->mctrl & 0x10) + { + serial_write_fifo(serial, val); + } + break; + case 1: + if (serial->lcr & 0x80) + { + serial->dlab2 = val; + return; + } + serial->ier = val & 0xf; + serial_update_ints(serial); + break; + case 3: + serial->lcr = val; + break; + case 4: + if ((val & 2) && !(serial->mctrl & 2)) + { + if (serial->rcr_callback) + serial->rcr_callback(serial); +// pclog("RCR raised! sending M\n"); + } + serial->mctrl = val; + if (val & 0x10) + { + uint8_t new_msr; + + new_msr = (val & 0x0c) << 4; + new_msr |= (val & 0x02) ? 0x10: 0; + new_msr |= (val & 0x01) ? 0x20: 0; + + if ((serial->msr ^ new_msr) & 0x10) + new_msr |= 0x01; + if ((serial->msr ^ new_msr) & 0x20) + new_msr |= 0x02; + if ((serial->msr ^ new_msr) & 0x80) + new_msr |= 0x08; + if ((serial->msr & 0x40) && !(new_msr & 0x40)) + new_msr |= 0x04; + + serial->msr = new_msr; + } + break; + case 5: + serial->lsr = val; + if (serial->lsr & 0x01) + serial->int_status |= SERIAL_INT_RECEIVE; + if (serial->lsr & 0x1e) + serial->int_status |= SERIAL_INT_LSR; + if (serial->lsr & 0x20) + serial->int_status |= SERIAL_INT_TRANSMIT; + serial_update_ints(serial); + break; + case 6: + serial->msr = val; + if (serial->msr & 0x0f) + serial->int_status |= SERIAL_INT_MSR; + serial_update_ints(serial); + break; + case 7: + serial->scratch = val; + break; + } +} + +uint8_t serial_read(uint16_t addr, void *p) +{ + SERIAL *serial = (SERIAL *)p; + uint8_t temp = 0; +// pclog("Read serial %03X %04X(%08X):%04X %i %i ", addr, CS, cs, pc, mousedelay, ins); + switch (addr&7) + { + case 0: + if (serial->lcr & 0x80) + { + temp = serial->dlab1; + break; + } + + serial->lsr &= ~1; + serial->int_status &= ~SERIAL_INT_RECEIVE; + serial_update_ints(serial); + temp = serial_read_fifo(serial); + if (serial->fifo_read != serial->fifo_write) + serial->recieve_delay = 1000 * TIMER_USEC; + break; + case 1: + if (serial->lcr & 0x80) + temp = serial->dlab2; + else + temp = serial->ier; + break; + case 2: + temp = serial->iir; + if ((temp & 0xe) == 2) + { + serial->int_status &= ~SERIAL_INT_TRANSMIT; + serial_update_ints(serial); + } + break; + case 3: + temp = serial->lcr; + break; + case 4: + temp = serial->mctrl; + break; + case 5: + if (serial->lsr & 0x20) + serial->lsr |= 0x40; + serial->lsr |= 0x20; + temp = serial->lsr; + if (serial->lsr & 0x1f) + serial->lsr &= ~0x1e; +// serial.lsr |= 0x60; + serial->int_status &= ~SERIAL_INT_LSR; + serial_update_ints(serial); + break; + case 6: + temp = serial->msr; + serial->msr &= ~0x0f; + serial->int_status &= ~SERIAL_INT_MSR; + serial_update_ints(serial); + break; + case 7: + temp = serial->scratch; + break; + } +// pclog("%02X\n",temp); + return temp; +} + +void serial_recieve_callback(void *p) +{ + SERIAL *serial = (SERIAL *)p; + + serial->recieve_delay = 0; + + if (serial->fifo_read != serial->fifo_write) + { + serial->lsr |= 1; + serial->int_status |= SERIAL_INT_RECEIVE; + serial_update_ints(serial); + } +} + +/*Tandy might need COM1 at 2f8*/ +void serial1_init(uint16_t addr, int irq) +{ + memset(&serial1, 0, sizeof(serial1)); + io_sethandler(addr, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); + serial1.irq = irq; + serial1.rcr_callback = NULL; + timer_add(serial_recieve_callback, &serial1.recieve_delay, &serial1.recieve_delay, &serial1); +} +void serial1_set(uint16_t addr, int irq) +{ + serial1_remove(); + io_sethandler(addr, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); + serial1.irq = irq; +} +void serial1_remove() +{ + io_removehandler(0x2e8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); + io_removehandler(0x2f8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); + io_removehandler(0x3e8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); + io_removehandler(0x3f8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial1); +} + +void serial2_init(uint16_t addr, int irq) +{ + memset(&serial2, 0, sizeof(serial2)); + io_sethandler(addr, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); + serial2.irq = irq; + serial2.rcr_callback = NULL; + timer_add(serial_recieve_callback, &serial2.recieve_delay, &serial2.recieve_delay, &serial2); +} +void serial2_set(uint16_t addr, int irq) +{ + serial2_remove(); + io_sethandler(addr, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); + serial2.irq = irq; +} +void serial2_remove() +{ + io_removehandler(0x2e8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); + io_removehandler(0x2f8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); + io_removehandler(0x3e8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); + io_removehandler(0x3f8, 0x0008, serial_read, NULL, NULL, serial_write, NULL, NULL, &serial2); +} diff --git a/src/serial.h b/src/serial.h new file mode 100644 index 000000000..ef04b1f07 --- /dev/null +++ b/src/serial.h @@ -0,0 +1,28 @@ +void serial1_init(uint16_t addr, int irq); +void serial2_init(uint16_t addr, int irq); +void serial1_set(uint16_t addr, int irq); +void serial2_set(uint16_t addr, int irq); +void serial1_remove(); +void serial2_remove(); +void serial_reset(); + +struct SERIAL; + +typedef struct +{ + uint8_t lsr,thr,mctrl,rcr,iir,ier,lcr,msr; + uint8_t dlab1,dlab2; + uint8_t dat; + uint8_t int_status; + uint8_t scratch; + + int irq; + + void (*rcr_callback)(void *p); + uint8_t fifo[256]; + int fifo_read, fifo_write; + + int recieve_delay; +} SERIAL; + +extern SERIAL serial1, serial2; diff --git a/src/sio.c b/src/sio.c new file mode 100644 index 000000000..582874086 --- /dev/null +++ b/src/sio.c @@ -0,0 +1,75 @@ +/*PRD format : + + word 0 - base address + word 1 - bits 1 - 15 = byte count, bit 31 = end of transfer +*/ +#include + +#include "ibm.h" +#include "ide.h" +#include "io.h" +#include "mem.h" +#include "pci.h" + +#include "sio.h" + +static uint8_t card_sio[256]; + +void sio_write(int func, int addr, uint8_t val, void *priv) +{ +// pclog("sio_write: func=%d addr=%02x val=%02x %04x:%08x\n", func, addr, val, CS, pc); + + if ((addr & 0xff) < 4) return; + + if (func > 0) + return; + + if (func == 0) + { + switch (addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0e: + return; + } + card_sio[addr] = val; + } +} + +uint8_t sio_read(int func, int addr, void *priv) +{ +// pclog("sio_read: func=%d addr=%02x %04x:%08x\n", func, addr, CS, pc); + + if (func > 0) + return 0xff; + + return card_sio[addr]; +} + +void sio_init(int card) +{ + pci_add_specific(card, sio_read, sio_write, NULL); + + memset(card_sio, 0, 256); + card_sio[0x00] = 0x86; card_sio[0x01] = 0x80; /*Intel*/ + card_sio[0x02] = 0x84; card_sio[0x03] = 0x04; /*82378ZB (SIO)*/ + card_sio[0x04] = 0x07; card_sio[0x05] = 0x00; + card_sio[0x06] = 0x00; card_sio[0x07] = 0x02; + card_sio[0x08] = 0x00; /*A0 stepping*/ + card_sio[0x40] = 0x20; + card_sio[0x42] = 0x24; + card_sio[0x45] = 0x10; + card_sio[0x46] = 0x0F; + card_sio[0x48] = 0x01; + card_sio[0x4A] = 0x10; + card_sio[0x4B] = 0x0F; + card_sio[0x4C] = 0x56; + card_sio[0x4D] = 0x40; + card_sio[0x4E] = 0x07; + card_sio[0x4F] = 0x4F; + card_sio[0x60] = card_sio[0x61] = card_sio[0x62] = card_sio[0x63] = 0x80; + card_sio[0x80] = 0x78; + card_sio[0xA0] = 0x08; + card_sio[0xA8] = 0x0F; +} diff --git a/src/sio.h b/src/sio.h new file mode 100644 index 000000000..a17f4ffb8 --- /dev/null +++ b/src/sio.h @@ -0,0 +1 @@ +void sio_init(int card); diff --git a/src/sis496.c b/src/sis496.c new file mode 100644 index 000000000..5c350fd86 --- /dev/null +++ b/src/sis496.c @@ -0,0 +1,127 @@ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "pci.h" + +#include "sis496.h" + +typedef struct sis496_t +{ + uint8_t pci_conf[256]; +} sis496_t; + +void sis496_recalcmapping(sis496_t *sis496) +{ + int c; + + for (c = 0; c < 8; c++) + { + uint32_t base = 0xc0000 + (c << 15); + if (sis496->pci_conf[0x44] & (1 << c)) + { + switch (sis496->pci_conf[0x45] & 3) + { + case 0: + mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 1: + mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 2: + mem_set_mem_state(base, 0x8000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + case 3: + mem_set_mem_state(base, 0x8000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + } + } + else + mem_set_mem_state(base, 0x8000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + + flushmmucache(); + shadowbios = (sis496->pci_conf[0x44] & 0xf0); +} + +void sis496_write(int func, int addr, uint8_t val, void *p) +{ + sis496_t *sis496 = (sis496_t *)p; + //pclog("sis496_write : addr=%02x val=%02x\n", addr, val); + switch (addr) + { + case 0x44: /*Shadow configure*/ + if ((sis496->pci_conf[0x44] & val) ^ 0xf0) + { + sis496->pci_conf[0x44] = val; + sis496_recalcmapping(sis496); + } + break; + case 0x45: /*Shadow configure*/ + if ((sis496->pci_conf[0x45] & val) ^ 0x01) + { + sis496->pci_conf[0x45] = val; + sis496_recalcmapping(sis496); + } + break; + } + + if ((addr >= 4 && addr < 8) || addr >= 0x40) + sis496->pci_conf[addr] = val; +} + +uint8_t sis496_read(int func, int addr, void *p) +{ + sis496_t *sis496 = (sis496_t *)p; + + return sis496->pci_conf[addr]; +} + +void *sis496_init() +{ + sis496_t *sis496 = malloc(sizeof(sis496_t)); + memset(sis496, 0, sizeof(sis496_t)); + + pci_add_specific(5, sis496_read, sis496_write, sis496); + + sis496->pci_conf[0x00] = 0x39; /*SiS*/ + sis496->pci_conf[0x01] = 0x10; + sis496->pci_conf[0x02] = 0x96; /*496/497*/ + sis496->pci_conf[0x03] = 0x04; + + sis496->pci_conf[0x04] = 7; + sis496->pci_conf[0x05] = 0; + + sis496->pci_conf[0x06] = 0x80; + sis496->pci_conf[0x07] = 0x02; + + sis496->pci_conf[0x08] = 2; /*Device revision*/ + + sis496->pci_conf[0x09] = 0x00; /*Device class (PCI bridge)*/ + sis496->pci_conf[0x0a] = 0x00; + sis496->pci_conf[0x0b] = 0x06; + + sis496->pci_conf[0x0e] = 0x00; /*Single function device*/ + + return sis496; +} + +void sis496_close(void *p) +{ + sis496_t *sis496 = (sis496_t *)p; + + free(sis496); +} + +device_t sis496_device = +{ + "SiS 496/497", + 0, + sis496_init, + sis496_close, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/sis496.h b/src/sis496.h new file mode 100644 index 000000000..c5bbac2b1 --- /dev/null +++ b/src/sis496.h @@ -0,0 +1 @@ +extern device_t sis496_device; diff --git a/src/sis50x.c b/src/sis50x.c new file mode 100644 index 000000000..817d7ba04 --- /dev/null +++ b/src/sis50x.c @@ -0,0 +1,288 @@ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "pci.h" + +#include "sis50x.h" + +typedef struct sis501_t +{ + uint8_t pci_conf[256]; + uint8_t turbo_reg; +} sis501_t; + +typedef struct sis503_t +{ + uint8_t pci_conf[256]; +} sis503_t; + +typedef struct sis50x_t +{ + uint8_t isa_conf[12]; + uint8_t reg; +} sis50x_t; + +void sis501_recalcmapping(sis501_t *sis501) +{ + int c, d; + + for (c = 0; c < 1; c++) + { + for (d = 0; d < 4; d++) + { + // uint32_t base = (((2 - c) << 16) + 0xc0000) + (d << 14); + uint32_t base = 0xe0000 + (d << 14); + if (sis501->pci_conf[0x54 + c] & (1 << (d + 4))) + { + switch (sis501->pci_conf[0x53] & 0x60) + { + case 0x00: + mem_set_mem_state(base, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_INTERNAL); + break; + case 0x20: + mem_set_mem_state(base, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + break; + case 0x40: + mem_set_mem_state(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_INTERNAL); + break; + case 0x60: + mem_set_mem_state(base, 0x4000, MEM_READ_INTERNAL | MEM_WRITE_EXTERNAL); + break; + } + } + else + mem_set_mem_state(base, 0x4000, MEM_READ_EXTERNAL | MEM_WRITE_EXTERNAL); + } + } + + flushmmucache(); + shadowbios = 1; +} + +void sis501_write(int func, int addr, uint8_t val, void *p) +{ + sis501_t *sis501 = (sis501_t *)p; + //pclog("sis501_write : addr=%02x val=%02x\n", addr, val); + switch (addr) + { + case 0x54: /*Shadow configure*/ + if ((sis501->pci_conf[0x54] & val) ^ 0xf0) + { + sis501->pci_conf[0x54] = val; + sis501_recalcmapping(sis501); + } + break; + } + + if ((addr >= 4 && addr < 8) || addr >= 0x40) + sis501->pci_conf[addr] = val; +} + +void sis501_turbo_write(uint16_t port, uint8_t val, void *priv) +{ + sis501_t *sis501 = (sis501_t *)priv; + + uint8_t valxor = val ^ sis501->turbo_reg; + + sis501->turbo_reg = val; + + if ((val & 4) && (valxor & 4)) + { + if (sis501->turbo_reg & 2) + resetpchard(); + else + softresetx86(); + } +} + +void sis503_write(int func, int addr, uint8_t val, void *p) +{ + sis503_t *sis503 = (sis503_t *)p; + //pclog("sis503_write : addr=%02x val=%02x\n", addr, val); + + if ((addr >= 4 && addr < 8) || addr >= 0x0f) + sis503->pci_conf[addr] = val; +} + +void sis50x_write(uint16_t port, uint8_t val, void *priv) +{ + sis50x_t *sis50x = (sis50x_t *)priv; + + if (port & 1) + { + if (sis50x->reg <= 0xB) sis50x->isa_conf[sis50x->reg] = val; + } + else + { + sis50x->reg = val; + } +} + +uint8_t sis501_read(int func, int addr, void *p) +{ + sis501_t *sis501 = (sis501_t *)p; + + return sis501->pci_conf[addr]; +} + +uint8_t sis501_turbo_read(uint16_t port, void *priv) +{ + sis501_t *sis501 = (sis501_t *)priv; + + return sis501->turbo_reg; +} + +uint8_t sis503_read(int func, int addr, void *p) +{ + sis503_t *sis503 = (sis503_t *)p; + + return sis503->pci_conf[addr]; +} + +uint8_t sis50x_read(uint16_t port, void *priv) +{ + sis50x_t *sis50x = (sis50x_t *)priv; + + if (port & 1) + { + if (sis50x->reg <= 0xB) + return sis50x->isa_conf[sis50x->reg]; + else + return 0xff; + } + else + { + return sis50x->reg; + } +} + +void *sis501_init() +{ + sis501_t *sis501 = malloc(sizeof(sis501_t)); + memset(sis501, 0, sizeof(sis501_t)); + + // io_sethandler(0x0cf9, 0x0001, sis501_turbo_read, NULL, NULL, sis501_turbo_write, NULL, NULL, sis501); + + // pci_add_specific(5, sis501_read, sis501_write, sis501); + pci_add_specific(0, sis501_read, sis501_write, sis501); + + sis501->pci_conf[0x00] = 0x39; /*SiS*/ + sis501->pci_conf[0x01] = 0x10; + sis501->pci_conf[0x02] = 0x06; /*501/502*/ + sis501->pci_conf[0x03] = 0x04; + + sis501->pci_conf[0x04] = 7; + sis501->pci_conf[0x05] = 0; + + sis501->pci_conf[0x06] = 0x80; + sis501->pci_conf[0x07] = 0x02; + + sis501->pci_conf[0x08] = 0; /*Device revision*/ + + sis501->pci_conf[0x09] = 0x00; /*Device class (PCI bridge)*/ + sis501->pci_conf[0x0a] = 0x00; + sis501->pci_conf[0x0b] = 0x06; + + sis501->pci_conf[0x0e] = 0x00; /*Single function device*/ + + shadowbios = 1; + + return sis501; +} + +void *sis503_init() +{ + sis503_t *sis503 = malloc(sizeof(sis503_t)); + memset(sis503, 0, sizeof(sis503_t)); + + // pci_add_specific(6, sis503_read, sis503_write, sis503); + pci_add_specific(1, sis503_read, sis503_write, sis503); + + sis503->pci_conf[0x00] = 0x39; /*SiS*/ + sis503->pci_conf[0x01] = 0x10; + sis503->pci_conf[0x02] = 0x08; /*503*/ + sis503->pci_conf[0x03] = 0x00; + + sis503->pci_conf[0x04] = 7; + sis503->pci_conf[0x05] = 0; + + sis503->pci_conf[0x06] = 0x80; + sis503->pci_conf[0x07] = 0x02; + + sis503->pci_conf[0x08] = 0; /*Device revision*/ + + sis503->pci_conf[0x09] = 0x00; /*Device class (PCI bridge)*/ + sis503->pci_conf[0x0a] = 0x01; + sis503->pci_conf[0x0b] = 0x06; + + sis503->pci_conf[0x0e] = 0x00; /*Single function device*/ + + return sis503; +} + +void *sis50x_init() +{ + sis50x_t *sis50x = malloc(sizeof(sis50x_t)); + memset(sis50x, 0, sizeof(sis50x_t)); + + io_sethandler(0x22, 0x0002, sis50x_read, NULL, NULL, sis50x_write, NULL, NULL, sis50x); +} + +void sis501_close(void *p) +{ + sis501_t *sis501 = (sis501_t *)p; + + free(sis501); +} + +void sis503_close(void *p) +{ + sis503_t *sis503 = (sis503_t *)p; + + free(sis503); +} + +void sis50x_close(void *p) +{ + sis50x_t *sis50x = (sis50x_t *)p; + + free(sis50x); +} + +device_t sis501_device = +{ + "SiS 501/502", + 0, + sis501_init, + sis501_close, + NULL, + NULL, + NULL, + NULL +}; + +device_t sis503_device = +{ + "SiS 503", + 0, + sis503_init, + sis503_close, + NULL, + NULL, + NULL, + NULL +}; + +device_t sis50x_device = +{ + "SiS 50x ISA", + 0, + sis50x_init, + sis50x_close, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/sis50x.h b/src/sis50x.h new file mode 100644 index 000000000..81e898980 --- /dev/null +++ b/src/sis50x.h @@ -0,0 +1,3 @@ +extern device_t sis501_device; +extern device_t sis503_device; +extern device_t sis50x_device; diff --git a/src/sis85c471.c b/src/sis85c471.c new file mode 100644 index 000000000..e38936da1 --- /dev/null +++ b/src/sis85c471.c @@ -0,0 +1,228 @@ +/* + SiS sis85c471 Super I/O Chip + Used by Batman's Revenge +*/ + +#include "ibm.h" +#include "ide.h" + +#include "fdc.h" +#include "fdd.h" +#include "io.h" +#include "lpt.h" +#include "mouse_serial.h" +#include "serial.h" +#include "sis85c471.h" + +static int sis85c471_curreg; +static uint8_t sis85c471_regs[39]; + +void sis85c471_write(uint16_t port, uint8_t val, void *priv) +{ + uint8_t index = (port & 1) ? 0 : 1; + int temp; + uint8_t x; + // pclog("sis85c471_write : port=%04x reg %02X = %02X\n", port, sis85c471_curreg, val); + + if (index) + { + if ((val >= 0x50) && (val <= 0x76)) sis85c471_curreg = val; + return; + } + else + { + if ((sis85c471_curreg < 0x50) || (sis85c471_curreg > 0x76)) return; + x = val ^ sis85c471_regs[sis85c471_curreg - 0x50]; + /* Writes to 0x52 are blocked as otherwise, large hard disks don't read correctly. */ + if (sis85c471_curreg != 0x52) sis85c471_regs[sis85c471_curreg - 0x50] = val; + goto process_value; + } + return; + +process_value: + switch(sis85c471_curreg) + { + case 0x73: +#if 0 + if (x & 0x40) + { + if (val & 0x40) + ide_pri_enable(); + else + ide_pri_disable(); + } +#endif + + if (x & 0x20) + { + if (val & 0x20) + { + serial1_init(0x3f8, 4); + serial2_init(0x2f8, 3); + mouse_serial_init(); + } + else + { + serial1_remove(); + serial2_remove(); + } + } + + if (x & 0x10) + { + if (val & 0x10) + lpt1_init(0x378); + else + lpt1_remove(); + } + + break; + } + sis85c471_curreg = 0; +} + +uint8_t sis85c471_read(uint16_t port, void *priv) +{ + // pclog("sis85c471_read : port=%04x reg %02X\n", port, sis85c471_curreg); + uint8_t index = (port & 1) ? 0 : 1; + uint8_t temp; + + if (index) + return sis85c471_curreg; + else + if ((sis85c471_curreg >= 0x50) && (sis85c471_curreg <= 0x76)) + { + temp = sis85c471_regs[sis85c471_curreg - 0x50]; + sis85c471_curreg = 0; + return temp; + } + else + return 0xFF; +} + +void sis85c471_init() +{ + int i = 0; + + // pclog("SiS 85c471 Init\n"); + + // ide_sec_disable(); + lpt2_remove(); + + sis85c471_curreg = 0; + for (i = 0; i < 0x27; i++) + { + sis85c471_regs[i] = 0; + } + sis85c471_regs[9] = 0x40; + switch (mem_size) + { + case 0: + case 1: + sis85c471_regs[9] |= 0; + break; + case 2: + case 3: + sis85c471_regs[9] |= 1; + break; + case 4: + sis85c471_regs[9] |= 2; + break; + case 5: + sis85c471_regs[9] |= 0x20; + break; + case 6: + case 7: + sis85c471_regs[9] |= 9; + break; + case 8: + case 9: + sis85c471_regs[9] |= 4; + break; + case 10: + case 11: + sis85c471_regs[9] |= 5; + break; + case 12: + case 13: + case 14: + case 15: + sis85c471_regs[9] |= 0xB; + break; + case 16: + sis85c471_regs[9] |= 0x13; + break; + case 17: + sis85c471_regs[9] |= 0x21; + break; + case 18: + case 19: + sis85c471_regs[9] |= 6; + break; + case 20: + case 21: + case 22: + case 23: + sis85c471_regs[9] |= 0xD; + break; + case 24: + case 25: + case 26: + case 27: + case 28: + case 29: + case 30: + case 31: + sis85c471_regs[9] |= 0xE; + break; + case 32: + case 33: + case 34: + case 35: + sis85c471_regs[9] |= 0x1B; + break; + case 36: + case 37: + case 38: + case 39: + sis85c471_regs[9] |= 0xF; + break; + case 40: + case 41: + case 42: + case 43: + case 44: + case 45: + case 46: + case 47: + sis85c471_regs[9] |= 0x17; + break; + case 48: + sis85c471_regs[9] |= 0x1E; + break; + default: + if (mem_size < 64) + { + sis85c471_regs[9] |= 0x1E; + } + else if ((mem_size >= 65) && (mem_size < 68)) + { + sis85c471_regs[9] |= 0x22; + } + else + { + sis85c471_regs[9] |= 0x24; + } + break; + } + + sis85c471_regs[0x11] = 9; + sis85c471_regs[0x12] = 0xFF; + sis85c471_regs[0x23] = 0xF0; + sis85c471_regs[0x26] = 1; + + fdc_update_densel_polarity(1); + fdc_update_densel_force(0); + fdd_swap = 0; + io_sethandler(0x0022, 0x0002, sis85c471_read, NULL, NULL, sis85c471_write, NULL, NULL, NULL); +} diff --git a/src/sis85c471.h b/src/sis85c471.h new file mode 100644 index 000000000..79ebe5dbf --- /dev/null +++ b/src/sis85c471.h @@ -0,0 +1 @@ +extern void sis85c471_init(); diff --git a/src/slirp/COPYRIGHT.txt b/src/slirp/COPYRIGHT.txt new file mode 100644 index 000000000..62ccebae1 --- /dev/null +++ b/src/slirp/COPYRIGHT.txt @@ -0,0 +1,61 @@ +Slirp was written by Danny Gasparovski. +Copyright (c), 1995,1996 All Rights Reserved. + +Slirp is maintained by Kelly Price + +Slirp is free software; "free" as in you don't have to pay for it, and you +are free to do whatever you want with it. I do not accept any donations, +monetary or otherwise, for Slirp. Instead, I would ask you to pass this +potential donation to your favorite charity. In fact, I encourage +*everyone* who finds Slirp useful to make a small donation to their +favorite charity (for example, GreenPeace). This is not a requirement, but +a suggestion from someone who highly values the service they provide. + +The copyright terms and conditions: + +---BEGIN--- + + Copyright (c) 1995,1996 Danny Gasparovski. All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + DANNY GASPAROVSKI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---END--- + +This basically means you can do anything you want with the software, except +1) call it your own, and 2) claim warranty on it. There is no warranty for +this software. None. Nada. If you lose a million dollars while using +Slirp, that's your loss not mine. So, ***USE AT YOUR OWN RISK!***. + +If these conditions cannot be met due to legal restrictions (E.g. where it +is against the law to give out Software without warranty), you must cease +using the software and delete all copies you have. + +Slirp uses code that is copyrighted by the following people/organizations: + +Juha Pirkola. +Gregory M. Christy. +The Regents of the University of California. +Carnegie Mellon University. +The Australian National University. +RSA Data Security, Inc. + +Please read the top of each source file for the details on the various +copyrights. \ No newline at end of file diff --git a/src/slirp/Makefile b/src/slirp/Makefile new file mode 100644 index 000000000..275c054d2 --- /dev/null +++ b/src/slirp/Makefile @@ -0,0 +1,26 @@ +CC=gcc +CFLAGS=-I. -O2 -Wall +DEPS = bootp.h config-host.h config.h ctl.h \ + debug.h icmp_var.h if.h ip.h \ + ip_icmp.h libslirp.h main.h mbuf.h \ + misc.h queue.h sbuf.h slirp.h \ + slirp_config.h socket.h tcp.h tcpip.h \ + tcp_timer.h tcp_var.h tftp.h udp.h + +OBJ = bootp.o cksum.o debug.o if.o ip_icmp.o \ + ip_input.o ip_output.o mbuf.o misc.o queue.o \ + sbuf.o slirp.o socket.o tcp_input.o tcp_output.o \ + tcp_subr.o tcp_timer.o tftp.o udp.o + +%.o: %.c $(DEPS) + $(CC) $(CFLAGS) -c $< -o $@ + +default: libslirp.a + +clean: + rm -f $(OBJ) + rm -f libslirp.a + +libslirp.a: $(OBJ) + ar rcs $@ $^ + ranlib $@ \ No newline at end of file diff --git a/src/slirp/VERSION.txt b/src/slirp/VERSION.txt new file mode 100644 index 000000000..0dd1c2b2b --- /dev/null +++ b/src/slirp/VERSION.txt @@ -0,0 +1 @@ +qemu 0.9.0 (2007/02/05) \ No newline at end of file diff --git a/src/slirp/bootp.c b/src/slirp/bootp.c new file mode 100644 index 000000000..9cbca7520 --- /dev/null +++ b/src/slirp/bootp.c @@ -0,0 +1,242 @@ +/* + * QEMU BOOTP/DHCP server + * + * Copyright (c) 2004 Fabrice Bellard + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ +#include "slirp.h" + +/* XXX: only DHCP is supported */ + +#define NB_ADDR 16 + +#define START_ADDR 15 + +#define LEASE_TIME (24 * 3600) + +typedef struct { + uint8_t allocated; + uint8_t macaddr[6]; +} BOOTPClient; + +BOOTPClient bootp_clients[NB_ADDR]; + +static const uint8_t rfc1533_cookie[] = { RFC1533_COOKIE }; + +static BOOTPClient *get_new_addr(struct in_addr *paddr) +{ + BOOTPClient *bc; + int i; + + for(i = 0; i < NB_ADDR; i++) { + if (!bootp_clients[i].allocated) + goto found; + } + return NULL; + found: + bc = &bootp_clients[i]; + bc->allocated = 1; + paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (i + START_ADDR)); + return bc; +} + +static BOOTPClient *find_addr(struct in_addr *paddr, const uint8_t *macaddr) +{ + BOOTPClient *bc; + int i; + + for(i = 0; i < NB_ADDR; i++) { + if (!memcmp(macaddr, bootp_clients[i].macaddr, 6)) + goto found; + } + return NULL; + found: + bc = &bootp_clients[i]; + bc->allocated = 1; + paddr->s_addr = htonl(ntohl(special_addr.s_addr) | (i + START_ADDR)); + return bc; +} + +static void dhcp_decode(const uint8_t *buf, int size, + int *pmsg_type) +{ + const uint8_t *p, *p_end; + int len, tag; + + *pmsg_type = 0; + + p = buf; + p_end = buf + size; + if (size < 5) + return; + if (memcmp(p, rfc1533_cookie, 4) != 0) + return; + p += 4; + while (p < p_end) { + tag = p[0]; + if (tag == RFC1533_PAD) { + p++; + } else if (tag == RFC1533_END) { + break; + } else { + p++; + if (p >= p_end) + break; + len = *p++; + + switch(tag) { + case RFC2132_MSG_TYPE: + if (len >= 1) + *pmsg_type = p[0]; + break; + default: + break; + } + p += len; + } + } +} + +static void bootp_reply(struct bootp_t *bp) +{ + BOOTPClient *bc; + struct SLIRPmbuf *m; + struct bootp_t *rbp; + struct sockaddr_in saddr, daddr; + struct in_addr dns_addr; + int dhcp_msg_type, val; + uint8_t *q; + + /* extract exact DHCP msg type */ + dhcp_decode(bp->bp_vend, DHCP_OPT_LEN, &dhcp_msg_type); + + if (dhcp_msg_type == 0) + dhcp_msg_type = DHCPREQUEST; /* Force reply for old BOOTP clients */ + + if (dhcp_msg_type != DHCPDISCOVER && + dhcp_msg_type != DHCPREQUEST) + return; + /* XXX: this is a hack to get the client mac address */ + memcpy(client_ethaddr, bp->bp_hwaddr, 6); + + if ((m = m_get()) == NULL) + return; + m->m_data += if_maxlinkhdr; + rbp = (struct bootp_t *)m->m_data; + m->m_data += sizeof(struct udpiphdr); + memset(rbp, 0, sizeof(struct bootp_t)); + + if (dhcp_msg_type == DHCPDISCOVER) { + new_addr: + bc = get_new_addr(&daddr.sin_addr); + if (!bc) + return; + memcpy(bc->macaddr, client_ethaddr, 6); + } else { + bc = find_addr(&daddr.sin_addr, bp->bp_hwaddr); + if (!bc) { + /* if never assigned, behaves as if it was already + assigned (windows fix because it remembers its address) */ + goto new_addr; + } + } + + saddr.sin_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_ALIAS); + saddr.sin_port = htons(BOOTP_SERVER); + + daddr.sin_port = htons(BOOTP_CLIENT); + + rbp->bp_op = BOOTP_REPLY; + rbp->bp_xid = bp->bp_xid; + rbp->bp_htype = 1; + rbp->bp_hlen = 6; + memcpy(rbp->bp_hwaddr, bp->bp_hwaddr, 6); + + rbp->bp_yiaddr = daddr.sin_addr; /* Client IP address */ + rbp->bp_siaddr = saddr.sin_addr; /* Server IP address */ + + q = rbp->bp_vend; + memcpy(q, rfc1533_cookie, 4); + q += 4; + + if (dhcp_msg_type == DHCPDISCOVER) { + *q++ = RFC2132_MSG_TYPE; + *q++ = 1; + *q++ = DHCPOFFER; + } else if (dhcp_msg_type == DHCPREQUEST) { + *q++ = RFC2132_MSG_TYPE; + *q++ = 1; + *q++ = DHCPACK; + } + + if (dhcp_msg_type == DHCPDISCOVER || + dhcp_msg_type == DHCPREQUEST) { + *q++ = RFC2132_SRV_ID; + *q++ = 4; + memcpy(q, &saddr.sin_addr, 4); + q += 4; + + *q++ = RFC1533_NETMASK; + *q++ = 4; + *q++ = 0xff; + *q++ = 0xff; + *q++ = 0xff; + *q++ = 0x00; + + *q++ = RFC1533_GATEWAY; + *q++ = 4; + memcpy(q, &saddr.sin_addr, 4); + q += 4; + + *q++ = RFC1533_DNS; + *q++ = 4; + dns_addr.s_addr = htonl(ntohl(special_addr.s_addr) | CTL_DNS); + memcpy(q, &dns_addr, 4); + q += 4; + + *q++ = RFC2132_LEASE_TIME; + *q++ = 4; + val = htonl(LEASE_TIME); + memcpy(q, &val, 4); + q += 4; + + if (*slirp_hostname) { + val = strlen(slirp_hostname); + *q++ = RFC1533_HOSTNAME; + *q++ = val; + memcpy(q, slirp_hostname, val); + q += val; + } + } + *q++ = RFC1533_END; + + m->m_len = sizeof(struct bootp_t) - + sizeof(struct ip) - sizeof(struct udphdr); + udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); +} + +void bootp_input(struct SLIRPmbuf *m) +{ + struct bootp_t *bp = mtod(m, struct bootp_t *); + + if (bp->bp_op == BOOTP_REQUEST) { + bootp_reply(bp); + } +} diff --git a/src/slirp/bootp.h b/src/slirp/bootp.h new file mode 100644 index 000000000..b2ee26e95 --- /dev/null +++ b/src/slirp/bootp.h @@ -0,0 +1,121 @@ +/* bootp/dhcp defines */ + +#define BOOTP_SERVER 67 +#define BOOTP_CLIENT 68 + +#define BOOTP_REQUEST 1 +#define BOOTP_REPLY 2 + +#define RFC1533_COOKIE 99, 130, 83, 99 +#define RFC1533_PAD 0 +#define RFC1533_NETMASK 1 +#define RFC1533_TIMEOFFSET 2 +#define RFC1533_GATEWAY 3 +#define RFC1533_TIMESERVER 4 +#define RFC1533_IEN116NS 5 +#define RFC1533_DNS 6 +#define RFC1533_LOGSERVER 7 +#define RFC1533_COOKIESERVER 8 +#define RFC1533_LPRSERVER 9 +#define RFC1533_IMPRESSSERVER 10 +#define RFC1533_RESOURCESERVER 11 +#define RFC1533_HOSTNAME 12 +#define RFC1533_BOOTFILESIZE 13 +#define RFC1533_MERITDUMPFILE 14 +#define RFC1533_DOMAINNAME 15 +#define RFC1533_SWAPSERVER 16 +#define RFC1533_ROOTPATH 17 +#define RFC1533_EXTENSIONPATH 18 +#define RFC1533_IPFORWARDING 19 +#define RFC1533_IPSOURCEROUTING 20 +#define RFC1533_IPPOLICYFILTER 21 +#define RFC1533_IPMAXREASSEMBLY 22 +#define RFC1533_IPTTL 23 +#define RFC1533_IPMTU 24 +#define RFC1533_IPMTUPLATEAU 25 +#define RFC1533_INTMTU 26 +#define RFC1533_INTLOCALSUBNETS 27 +#define RFC1533_INTBROADCAST 28 +#define RFC1533_INTICMPDISCOVER 29 +#define RFC1533_INTICMPRESPOND 30 +#define RFC1533_INTROUTEDISCOVER 31 +#define RFC1533_INTROUTESOLICIT 32 +#define RFC1533_INTSTATICROUTES 33 +#define RFC1533_LLTRAILERENCAP 34 +#define RFC1533_LLARPCACHETMO 35 +#define RFC1533_LLETHERNETENCAP 36 +#define RFC1533_TCPTTL 37 +#define RFC1533_TCPKEEPALIVETMO 38 +#define RFC1533_TCPKEEPALIVEGB 39 +#define RFC1533_NISDOMAIN 40 +#define RFC1533_NISSERVER 41 +#define RFC1533_NTPSERVER 42 +#define RFC1533_VENDOR 43 +#define RFC1533_NBNS 44 +#define RFC1533_NBDD 45 +#define RFC1533_NBNT 46 +#define RFC1533_NBSCOPE 47 +#define RFC1533_XFS 48 +#define RFC1533_XDM 49 + +#define RFC2132_REQ_ADDR 50 +#define RFC2132_LEASE_TIME 51 +#define RFC2132_MSG_TYPE 53 +#define RFC2132_SRV_ID 54 +#define RFC2132_PARAM_LIST 55 +#define RFC2132_MAX_SIZE 57 +#define RFC2132_RENEWAL_TIME 58 +#define RFC2132_REBIND_TIME 59 + +#define DHCPDISCOVER 1 +#define DHCPOFFER 2 +#define DHCPREQUEST 3 +#define DHCPACK 5 + +#define RFC1533_VENDOR_MAJOR 0 +#define RFC1533_VENDOR_MINOR 0 + +#define RFC1533_VENDOR_MAGIC 128 +#define RFC1533_VENDOR_ADDPARM 129 +#define RFC1533_VENDOR_ETHDEV 130 +#define RFC1533_VENDOR_HOWTO 132 +#define RFC1533_VENDOR_MNUOPTS 160 +#define RFC1533_VENDOR_SELECTION 176 +#define RFC1533_VENDOR_MOTD 184 +#define RFC1533_VENDOR_NUMOFMOTD 8 +#define RFC1533_VENDOR_IMG 192 +#define RFC1533_VENDOR_NUMOFIMG 16 + +#define RFC1533_END 255 +#define BOOTP_VENDOR_LEN 64 +#define DHCP_OPT_LEN 312 + +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(1) +#endif + +struct bootp_t { + struct ip ip; + struct udphdr udp; + uint8_t bp_op; + uint8_t bp_htype; + uint8_t bp_hlen; + uint8_t bp_hops; + uint32_t bp_xid; + uint16_t bp_secs; + uint16_t unused; + struct in_addr bp_ciaddr; + struct in_addr bp_yiaddr; + struct in_addr bp_siaddr; + struct in_addr bp_giaddr; + uint8_t bp_hwaddr[16]; + uint8_t bp_sname[64]; + uint8_t bp_file[128]; + uint8_t bp_vend[DHCP_OPT_LEN]; +} PACKED__; + +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(PACK_END) +#endif + +void bootp_input(struct SLIRPmbuf *m); diff --git a/src/slirp/cksum.c b/src/slirp/cksum.c new file mode 100644 index 000000000..79df96d34 --- /dev/null +++ b/src/slirp/cksum.c @@ -0,0 +1,137 @@ +/* + * Copyright (c) 1988, 1992, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)in_cksum.c 8.1 (Berkeley) 6/10/93 + * in_cksum.c,v 1.2 1994/08/02 07:48:16 davidg Exp + */ + +#include "slirp.h" + +/* + * Checksum routine for Internet Protocol family headers (Portable Version). + * + * This routine is very heavily used in the network + * code and should be modified for each CPU to be as fast as possible. + * + * XXX Since we will never span more than 1 SLIRPmbuf, we can optimise this + */ + +#define ADDCARRY(x) (x > 65535 ? x -= 65535 : x) +#define REDUCE {l_util.l = sum; sum = l_util.s[0] + l_util.s[1]; ADDCARRY(sum);} + +int cksum(struct SLIRPmbuf *m, int len) +{ + register u_int16_t *w; + register int sum = 0; + register int mlen = 0; + int byte_swapped = 0; + + union { + u_int8_t c[2]; + u_int16_t s; + } s_util; + union { + u_int16_t s[2]; + u_int32_t l; + } l_util; + + if (m->m_len == 0) + goto cont; + w = mtod(m, u_int16_t *); + + mlen = m->m_len; + + if (len < mlen) + mlen = len; + len -= mlen; + /* + * Force to even boundary. + */ + if ((1 & (long) w) && (mlen > 0)) { + REDUCE; + sum <<= 8; + s_util.c[0] = *(u_int8_t *)w; + w = (u_int16_t *)((int8_t *)w + 1); + mlen--; + byte_swapped = 1; + } + /* + * Unroll the loop to make overhead from + * branches &c small. + */ + while ((mlen -= 32) >= 0) { + sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; + sum += w[4]; sum += w[5]; sum += w[6]; sum += w[7]; + sum += w[8]; sum += w[9]; sum += w[10]; sum += w[11]; + sum += w[12]; sum += w[13]; sum += w[14]; sum += w[15]; + w += 16; + } + mlen += 32; + while ((mlen -= 8) >= 0) { + sum += w[0]; sum += w[1]; sum += w[2]; sum += w[3]; + w += 4; + } + mlen += 8; + if (mlen == 0 && byte_swapped == 0) + goto cont; + REDUCE; + while ((mlen -= 2) >= 0) { + sum += *w++; + } + + if (byte_swapped) { + REDUCE; + sum <<= 8; + byte_swapped = 0; + if (mlen == -1) { + s_util.c[1] = *(u_int8_t *)w; + sum += s_util.s; + mlen = 0; + } else + + mlen = -1; + } else if (mlen == -1) + s_util.c[0] = *(u_int8_t *)w; + +cont: +#ifdef SLIRP_DEBUG + if (len) { + DEBUG_ERROR((dfd, "cksum: out of data\n")); + DEBUG_ERROR((dfd, " len = %d\n", len)); + } +#endif + if (mlen == -1) { + /* The last SLIRPmbuf has odd # of bytes. Follow the + standard (the odd byte may be shifted left by 8 bits + or not as determined by endian-ness of the machine) */ + s_util.c[1] = 0; + sum += s_util.s; + } + REDUCE; + return (~sum & 0xffff); +} diff --git a/src/slirp/config-host.h b/src/slirp/config-host.h new file mode 100644 index 000000000..2983fc727 --- /dev/null +++ b/src/slirp/config-host.h @@ -0,0 +1,9 @@ +/* Automatically generated by configure - do not modify */ +#define CONFIG_QEMU_SHAREDIR "/c/Program Files/Qemu" +#define HOST_I386 1 +#define HOST_LONG_BITS 32 +#define CONFIG_WIN32 1 +#define CONFIG_GDBSTUB 1 +#define CONFIG_SLIRP 1 +#define QEMU_VERSION "0.9.0" +#define CONFIG_UNAME_RELEASE "" diff --git a/src/slirp/config.h b/src/slirp/config.h new file mode 100644 index 000000000..d9043ae85 --- /dev/null +++ b/src/slirp/config.h @@ -0,0 +1,9 @@ +/* Automatically generated by configure - do not modify */ +#include "config-host.h" +#define CONFIG_QEMU_PREFIX "/usr/gnemul/qemu-i386" +#define TARGET_ARCH "i386" +#define TARGET_I386 1 +#define USE_KQEMU 1 +#define CONFIG_SOFTMMU 1 +#define CONFIG_SDL 1 +#define HAVE_STRDUP 1 diff --git a/src/slirp/ctl.h b/src/slirp/ctl.h new file mode 100644 index 000000000..4a8576dc1 --- /dev/null +++ b/src/slirp/ctl.h @@ -0,0 +1,7 @@ +#define CTL_CMD 0 +#define CTL_EXEC 1 +#define CTL_ALIAS 2 +#define CTL_DNS 3 + +#define CTL_SPECIAL "10.0.2.0" +#define CTL_LOCAL "10.0.2.15" diff --git a/src/slirp/debug.c b/src/slirp/debug.c new file mode 100644 index 000000000..556e02672 --- /dev/null +++ b/src/slirp/debug.c @@ -0,0 +1,440 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * Portions copyright (c) 2000 Kelly Price. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#include "slirp.h" + +FILE *dfd = NULL; +#ifdef SLIRP_DEBUG +int dostats = 1; +#else +int dostats = 0; +#endif +int slirp_debug = 0; + +extern char *strerror _P((int)); + +/* Carry over one item from main.c so that the tty's restored. + * Only done when the tty being used is /dev/tty --RedWolf */ +extern struct termios slirp_tty_settings; +extern int slirp_tty_restore; + + +void +debug_init(file, dbg) + char *file; + int dbg; +{ + /* Close the old debugging file */ + if (dfd) + fclose(dfd); + + dfd = fopen(file,"w"); + if (dfd != NULL) { +#if 1 + fprintf(dfd,"Slirp %s - Debugging Started.\n", SLIRP_VERSION); +#endif + fprintf(dfd,"Debugging Started level %i.\r\n",dbg); + fflush(dfd); + slirp_debug = dbg; + } else { + lprint("Error: Debugging file \"%s\" could not be opened: %s\r\n", + file, strerror(errno)); + } +} + +/* + * Dump a packet in the same format as tcpdump -x + */ +#ifdef SLIRP_DEBUG +void +dump_packet(dat, n) + void *dat; + int n; +{ + u_char *pptr = (u_char *)dat; + int j,k; + + n /= 16; + n++; + DEBUG_MISC((dfd, "PACKET DUMPED: \n")); + for(j = 0; j < n; j++) { + for(k = 0; k < 6; k++) + DEBUG_MISC((dfd, "%02x ", *pptr++)); + DEBUG_MISC((dfd, "\n")); + fflush(dfd); + } +} +#endif + +#if 0 +/* + * Statistic routines + * + * These will print statistics to the screen, the debug file (dfd), or + * a buffer, depending on "type", so that the stats can be sent over + * the link as well. + */ + +void +ttystats(ttyp) + struct ttys *ttyp; +{ + struct slirp_ifstats *is = &ttyp->ifstats; + char buff[512]; + + lprint(" \r\n"); + + if (if_comp & IF_COMPRESS) + strcpy(buff, "on"); + else if (if_comp & IF_NOCOMPRESS) + strcpy(buff, "off"); + else + strcpy(buff, "off (for now)"); + lprint("Unit %d:\r\n", ttyp->unit); + lprint(" using %s encapsulation (VJ compression is %s)\r\n", ( +#ifdef USE_PPP + ttyp->proto==PROTO_PPP?"PPP": +#endif + "SLIP"), buff); + lprint(" %d baudrate\r\n", ttyp->baud); + lprint(" interface is %s\r\n", ttyp->up?"up":"down"); + lprint(" using fd %d, guardian pid is %d\r\n", ttyp->fd, ttyp->pid); +#ifndef FULL_BOLT + lprint(" towrite is %d bytes\r\n", ttyp->towrite); +#endif + if (ttyp->zeros) + lprint(" %d zeros have been typed\r\n", ttyp->zeros); + else if (ttyp->ones) + lprint(" %d ones have been typed\r\n", ttyp->ones); + lprint("Interface stats:\r\n"); + lprint(" %6d output packets sent (%d bytes)\r\n", is->out_pkts, is->out_bytes); + lprint(" %6d output packets dropped (%d bytes)\r\n", is->out_errpkts, is->out_errbytes); + lprint(" %6d input packets received (%d bytes)\r\n", is->in_pkts, is->in_bytes); + lprint(" %6d input packets dropped (%d bytes)\r\n", is->in_errpkts, is->in_errbytes); + lprint(" %6d bad input packets\r\n", is->in_mbad); +} + +void +allttystats() +{ + struct ttys *ttyp; + + for (ttyp = ttys; ttyp; ttyp = ttyp->next) + ttystats(ttyp); +} +#endif + +void +ipstats() +{ + lprint(" \r\n"); + + lprint("IP stats:\r\n"); + lprint(" %6d total packets received (%d were unaligned)\r\n", + ipstat.ips_total, ipstat.ips_unaligned); + lprint(" %6d with incorrect version\r\n", ipstat.ips_badvers); + lprint(" %6d with bad header checksum\r\n", ipstat.ips_badsum); + lprint(" %6d with length too short (len < sizeof(iphdr))\r\n", ipstat.ips_tooshort); + lprint(" %6d with length too small (len < ip->len)\r\n", ipstat.ips_toosmall); + lprint(" %6d with bad header length\r\n", ipstat.ips_badhlen); + lprint(" %6d with bad packet length\r\n", ipstat.ips_badlen); + lprint(" %6d fragments received\r\n", ipstat.ips_fragments); + lprint(" %6d fragments dropped\r\n", ipstat.ips_fragdropped); + lprint(" %6d fragments timed out\r\n", ipstat.ips_fragtimeout); + lprint(" %6d packets reassembled ok\r\n", ipstat.ips_reassembled); + lprint(" %6d outgoing packets fragmented\r\n", ipstat.ips_fragmented); + lprint(" %6d total outgoing fragments\r\n", ipstat.ips_ofragments); + lprint(" %6d with bad protocol field\r\n", ipstat.ips_noproto); + lprint(" %6d total packets delivered\r\n", ipstat.ips_delivered); +} + +#if 0 +void +vjstats() +{ + lprint(" \r\n"); + + lprint("VJ compression stats:\r\n"); + + lprint(" %6d outbound packets (%d compressed)\r\n", + comp_s.sls_packets, comp_s.sls_compressed); + lprint(" %6d searches for connection stats (%d misses)\r\n", + comp_s.sls_searches, comp_s.sls_misses); + lprint(" %6d inbound uncompressed packets\r\n", comp_s.sls_uncompressedin); + lprint(" %6d inbound compressed packets\r\n", comp_s.sls_compressedin); + lprint(" %6d inbound unknown type packets\r\n", comp_s.sls_errorin); + lprint(" %6d inbound packets tossed due to error\r\n", comp_s.sls_tossed); +} +#endif + +void +tcpstats() +{ + lprint(" \r\n"); + + lprint("TCP stats:\r\n"); + + lprint(" %6d packets sent\r\n", tcpstat.tcps_sndtotal); + lprint(" %6d data packets (%d bytes)\r\n", + tcpstat.tcps_sndpack, tcpstat.tcps_sndbyte); + lprint(" %6d data packets retransmitted (%d bytes)\r\n", + tcpstat.tcps_sndrexmitpack, tcpstat.tcps_sndrexmitbyte); + lprint(" %6d ack-only packets (%d delayed)\r\n", + tcpstat.tcps_sndacks, tcpstat.tcps_delack); + lprint(" %6d URG only packets\r\n", tcpstat.tcps_sndurg); + lprint(" %6d window probe packets\r\n", tcpstat.tcps_sndprobe); + lprint(" %6d window update packets\r\n", tcpstat.tcps_sndwinup); + lprint(" %6d control (SYN/FIN/RST) packets\r\n", tcpstat.tcps_sndctrl); + lprint(" %6d times tcp_output did nothing\r\n", tcpstat.tcps_didnuttin); + + lprint(" %6d packets received\r\n", tcpstat.tcps_rcvtotal); + lprint(" %6d acks (for %d bytes)\r\n", + tcpstat.tcps_rcvackpack, tcpstat.tcps_rcvackbyte); + lprint(" %6d duplicate acks\r\n", tcpstat.tcps_rcvdupack); + lprint(" %6d acks for unsent data\r\n", tcpstat.tcps_rcvacktoomuch); + lprint(" %6d packets received in sequence (%d bytes)\r\n", + tcpstat.tcps_rcvpack, tcpstat.tcps_rcvbyte); + lprint(" %6d completely duplicate packets (%d bytes)\r\n", + tcpstat.tcps_rcvduppack, tcpstat.tcps_rcvdupbyte); + + lprint(" %6d packets with some duplicate data (%d bytes duped)\r\n", + tcpstat.tcps_rcvpartduppack, tcpstat.tcps_rcvpartdupbyte); + lprint(" %6d out-of-order packets (%d bytes)\r\n", + tcpstat.tcps_rcvoopack, tcpstat.tcps_rcvoobyte); + lprint(" %6d packets of data after window (%d bytes)\r\n", + tcpstat.tcps_rcvpackafterwin, tcpstat.tcps_rcvbyteafterwin); + lprint(" %6d window probes\r\n", tcpstat.tcps_rcvwinprobe); + lprint(" %6d window update packets\r\n", tcpstat.tcps_rcvwinupd); + lprint(" %6d packets received after close\r\n", tcpstat.tcps_rcvafterclose); + lprint(" %6d discarded for bad checksums\r\n", tcpstat.tcps_rcvbadsum); + lprint(" %6d discarded for bad header offset fields\r\n", + tcpstat.tcps_rcvbadoff); + + lprint(" %6d connection requests\r\n", tcpstat.tcps_connattempt); + lprint(" %6d connection accepts\r\n", tcpstat.tcps_accepts); + lprint(" %6d connections established (including accepts)\r\n", tcpstat.tcps_connects); + lprint(" %6d connections closed (including %d drop)\r\n", + tcpstat.tcps_closed, tcpstat.tcps_drops); + lprint(" %6d embryonic connections dropped\r\n", tcpstat.tcps_conndrops); + lprint(" %6d segments we tried to get rtt (%d succeeded)\r\n", + tcpstat.tcps_segstimed, tcpstat.tcps_rttupdated); + lprint(" %6d retransmit timeouts\r\n", tcpstat.tcps_rexmttimeo); + lprint(" %6d connections dropped by rxmt timeout\r\n", + tcpstat.tcps_timeoutdrop); + lprint(" %6d persist timeouts\r\n", tcpstat.tcps_persisttimeo); + lprint(" %6d keepalive timeouts\r\n", tcpstat.tcps_keeptimeo); + lprint(" %6d keepalive probes sent\r\n", tcpstat.tcps_keepprobe); + lprint(" %6d connections dropped by keepalive\r\n", tcpstat.tcps_keepdrops); + lprint(" %6d correct ACK header predictions\r\n", tcpstat.tcps_predack); + lprint(" %6d correct data packet header predictions\n", tcpstat.tcps_preddat); + lprint(" %6d TCP cache misses\r\n", tcpstat.tcps_socachemiss); + + +/* lprint(" Packets received too short: %d\r\n", tcpstat.tcps_rcvshort); */ +/* lprint(" Segments dropped due to PAWS: %d\r\n", tcpstat.tcps_pawsdrop); */ + +} + +void +udpstats() +{ + lprint(" \r\n"); + + lprint("UDP stats:\r\n"); + lprint(" %6d datagrams received\r\n", udpstat.udps_ipackets); + lprint(" %6d with packets shorter than header\r\n", udpstat.udps_hdrops); + lprint(" %6d with bad checksums\r\n", udpstat.udps_badsum); + lprint(" %6d with data length larger than packet\r\n", udpstat.udps_badlen); + lprint(" %6d UDP socket cache misses\r\n", udpstat.udpps_pcbcachemiss); + lprint(" %6d datagrams sent\r\n", udpstat.udps_opackets); +} + +void +icmpstats() +{ + lprint(" \r\n"); + lprint("ICMP stats:\r\n"); + lprint(" %6d ICMP packets received\r\n", icmpstat.icps_received); + lprint(" %6d were too short\r\n", icmpstat.icps_tooshort); + lprint(" %6d with bad checksums\r\n", icmpstat.icps_checksum); + lprint(" %6d with type not supported\r\n", icmpstat.icps_notsupp); + lprint(" %6d with bad type feilds\r\n", icmpstat.icps_badtype); + lprint(" %6d ICMP packets sent in reply\r\n", icmpstat.icps_reflect); +} + +void +mbufstats() +{ + struct SLIRPmbuf *m; + int i; + + lprint(" \r\n"); + + lprint("Mbuf stats:\r\n"); + + lprint(" %6d mbufs allocated (%d max)\r\n", mbuf_alloced, mbuf_max); + + i = 0; + for (m = m_freelist.m_next; m != &m_freelist; m = m->m_next) + i++; + lprint(" %6d mbufs on free list\r\n", i); + + i = 0; + for (m = m_usedlist.m_next; m != &m_usedlist; m = m->m_next) + i++; + lprint(" %6d mbufs on used list\r\n", i); + lprint(" %6d mbufs queued as packets\r\n\r\n", if_queued); +} + + +void sockstats(void) +{ + char buff[256]; + int n; + struct SLIRPsocket *so; + + lprint(" \r\n"); + + lprint( + "Proto[state] Sock Local Address, Port Remote Address, Port RecvQ SendQ\r\n"); + + for (so = tcb.so_next; so != &tcb; so = so->so_next) { + + n = sprintf(buff, "tcp[%s]", so->so_tcpcb?tcpstates[so->so_tcpcb->t_state]:"NONE"); + while (n < 17) + buff[n++] = ' '; + buff[17] = 0; + lprint("%s %3d %15s %5d ", + buff, so->s, + inet_ntoa(so->so_laddr), ntohs(so->so_lport)); + lprint("%15s %5d %5d %5d\r\n", + inet_ntoa(so->so_faddr), ntohs(so->so_fport), + so->so_rcv.sb_cc, so->so_snd.sb_cc); + + } + + for (so = udb.so_next; so != &udb; so = so->so_next) { + + n = sprintf(buff, "udp[%d sec]", (so->so_expire - curtime) / 1000); + while (n < 17) + buff[n++] = ' '; + buff[17] = 0; + lprint("%s %3d %15s %5d ", + buff, so->s, + inet_ntoa(so->so_laddr), ntohs(so->so_lport)); + lprint("%15s %5d %5d %5d\r\n", + inet_ntoa(so->so_faddr), ntohs(so->so_fport), + so->so_rcv.sb_cc, so->so_snd.sb_cc); + } +} + + + +void printf_sockstats(void) +{ + char buff[256]; + int n; + struct SLIRPsocket *so; + + printf(" \r\n"); + + printf( + "Proto[state] Sock Local Address, Port Remote Address, Port RecvQ SendQ\r\n"); + + for (so = tcb.so_next; so != &tcb; so = so->so_next) { + + n = sprintf(buff, "tcp[%s]", so->so_tcpcb?tcpstates[so->so_tcpcb->t_state]:"NONE"); + while (n < 17) + buff[n++] = ' '; + buff[17] = 0; + printf("%s %3d %15s %5d ", + buff, so->s, + inet_ntoa(so->so_laddr), ntohs(so->so_lport)); + printf("%15s %5d %5d %5d\r\n", + inet_ntoa(so->so_faddr), ntohs(so->so_fport), + so->so_rcv.sb_cc, so->so_snd.sb_cc); + + } + + for (so = udb.so_next; so != &udb; so = so->so_next) { + + n = sprintf(buff, "udp[%d sec]", (so->so_expire - curtime) / 1000); + while (n < 17) + buff[n++] = ' '; + buff[17] = 0; + printf("%s %3d %15s %5d ", + buff, so->s, + inet_ntoa(so->so_laddr), ntohs(so->so_lport)); + printf("%15s %5d %5d %5d\r\n", + inet_ntoa(so->so_faddr), ntohs(so->so_fport), + so->so_rcv.sb_cc, so->so_snd.sb_cc); + } +printf("\n\n"); +} + +//Simple code to purge and close open sockets. +//This way we can open/close/open/close.. +void purgesocks(void) +{ + struct SLIRPsocket *so; + + for (so = tcb.so_next; so != &tcb; so = so->so_next) { + + closesocket(so->s); //close the socket + } +} + +#if 1 +void +slirp_exit(exit_status) + int exit_status; +{ +// struct ttys *ttyp; + + DEBUG_CALL("slirp_exit"); + DEBUG_ARG("exit_status = %d", exit_status); + + if (dostats) { + lprint_print = (int (*) _P((void *, const char *, va_list)))vfprintf; + if (!dfd) + debug_init("slirp_stats", 0xf); + lprint_arg = (char **)&dfd; + + ipstats(); + tcpstats(); + udpstats(); + icmpstats(); + mbufstats(); + sockstats(); + fclose(dfd); +// allttystats(); +// vjstats(); + } + +// for (ttyp = ttys; ttyp; ttyp = ttyp->next) +// tty_detached(ttyp, 1); + +// if (slirp_forked) { +// /* Menendez time */ +// if (kill(getppid(), SIGQUIT) < 0) +// lprint("Couldn't kill parent process %ld!\n", +// (long) getppid()); +// } + + /* Restore the terminal if we gotta */ +// if(slirp_tty_restore) +// tcsetattr(0,TCSANOW, &slirp_tty_settings); /* NOW DAMMIT! */ +// exit(exit_status); + + //This will iterate though the sockets, and close them all (think redirects) + //PCem will have SLiRP open, close several times, which trips up SLiRP + //So for now I go through the sockets and close them + purgesocks(); + +} +#endif diff --git a/src/slirp/debug.h b/src/slirp/debug.h new file mode 100644 index 000000000..9a8c5e8c8 --- /dev/null +++ b/src/slirp/debug.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#define PRN_STDERR 1 +#define PRN_SPRINTF 2 + +extern FILE *dfd; +extern FILE *lfd; +extern int dostats; +extern int slirp_debug; + +#define DBG_CALL 0x1 +#define DBG_MISC 0x2 +#define DBG_ERROR 0x4 +#define DEBUG_DEFAULT DBG_CALL|DBG_MISC|DBG_ERROR + +#ifdef SLIRP_DEBUG +#define DEBUG_CALL(x) if (slirp_debug & DBG_CALL) { fprintf(dfd, "%s...\n", x); fflush(dfd); } +#define DEBUG_ARG(x, y) if (slirp_debug & DBG_CALL) { fputc(' ', dfd); fprintf(dfd, x, y); fputc('\n', dfd); fflush(dfd); } +#define DEBUG_ARGS(x) if (slirp_debug & DBG_CALL) { fprintf x ; fflush(dfd); } +#define DEBUG_MISC(x) if (slirp_debug & DBG_MISC) { fprintf x ; fflush(dfd); } +#define DEBUG_ERROR(x) if (slirp_debug & DBG_ERROR) {fprintf x ; fflush(dfd); } + + +#else + +#define DEBUG_CALL(x) +#define DEBUG_ARG(x, y) +#define DEBUG_ARGS(x) +#define DEBUG_MISC(x) +#define DEBUG_ERROR(x) + +#endif + +void debug_init _P((char *, int)); +//void ttystats _P((struct ttys *)); +void allttystats _P((void)); +void ipstats _P((void)); +void vjstats _P((void)); +void tcpstats _P((void)); +void udpstats _P((void)); +void icmpstats _P((void)); +void mbufstats _P((void)); +void sockstats _P((void)); +void slirp_exit _P((int)); + diff --git a/src/slirp/icmp_var.h b/src/slirp/icmp_var.h new file mode 100644 index 000000000..9af222fb7 --- /dev/null +++ b/src/slirp/icmp_var.h @@ -0,0 +1,65 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)icmp_var.h 8.1 (Berkeley) 6/10/93 + * icmp_var.h,v 1.4 1995/02/16 00:27:40 wollman Exp + */ + +#ifndef _NETINET_ICMP_VAR_H_ +#define _NETINET_ICMP_VAR_H_ + +/* + * Variables related to this implementation + * of the internet control message protocol. + */ +struct icmpstat { +/* statistics related to input messages processed */ + u_long icps_received; /* #ICMP packets received */ + u_long icps_tooshort; /* packet < ICMP_MINLEN */ + u_long icps_checksum; /* bad checksum */ + u_long icps_notsupp; /* #ICMP packets not supported */ + u_long icps_badtype; /* #with bad type feild */ + u_long icps_reflect; /* number of responses */ +}; + +/* + * Names for ICMP sysctl objects + */ +#define ICMPCTL_MASKREPL 1 /* allow replies to netmask requests */ +#define ICMPCTL_STATS 2 /* statistics (read-only) */ +#define ICMPCTL_MAXID 3 + +#define ICMPCTL_NAMES { \ + { 0, 0 }, \ + { "maskrepl", CTLTYPE_INT }, \ + { "stats", CTLTYPE_STRUCT }, \ +} + +extern struct icmpstat icmpstat; + +#endif diff --git a/src/slirp/if.c b/src/slirp/if.c new file mode 100644 index 000000000..24f1b9947 --- /dev/null +++ b/src/slirp/if.c @@ -0,0 +1,322 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#include "slirp.h" + +int if_mtu, if_mru; +int if_comp; +int if_maxlinkhdr; +int if_queued = 0; /* Number of packets queued so far */ +int if_thresh = 10; /* Number of packets queued before we start sending + * (to prevent allocing too many SLIRPmbufs) */ + +struct SLIRPmbuf if_fastq; /* fast queue (for interactive data) */ +struct SLIRPmbuf if_batchq; /* queue for non-interactive data */ +struct SLIRPmbuf *next_m; /* Pointer to next SLIRPmbuf to output */ + +#define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm)) + +void +ifs_insque(ifm, ifmhead) + struct SLIRPmbuf *ifm, *ifmhead; +{ + ifm->ifs_next = ifmhead->ifs_next; + ifmhead->ifs_next = ifm; + ifm->ifs_prev = ifmhead; + ifm->ifs_next->ifs_prev = ifm; +} + +void +ifs_remque(ifm) + struct SLIRPmbuf *ifm; +{ + ifm->ifs_prev->ifs_next = ifm->ifs_next; + ifm->ifs_next->ifs_prev = ifm->ifs_prev; +} + +void +if_init() +{ +#if 0 + /* + * Set if_maxlinkhdr to 48 because it's 40 bytes for TCP/IP, + * and 8 bytes for PPP, but need to have it on an 8byte boundary + */ +#ifdef USE_PPP + if_maxlinkhdr = 48; +#else + if_maxlinkhdr = 40; +#endif +#else + /* 2 for alignment, 14 for ethernet, 40 for TCP/IP */ + if_maxlinkhdr = 2 + 14 + 40; +#endif + if_mtu = 1500; + if_mru = 1500; + if_comp = IF_AUTOCOMP; + if_fastq.ifq_next = if_fastq.ifq_prev = &if_fastq; + if_batchq.ifq_next = if_batchq.ifq_prev = &if_batchq; + // sl_compress_init(&comp_s); + next_m = &if_batchq; +} + +#if 0 +/* + * This shouldn't be needed since the modem is blocking and + * we don't expect any signals, but what the hell.. + */ +inline int +writen(fd, bptr, n) + int fd; + char *bptr; + int n; +{ + int ret; + int total; + + /* This should succeed most of the time */ + ret = send(fd, bptr, n,0); + if (ret == n || ret <= 0) + return ret; + + /* Didn't write everything, go into the loop */ + total = ret; + while (n > total) { + ret = send(fd, bptr+total, n-total,0); + if (ret <= 0) + return ret; + total += ret; + } + return total; +} + +/* + * if_input - read() the tty, do "top level" processing (ie: check for any escapes), + * and pass onto (*ttyp->if_input) + * + * XXXXX Any zeros arriving by themselves are NOT placed into the arriving packet. + */ +#define INBUFF_SIZE 2048 /* XXX */ +void +if_input(ttyp) + struct ttys *ttyp; +{ + u_char if_inbuff[INBUFF_SIZE]; + int if_n; + + DEBUG_CALL("if_input"); + DEBUG_ARG("ttyp = %lx", (long)ttyp); + + if_n = recv(ttyp->fd, (char *)if_inbuff, INBUFF_SIZE,0); + + DEBUG_MISC((dfd, " read %d bytes\n", if_n)); + + if (if_n <= 0) { + if (if_n == 0 || (errno != EINTR && errno != EAGAIN)) { + if (ttyp->up) + link_up--; + tty_detached(ttyp, 0); + } + return; + } + if (if_n == 1) { + if (*if_inbuff == '0') { + ttyp->ones = 0; + if (++ttyp->zeros >= 5) + slirp_exit(0); + return; + } + if (*if_inbuff == '1') { + ttyp->zeros = 0; + if (++ttyp->ones >= 5) + tty_detached(ttyp, 0); + return; + } + } + ttyp->ones = ttyp->zeros = 0; + + (*ttyp->if_input)(ttyp, if_inbuff, if_n); +} +#endif + +/* + * if_output: Queue packet into an output queue. + * There are 2 output queue's, if_fastq and if_batchq. + * Each output queue is a doubly linked list of double linked lists + * of SLIRPmbufs, each list belonging to one "session" (socket). This + * way, we can output packets fairly by sending one packet from each + * session, instead of all the packets from one session, then all packets + * from the next session, etc. Packets on the if_fastq get absolute + * priority, but if one session hogs the link, it gets "downgraded" + * to the batchq until it runs out of packets, then it'll return + * to the fastq (eg. if the user does an ls -alR in a telnet session, + * it'll temporarily get downgraded to the batchq) + */ +void +if_output(so, ifm) + struct SLIRPsocket *so; + struct SLIRPmbuf *ifm; +{ + struct SLIRPmbuf *ifq; + int on_fastq = 1; + + DEBUG_CALL("if_output"); + DEBUG_ARG("so = %lx", (long)so); + DEBUG_ARG("ifm = %lx", (long)ifm); + + /* + * First remove the SLIRPmbuf from m_usedlist, + * since we're gonna use m_next and m_prev ourselves + * XXX Shouldn't need this, gotta change dtom() etc. + */ + if (ifm->m_flags & M_USEDLIST) { + remque(ifm); + ifm->m_flags &= ~M_USEDLIST; + } + + /* + * See if there's already a batchq list for this session. + * This can include an interactive session, which should go on fastq, + * but gets too greedy... hence it'll be downgraded from fastq to batchq. + * We mustn't put this packet back on the fastq (or we'll send it out of order) + * XXX add cache here? + */ + for (ifq = if_batchq.ifq_prev; ifq != &if_batchq; ifq = ifq->ifq_prev) { + if (so == ifq->ifq_so) { + /* A match! */ + ifm->ifq_so = so; + ifs_insque(ifm, ifq->ifs_prev); + goto diddit; + } + } + + /* No match, check which queue to put it on */ + if (so && (so->so_iptos & IPTOS_LOWDELAY)) { + ifq = if_fastq.ifq_prev; + on_fastq = 1; + /* + * Check if this packet is a part of the last + * packet's session + */ + if (ifq->ifq_so == so) { + ifm->ifq_so = so; + ifs_insque(ifm, ifq->ifs_prev); + goto diddit; + } + } else + ifq = if_batchq.ifq_prev; + + /* Create a new doubly linked list for this session */ + ifm->ifq_so = so; + ifs_init(ifm); + insque(ifm, ifq); + +diddit: + ++if_queued; + + if (so) { + /* Update *_queued */ + so->so_queued++; + so->so_nqueued++; + /* + * Check if the interactive session should be downgraded to + * the batchq. A session is downgraded if it has queued 6 + * packets without pausing, and at least 3 of those packets + * have been sent over the link + * (XXX These are arbitrary numbers, probably not optimal..) + */ + if (on_fastq && ((so->so_nqueued >= 6) && + (so->so_nqueued - so->so_queued) >= 3)) { + + /* Remove from current queue... */ + remque(ifm->ifs_next); + + /* ...And insert in the new. That'll teach ya! */ + insque(ifm->ifs_next, &if_batchq); + } + } + +#ifndef FULL_BOLT + /* + * This prevents us from malloc()ing too many SLIRPmbufs + */ + if (link_up) { + /* if_start will check towrite */ + if_start(); + } +#endif +} + +/* + * Send a packet + * We choose a packet based on it's position in the output queues; + * If there are packets on the fastq, they are sent FIFO, before + * everything else. Otherwise we choose the first packet from the + * batchq and send it. the next packet chosen will be from the session + * after this one, then the session after that one, and so on.. So, + * for example, if there are 3 ftp session's fighting for bandwidth, + * one packet will be sent from the first session, then one packet + * from the second session, then one packet from the third, then back + * to the first, etc. etc. + */ +void +if_start(void) +{ + struct SLIRPmbuf *ifm, *ifqt; + + DEBUG_CALL("if_start"); + + if (if_queued == 0) + return; /* Nothing to do */ + + again: + /* check if we can really output */ + if (!slirp_can_output()) + return; + + /* + * See which queue to get next packet from + * If there's something in the fastq, select it immediately + */ + if (if_fastq.ifq_next != &if_fastq) { + ifm = if_fastq.ifq_next; + } else { + /* Nothing on fastq, see if next_m is valid */ + if (next_m != &if_batchq) + ifm = next_m; + else + ifm = if_batchq.ifq_next; + + /* Set which packet to send on next iteration */ + next_m = ifm->ifq_next; + } + /* Remove it from the queue */ + ifqt = ifm->ifq_prev; + remque(ifm); + --if_queued; + + /* If there are more packets for this session, re-queue them */ + if (ifm->ifs_next != /* ifm->ifs_prev != */ ifm) { + insque(ifm->ifs_next, ifqt); + ifs_remque(ifm); + } + + /* Update so_queued */ + if (ifm->ifq_so) { + if (--ifm->ifq_so->so_queued == 0) + /* If there's no more queued, reset nqueued */ + ifm->ifq_so->so_nqueued = 0; + } + + /* Encapsulate the packet for sending */ + if_encap((uint8_t*)ifm->m_data, ifm->m_len); + + m_free(ifm); + + if (if_queued) + goto again; +} diff --git a/src/slirp/if.h b/src/slirp/if.h new file mode 100644 index 000000000..85a5a96d2 --- /dev/null +++ b/src/slirp/if.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#ifndef _IF_H_ +#define _IF_H_ + +#define IF_COMPRESS 0x01 /* We want compression */ +#define IF_NOCOMPRESS 0x02 /* Do not do compression */ +#define IF_AUTOCOMP 0x04 /* Autodetect (default) */ +#define IF_NOCIDCOMP 0x08 /* CID compression */ + +/* Needed for FreeBSD */ +#undef if_mtu +extern int if_mtu; +extern int if_mru; /* MTU and MRU */ +extern int if_comp; /* Flags for compression */ +extern int if_maxlinkhdr; +extern int if_queued; /* Number of packets queued so far */ +extern int if_thresh; /* Number of packets queued before we start sending + * (to prevent allocing too many SLIRPmbufs) */ + +extern struct SLIRPmbuf if_fastq; /* fast queue (for interactive data) */ +extern struct SLIRPmbuf if_batchq; /* queue for non-interactive data */ +extern struct SLIRPmbuf *next_m; + +#define ifs_init(ifm) ((ifm)->ifs_next = (ifm)->ifs_prev = (ifm)) + +/* Interface statistics */ +struct slirp_ifstats { + u_int out_pkts; /* Output packets */ + u_int out_bytes; /* Output bytes */ + u_int out_errpkts; /* Output Error Packets */ + u_int out_errbytes; /* Output Error Bytes */ + u_int in_pkts; /* Input packets */ + u_int in_bytes; /* Input bytes */ + u_int in_errpkts; /* Input Error Packets */ + u_int in_errbytes; /* Input Error Bytes */ + + u_int bytes_saved; /* Number of bytes that compression "saved" */ + /* ie: number of bytes that didn't need to be sent over the link + * because of compression */ + + u_int in_mbad; /* Bad incoming packets */ +}; + +#endif diff --git a/src/slirp/ip.h b/src/slirp/ip.h new file mode 100644 index 000000000..203aa750c --- /dev/null +++ b/src/slirp/ip.h @@ -0,0 +1,341 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ip.h 8.1 (Berkeley) 6/10/93 + * ip.h,v 1.3 1994/08/21 05:27:30 paul Exp + */ + +#ifndef _IP_H_ +#define _IP_H_ + +#ifdef WORDS_BIGENDIAN +# ifndef NTOHL +# define NTOHL(d) +# endif +# ifndef NTOHS +# define NTOHS(d) +# endif +# ifndef HTONL +# define HTONL(d) +# endif +# ifndef HTONS +# define HTONS(d) +# endif +#else +# ifndef NTOHL +# define NTOHL(d) ((d) = ntohl((d))) +# endif +# ifndef NTOHS +# define NTOHS(d) ((d) = ntohs((u_int16_t)(d))) +# endif +# ifndef HTONL +# define HTONL(d) ((d) = htonl((d))) +# endif +# ifndef HTONS +# define HTONS(d) ((d) = htons((u_int16_t)(d))) +# endif +#endif + +typedef u_int32_t n_long; /* long as received from the net */ + +/* + * Definitions for internet protocol version 4. + * Per RFC 791, September 1981. + */ +#define IPVERSION 4 + +#if defined(_MSC_VER) +#pragma pack(push, 1) +#endif + +/* + * Structure of an internet header, naked of options. + */ +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(1) +#endif + +struct ip { +#ifdef WORDS_BIGENDIAN + u_char ip_v:4, /* version */ + ip_hl:4; /* header length */ +#else + u_char ip_hl:4, /* header length */ + ip_v:4; /* version */ +#endif + u_int8_t ip_tos; /* type of service */ + u_int16_t ip_len; /* total length */ + u_int16_t ip_id; /* identification */ + u_int16_t ip_off; /* fragment offset field */ +#define IP_DF 0x4000 /* don't fragment flag */ +#define IP_MF 0x2000 /* more fragments flag */ +#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ + u_int8_t ip_ttl; /* time to live */ + u_int8_t ip_p; /* protocol */ + u_int16_t ip_sum; /* checksum */ + struct in_addr ip_src,ip_dst; /* source and dest address */ +} PACKED__; + +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(PACK_END) //WAS 0 +#endif + +#define IP_MAXPACKET 65535 /* maximum packet size */ + +/* + * Definitions for IP type of service (ip_tos) + */ +#define IPTOS_LOWDELAY 0x10 +#define IPTOS_THROUGHPUT 0x08 +#define IPTOS_RELIABILITY 0x04 + +/* + * Definitions for options. + */ +#define IPOPT_COPIED(o) ((o)&0x80) +#define IPOPT_CLASS(o) ((o)&0x60) +#define IPOPT_NUMBER(o) ((o)&0x1f) + +#define IPOPT_CONTROL 0x00 +#define IPOPT_RESERVED1 0x20 +#define IPOPT_DEBMEAS 0x40 +#define IPOPT_RESERVED2 0x60 + +#define IPOPT_EOL 0 /* end of option list */ +#define IPOPT_NOP 1 /* no operation */ + +#define IPOPT_RR 7 /* record packet route */ +#define IPOPT_TS 68 /* timestamp */ +#define IPOPT_SECURITY 130 /* provide s,c,h,tcc */ +#define IPOPT_LSRR 131 /* loose source route */ +#define IPOPT_SATID 136 /* satnet id */ +#define IPOPT_SSRR 137 /* strict source route */ + +/* + * Offsets to fields in options other than EOL and NOP. + */ +#define IPOPT_OPTVAL 0 /* option ID */ +#define IPOPT_OLEN 1 /* option length */ +#define IPOPT_OFFSET 2 /* offset within option */ +#define IPOPT_MINOFF 4 /* min value of above */ + +/* + * Time stamp option structure. + */ +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(1) +#endif + +struct ip_timestamp { + u_int8_t ipt_code; /* IPOPT_TS */ + u_int8_t ipt_len; /* size of structure (variable) */ + u_int8_t ipt_ptr; /* index of current entry */ +#ifdef WORDS_BIGENDIAN + u_char ipt_oflw:4, /* overflow counter */ + ipt_flg:4; /* flags, see below */ +#else + u_char ipt_flg:4, /* flags, see below */ + ipt_oflw:4; /* overflow counter */ +#endif + union ipt_timestamp { + n_long ipt_time[1]; + struct ipt_ta { + struct in_addr ipt_addr; + n_long ipt_time; + } ipt_ta[1]; + } ipt_timestamp; +} PACKED__; + +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(PACK_END) +#endif + +/* flag bits for ipt_flg */ +#define IPOPT_TS_TSONLY 0 /* timestamps only */ +#define IPOPT_TS_TSANDADDR 1 /* timestamps and addresses */ +#define IPOPT_TS_PRESPEC 3 /* specified modules only */ + +/* bits for security (not byte swapped) */ +#define IPOPT_SECUR_UNCLASS 0x0000 +#define IPOPT_SECUR_CONFID 0xf135 +#define IPOPT_SECUR_EFTO 0x789a +#define IPOPT_SECUR_MMMM 0xbc4d +#define IPOPT_SECUR_RESTR 0xaf13 +#define IPOPT_SECUR_SECRET 0xd788 +#define IPOPT_SECUR_TOPSECRET 0x6bc5 + +/* + * Internet implementation parameters. + */ +#define MAXTTL 255 /* maximum time to live (seconds) */ +#define IPDEFTTL 64 /* default ttl, from RFC 1340 */ +#define IPFRAGTTL 60 /* time to live for frags, slowhz */ +#define IPTTLDEC 1 /* subtracted when forwarding */ + +#define IP_MSS 576 /* default maximum segment size */ + +#ifdef HAVE_SYS_TYPES32_H /* Overcome some Solaris 2.x junk */ +#include +#else +#if SIZEOF_CHAR_P == 4 +typedef SLIRPcaddr_t caddr32_t; +#else +typedef u_int32_t caddr32_t; +#endif +#endif + +#if SIZEOF_CHAR_P == 4 +typedef struct ipq *ipqp_32; +typedef struct ipasfrag *ipasfragp_32; +#else +typedef caddr32_t ipqp_32; +typedef caddr32_t ipasfragp_32; +#endif + +/* + * Overlay for ip header used by other protocols (tcp, udp). + */ +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(1) +#endif + +struct ipovly { + caddr32_t ih_next, ih_prev; /* for protocol sequence q's */ + u_int8_t ih_x1; /* (unused) */ + u_int8_t ih_pr; /* protocol */ + u_int16_t ih_len; /* protocol length */ + struct in_addr ih_src; /* source internet address */ + struct in_addr ih_dst; /* destination internet address */ +} PACKED__; + +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(PACK_END) +#endif + +#if defined(_MSC_VER) +#pragma pack(pop) +#endif + +/* + * Ip reassembly queue structure. Each fragment + * being reassembled is attached to one of these structures. + * They are timed out after ipq_ttl drops to 0, and may also + * be reclaimed if memory becomes tight. + * size 28 bytes + */ +struct ipq { + ipqp_32 next,prev; /* to other reass headers */ + u_int8_t ipq_ttl; /* time for reass q to live */ + u_int8_t ipq_p; /* protocol of this fragment */ + u_int16_t ipq_id; /* sequence id for reassembly */ + ipasfragp_32 ipq_next,ipq_prev; + /* to ip headers of fragments */ + struct in_addr ipq_src,ipq_dst; +}; + +/* + * Ip header, when holding a fragment. + * + * Note: ipf_next must be at same offset as ipq_next above + */ +struct ipasfrag { +#ifdef WORDS_BIGENDIAN + u_char ip_v:4, + ip_hl:4; +#else + u_char ip_hl:4, + ip_v:4; +#endif + /* BUG : u_int changed to u_int8_t. + * sizeof(u_int)==4 on linux 2.0 + */ + u_int8_t ipf_mff; /* XXX overlays ip_tos: use low bit + * to avoid destroying tos (PPPDTRuu); + * copied from (ip_off&IP_MF) */ + u_int16_t ip_len; + u_int16_t ip_id; + u_int16_t ip_off; + u_int8_t ip_ttl; + u_int8_t ip_p; + u_int16_t ip_sum; + ipasfragp_32 ipf_next; /* next fragment */ + ipasfragp_32 ipf_prev; /* previous fragment */ +}; + +/* + * Structure stored in mbuf in inpcb.ip_options + * and passed to ip_output when ip options are in use. + * The actual length of the options (including ipopt_dst) + * is in m_len. + */ +#define MAX_IPOPTLEN 40 + +struct ipoption { + struct in_addr ipopt_dst; /* first-hop dst if source routed */ + int8_t ipopt_list[MAX_IPOPTLEN]; /* options proper */ +}; + +/* + * Structure attached to inpcb.ip_moptions and + * passed to ip_output when IP multicast options are in use. + */ + +struct ipstat { + u_long ips_total; /* total packets received */ + u_long ips_badsum; /* checksum bad */ + u_long ips_tooshort; /* packet too short */ + u_long ips_toosmall; /* not enough data */ + u_long ips_badhlen; /* ip header length < data size */ + u_long ips_badlen; /* ip length < ip header length */ + u_long ips_fragments; /* fragments received */ + u_long ips_fragdropped; /* frags dropped (dups, out of space) */ + u_long ips_fragtimeout; /* fragments timed out */ + u_long ips_forward; /* packets forwarded */ + u_long ips_cantforward; /* packets rcvd for unreachable dest */ + u_long ips_redirectsent; /* packets forwarded on same net */ + u_long ips_noproto; /* unknown or unsupported protocol */ + u_long ips_delivered; /* datagrams delivered to upper level*/ + u_long ips_localout; /* total ip packets generated here */ + u_long ips_odropped; /* lost packets due to nobufs, etc. */ + u_long ips_reassembled; /* total packets reassembled ok */ + u_long ips_fragmented; /* datagrams successfully fragmented */ + u_long ips_ofragments; /* output fragments created */ + u_long ips_cantfrag; /* don't fragment flag was set, etc. */ + u_long ips_badoptions; /* error in option processing */ + u_long ips_noroute; /* packets discarded due to no route */ + u_long ips_badvers; /* ip version != 4 */ + u_long ips_rawout; /* total raw ip packets generated */ + u_long ips_unaligned; /* times the ip packet was not aligned */ +}; + +extern struct ipstat ipstat; +extern struct ipq ipq; /* ip reass. queue */ +extern u_int16_t ip_id; /* ip packet ctr, for ids */ +extern int ip_defttl; /* default IP ttl */ + +#endif diff --git a/src/slirp/ip_icmp.c b/src/slirp/ip_icmp.c new file mode 100644 index 000000000..3106147bd --- /dev/null +++ b/src/slirp/ip_icmp.c @@ -0,0 +1,371 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ip_icmp.c 8.2 (Berkeley) 1/4/94 + * ip_icmp.c,v 1.7 1995/05/30 08:09:42 rgrimes Exp + */ + +#include "slirp.h" +#include "ip_icmp.h" + +struct icmpstat icmpstat; + +/* The message sent when emulating PING */ +/* Be nice and tell them it's just a psuedo-ping packet */ +char icmp_ping_msg[] = "This is a psuedo-PING packet used by Slirp to emulate ICMP ECHO-REQUEST packets.\n"; + +/* list of actions for icmp_error() on RX of an icmp message */ +static int icmp_flush[19] = { +/* ECHO REPLY (0) */ 0, + 1, + 1, +/* DEST UNREACH (3) */ 1, +/* SOURCE QUENCH (4)*/ 1, +/* REDIRECT (5) */ 1, + 1, + 1, +/* ECHO (8) */ 0, +/* ROUTERADVERT (9) */ 1, +/* ROUTERSOLICIT (10) */ 1, +/* TIME EXCEEDED (11) */ 1, +/* PARAMETER PROBLEM (12) */ 1, +/* TIMESTAMP (13) */ 0, +/* TIMESTAMP REPLY (14) */ 0, +/* INFO (15) */ 0, +/* INFO REPLY (16) */ 0, +/* ADDR MASK (17) */ 0, +/* ADDR MASK REPLY (18) */ 0 +}; + +/* + * Process a received ICMP message. + */ +void +icmp_input(m, hlen) + struct SLIRPmbuf *m; + int hlen; +{ + register struct icmp *icp; + register struct ip *ip=mtod(m, struct ip *); + int icmplen=ip->ip_len; + /* int code; */ + + DEBUG_CALL("icmp_input"); + DEBUG_ARG("m = %lx", (long )m); + DEBUG_ARG("m_len = %d", m->m_len); + + icmpstat.icps_received++; + + /* + * Locate icmp structure in SLIRPmbuf, and check + * that its not corrupted and of at least minimum length. + */ + if (icmplen < ICMP_MINLEN) { /* min 8 bytes payload */ + icmpstat.icps_tooshort++; + freeit: + m_freem(m); + goto end_error; + } + + m->m_len -= hlen; + m->m_data += hlen; + icp = mtod(m, struct icmp *); + if (cksum(m, icmplen)) { + icmpstat.icps_checksum++; + goto freeit; + } + m->m_len += hlen; + m->m_data -= hlen; + + /* icmpstat.icps_inhist[icp->icmp_type]++; */ + /* code = icp->icmp_code; */ + + DEBUG_ARG("icmp_type = %d", icp->icmp_type); + switch (icp->icmp_type) { + case ICMP_ECHO: + icp->icmp_type = ICMP_ECHOREPLY; + ip->ip_len += hlen; /* since ip_input subtracts this */ + if (ip->ip_dst.s_addr == alias_addr.s_addr) { + icmp_reflect(m); + } else { + struct SLIRPsocket *so; + struct sockaddr_in addr; + if ((so = socreate()) == NULL) goto freeit; + if(udp_attach(so) == -1) { + DEBUG_MISC((dfd,"icmp_input udp_attach errno = %d-%s\n", + errno,strerror(errno))); + sofree(so); + m_free(m); + goto end_error; + } + so->so_m = m; + so->so_faddr = ip->ip_dst; + so->so_fport = htons(7); + so->so_laddr = ip->ip_src; + so->so_lport = htons(9); + so->so_iptos = ip->ip_tos; + so->so_type = IPPROTO_ICMP; + so->so_state = SS_ISFCONNECTED; + + /* Send the packet */ + addr.sin_family = AF_INET; + if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { + /* It's an alias */ + switch(ntohl(so->so_faddr.s_addr) & 0xff) { + case CTL_DNS: + addr.sin_addr = dns_addr; + break; + case CTL_ALIAS: + default: + addr.sin_addr = loopback_addr; + break; + } + } else { + addr.sin_addr = so->so_faddr; + } + addr.sin_port = so->so_fport; + if(sendto(so->s, icmp_ping_msg, strlen(icmp_ping_msg), 0, + (struct sockaddr *)&addr, sizeof(addr)) == -1) { + DEBUG_MISC((dfd,"icmp_input udp sendto tx errno = %d-%s\n", + errno,strerror(errno))); + icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno)); + udp_detach(so); + } + } /* if ip->ip_dst.s_addr == alias_addr.s_addr */ + break; + case ICMP_UNREACH: + /* XXX? report error? close socket? */ + case ICMP_TIMXCEED: + case ICMP_PARAMPROB: + case ICMP_SOURCEQUENCH: + case ICMP_TSTAMP: + case ICMP_MASKREQ: + case ICMP_REDIRECT: + icmpstat.icps_notsupp++; + m_freem(m); + break; + + default: + icmpstat.icps_badtype++; + m_freem(m); + } /* swith */ + +end_error: + /* m is m_free()'d xor put in a socket xor or given to ip_send */ + return; +} + + +/* + * Send an ICMP message in response to a situation + * + * RFC 1122: 3.2.2 MUST send at least the IP header and 8 bytes of header. MAY send more (we do). + * MUST NOT change this header information. + * MUST NOT reply to a multicast/broadcast IP address. + * MUST NOT reply to a multicast/broadcast MAC address. + * MUST reply to only the first fragment. + */ +/* + * Send ICMP_UNREACH back to the source regarding msrc. + * SLIRPmbuf *msrc is used as a template, but is NOT m_free()'d. + * It is reported as the bad ip packet. The header should + * be fully correct and in host byte order. + * ICMP fragmentation is illegal. All machines must accept 576 bytes in one + * packet. The maximum payload is 576-20(ip hdr)-8(icmp hdr)=548 + */ + +#define ICMP_MAXDATALEN (IP_MSS-28) +void +icmp_error(msrc, type, code, minsize, message) + struct SLIRPmbuf *msrc; + u_char type; + u_char code; + int minsize; + char *message; +{ + unsigned hlen, shlen, s_ip_len; + register struct ip *ip; + register struct icmp *icp; + register struct SLIRPmbuf *m; + + DEBUG_CALL("icmp_error"); + DEBUG_ARG("msrc = %lx", (long )msrc); + DEBUG_ARG("msrc_len = %d", msrc->m_len); + + if(type!=ICMP_UNREACH && type!=ICMP_TIMXCEED) goto end_error; + + /* check msrc */ + if(!msrc) goto end_error; + ip = mtod(msrc, struct ip *); +#if SLIRP_DEBUG + { char bufa[20], bufb[20]; + strcpy(bufa, inet_ntoa(ip->ip_src)); + strcpy(bufb, inet_ntoa(ip->ip_dst)); + DEBUG_MISC((dfd, " %.16s to %.16s\n", bufa, bufb)); + } +#endif + if(ip->ip_off & IP_OFFMASK) goto end_error; /* Only reply to fragment 0 */ + + shlen=ip->ip_hl << 2; + s_ip_len=ip->ip_len; + if(ip->ip_p == IPPROTO_ICMP) { + icp = (struct icmp *)((char *)ip + shlen); + /* + * Assume any unknown ICMP type is an error. This isn't + * specified by the RFC, but think about it.. + */ + if(icp->icmp_type>18 || icmp_flush[icp->icmp_type]) goto end_error; + } + + /* make a copy */ + if(!(m=m_get())) goto end_error; /* get SLIRPmbuf */ + { u_int new_m_size; + new_m_size=sizeof(struct ip )+ICMP_MINLEN+msrc->m_len+ICMP_MAXDATALEN; + if(new_m_size>m->m_size) m_inc(m, new_m_size); + } + memcpy(m->m_data, msrc->m_data, msrc->m_len); + m->m_len = msrc->m_len; /* copy msrc to m */ + + /* make the header of the reply packet */ + ip = mtod(m, struct ip *); + hlen= sizeof(struct ip ); /* no options in reply */ + + /* fill in icmp */ + m->m_data += hlen; + m->m_len -= hlen; + + icp = mtod(m, struct icmp *); + + if(minsize) s_ip_len=shlen+ICMP_MINLEN; /* return header+8b only */ + else if(s_ip_len>ICMP_MAXDATALEN) /* maximum size */ + s_ip_len=ICMP_MAXDATALEN; + + m->m_len=ICMP_MINLEN+s_ip_len; /* 8 bytes ICMP header */ + + /* min. size = 8+sizeof(struct ip)+8 */ + + icp->icmp_type = type; + icp->icmp_code = code; + icp->icmp_id = 0; + icp->icmp_seq = 0; + + memcpy(&icp->icmp_ip, msrc->m_data, s_ip_len); /* report the ip packet */ + HTONS(icp->icmp_ip.ip_len); + HTONS(icp->icmp_ip.ip_id); + HTONS(icp->icmp_ip.ip_off); + +#if SLIRP_DEBUG + if(message) { /* DEBUG : append message to ICMP packet */ + int message_len; + char *cpnt; + message_len=strlen(message); + if(message_len>ICMP_MAXDATALEN) message_len=ICMP_MAXDATALEN; + cpnt=(char *)m->m_data+m->m_len; + memcpy(cpnt, message, message_len); + m->m_len+=message_len; + } +#endif + + icp->icmp_cksum = 0; + icp->icmp_cksum = cksum(m, m->m_len); + + m->m_data -= hlen; + m->m_len += hlen; + + /* fill in ip */ + ip->ip_hl = hlen >> 2; + ip->ip_len = (u_int16_t)m->m_len; + + ip->ip_tos=((ip->ip_tos & 0x1E) | 0xC0); /* high priority for errors */ + + ip->ip_ttl = MAXTTL; + ip->ip_p = IPPROTO_ICMP; + ip->ip_dst = ip->ip_src; /* ip adresses */ + ip->ip_src = alias_addr; + + (void ) ip_output((struct SLIRPsocket *)NULL, m); + + icmpstat.icps_reflect++; + +end_error: + return; +} +#undef ICMP_MAXDATALEN + +/* + * Reflect the ip packet back to the source + */ +void +icmp_reflect(m) + struct SLIRPmbuf *m; +{ + register struct ip *ip = mtod(m, struct ip *); + int hlen = ip->ip_hl << 2; + int optlen = hlen - sizeof(struct ip ); + register struct icmp *icp; + + /* + * Send an icmp packet back to the ip level, + * after supplying a checksum. + */ + m->m_data += hlen; + m->m_len -= hlen; + icp = mtod(m, struct icmp *); + + icp->icmp_cksum = 0; + icp->icmp_cksum = cksum(m, ip->ip_len - hlen); + + m->m_data -= hlen; + m->m_len += hlen; + + /* fill in ip */ + if (optlen > 0) { + /* + * Strip out original options by copying rest of first + * SLIRPmbuf's data back, and adjust the IP length. + */ + memmove((SLIRPcaddr_t)(ip + 1), (SLIRPcaddr_t)ip + hlen, + (unsigned )(m->m_len - hlen)); + hlen -= optlen; + ip->ip_hl = hlen >> 2; + ip->ip_len -= optlen; + m->m_len -= optlen; + } + + ip->ip_ttl = MAXTTL; + { /* swap */ + struct in_addr icmp_dst; + icmp_dst = ip->ip_dst; + ip->ip_dst = ip->ip_src; + ip->ip_src = icmp_dst; + } + + (void ) ip_output((struct SLIRPsocket *)NULL, m); + + icmpstat.icps_reflect++; +} diff --git a/src/slirp/ip_icmp.h b/src/slirp/ip_icmp.h new file mode 100644 index 000000000..20fcda1bd --- /dev/null +++ b/src/slirp/ip_icmp.h @@ -0,0 +1,168 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ip_icmp.h 8.1 (Berkeley) 6/10/93 + * ip_icmp.h,v 1.4 1995/05/30 08:09:43 rgrimes Exp + */ + +#ifndef _NETINET_IP_ICMP_H_ +#define _NETINET_IP_ICMP_H_ + +/* + * Interface Control Message Protocol Definitions. + * Per RFC 792, September 1981. + */ + +typedef u_int32_t n_time; + +/* + * Structure of an icmp header. + */ +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(1) +#endif + +struct icmp { + u_char icmp_type; /* type of message, see below */ + u_char icmp_code; /* type sub code */ + u_short icmp_cksum; /* ones complement cksum of struct */ + union { + u_char ih_pptr; /* ICMP_PARAMPROB */ + struct in_addr ih_gwaddr; /* ICMP_REDIRECT */ + struct ih_idseq { + u_short icd_id; + u_short icd_seq; + } ih_idseq; + int ih_void; + + /* ICMP_UNREACH_NEEDFRAG -- Path MTU Discovery (RFC1191) */ + struct ih_pmtu { + u_short ipm_void; + u_short ipm_nextmtu; + } ih_pmtu; + } icmp_hun; +#define icmp_pptr icmp_hun.ih_pptr +#define icmp_gwaddr icmp_hun.ih_gwaddr +#define icmp_id icmp_hun.ih_idseq.icd_id +#define icmp_seq icmp_hun.ih_idseq.icd_seq +#define icmp_void icmp_hun.ih_void +#define icmp_pmvoid icmp_hun.ih_pmtu.ipm_void +#define icmp_nextmtu icmp_hun.ih_pmtu.ipm_nextmtu + union { + struct id_ts { + n_time its_otime; + n_time its_rtime; + n_time its_ttime; + } id_ts; + struct id_ip { + struct ip idi_ip; + /* options and then 64 bits of data */ + } id_ip; + uint32_t id_mask; + char id_data[1]; + } icmp_dun; +#define icmp_otime icmp_dun.id_ts.its_otime +#define icmp_rtime icmp_dun.id_ts.its_rtime +#define icmp_ttime icmp_dun.id_ts.its_ttime +#define icmp_ip icmp_dun.id_ip.idi_ip +#define icmp_mask icmp_dun.id_mask +#define icmp_data icmp_dun.id_data +} PACKED__; + +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(0) +#endif + +/* + * Lower bounds on packet lengths for various types. + * For the error advice packets must first insure that the + * packet is large enought to contain the returned ip header. + * Only then can we do the check to see if 64 bits of packet + * data have been returned, since we need to check the returned + * ip header length. + */ +#define ICMP_MINLEN 8 /* abs minimum */ +#define ICMP_TSLEN (8 + 3 * sizeof (n_time)) /* timestamp */ +#define ICMP_MASKLEN 12 /* address mask */ +#define ICMP_ADVLENMIN (8 + sizeof (struct ip) + 8) /* min */ +#define ICMP_ADVLEN(p) (8 + ((p)->icmp_ip.ip_hl << 2) + 8) + /* N.B.: must separately check that ip_hl >= 5 */ + +/* + * Definition of type and code field values. + */ +#define ICMP_ECHOREPLY 0 /* echo reply */ +#define ICMP_UNREACH 3 /* dest unreachable, codes: */ +#define ICMP_UNREACH_NET 0 /* bad net */ +#define ICMP_UNREACH_HOST 1 /* bad host */ +#define ICMP_UNREACH_PROTOCOL 2 /* bad protocol */ +#define ICMP_UNREACH_PORT 3 /* bad port */ +#define ICMP_UNREACH_NEEDFRAG 4 /* IP_DF caused drop */ +#define ICMP_UNREACH_SRCFAIL 5 /* src route failed */ +#define ICMP_UNREACH_NET_UNKNOWN 6 /* unknown net */ +#define ICMP_UNREACH_HOST_UNKNOWN 7 /* unknown host */ +#define ICMP_UNREACH_ISOLATED 8 /* src host isolated */ +#define ICMP_UNREACH_NET_PROHIB 9 /* prohibited access */ +#define ICMP_UNREACH_HOST_PROHIB 10 /* ditto */ +#define ICMP_UNREACH_TOSNET 11 /* bad tos for net */ +#define ICMP_UNREACH_TOSHOST 12 /* bad tos for host */ +#define ICMP_SOURCEQUENCH 4 /* packet lost, slow down */ +#define ICMP_REDIRECT 5 /* shorter route, codes: */ +#define ICMP_REDIRECT_NET 0 /* for network */ +#define ICMP_REDIRECT_HOST 1 /* for host */ +#define ICMP_REDIRECT_TOSNET 2 /* for tos and net */ +#define ICMP_REDIRECT_TOSHOST 3 /* for tos and host */ +#define ICMP_ECHO 8 /* echo service */ +#define ICMP_ROUTERADVERT 9 /* router advertisement */ +#define ICMP_ROUTERSOLICIT 10 /* router solicitation */ +#define ICMP_TIMXCEED 11 /* time exceeded, code: */ +#define ICMP_TIMXCEED_INTRANS 0 /* ttl==0 in transit */ +#define ICMP_TIMXCEED_REASS 1 /* ttl==0 in reass */ +#define ICMP_PARAMPROB 12 /* ip header bad */ +#define ICMP_PARAMPROB_OPTABSENT 1 /* req. opt. absent */ +#define ICMP_TSTAMP 13 /* timestamp request */ +#define ICMP_TSTAMPREPLY 14 /* timestamp reply */ +#define ICMP_IREQ 15 /* information request */ +#define ICMP_IREQREPLY 16 /* information reply */ +#define ICMP_MASKREQ 17 /* address mask request */ +#define ICMP_MASKREPLY 18 /* address mask reply */ + +#define ICMP_MAXTYPE 18 + +#define ICMP_INFOTYPE(type) \ + ((type) == ICMP_ECHOREPLY || (type) == ICMP_ECHO || \ + (type) == ICMP_ROUTERADVERT || (type) == ICMP_ROUTERSOLICIT || \ + (type) == ICMP_TSTAMP || (type) == ICMP_TSTAMPREPLY || \ + (type) == ICMP_IREQ || (type) == ICMP_IREQREPLY || \ + (type) == ICMP_MASKREQ || (type) == ICMP_MASKREPLY) + +void icmp_input _P((struct SLIRPmbuf *, int)); +void icmp_error _P((struct SLIRPmbuf *, u_char, u_char, int, char *)); +void icmp_reflect _P((struct SLIRPmbuf *)); + +#endif diff --git a/src/slirp/ip_input.c b/src/slirp/ip_input.c new file mode 100644 index 000000000..fb8f3fcf1 --- /dev/null +++ b/src/slirp/ip_input.c @@ -0,0 +1,693 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ip_input.c 8.2 (Berkeley) 1/4/94 + * ip_input.c,v 1.11 1994/11/16 10:17:08 jkh Exp + */ + +/* + * Changes and additions relating to SLiRP are + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#include "slirp.h" +#include "ip_icmp.h" + +int ip_defttl; +struct ipstat ipstat; +struct ipq ipq; + +/* + * IP initialization: fill in IP protocol switch table. + * All protocols not implemented in kernel go to raw IP protocol handler. + */ +void +ip_init() +{ + ipq.next = ipq.prev = (ipqp_32)&ipq; + ip_id = tt.tv_sec & 0xffff; + udp_init(); + tcp_init(); + ip_defttl = IPDEFTTL; +} + +/* + * Ip input routine. Checksum and byte swap header. If fragmented + * try to reassemble. Process options. Pass to next level. + */ +void +ip_input(m) + struct SLIRPmbuf *m; +{ + register struct ip *ip; + u_int hlen; + + DEBUG_CALL("ip_input"); + DEBUG_ARG("m = %lx", (long)m); + DEBUG_ARG("m_len = %d", m->m_len); + + ipstat.ips_total++; + + if (m->m_len < sizeof (struct ip)) { + ipstat.ips_toosmall++; + return; + } + + ip = mtod(m, struct ip *); + + if (ip->ip_v != IPVERSION) { + ipstat.ips_badvers++; + goto bad; + } + + hlen = ip->ip_hl << 2; + if (hlenm->m_len) {/* min header length */ + ipstat.ips_badhlen++; /* or packet too short */ + goto bad; + } + + /* keep ip header intact for ICMP reply + * ip->ip_sum = cksum(m, hlen); + * if (ip->ip_sum) { + */ + if(cksum(m,hlen)) { + ipstat.ips_badsum++; + goto bad; + } + + /* + * Convert fields to host representation. + */ + NTOHS(ip->ip_len); + if (ip->ip_len < hlen) { + ipstat.ips_badlen++; + goto bad; + } + NTOHS(ip->ip_id); + NTOHS(ip->ip_off); + + /* + * Check that the amount of data in the buffers + * is as at least much as the IP header would have us expect. + * Trim SLIRPmbufs if longer than we expect. + * Drop packet if shorter than we expect. + */ + if (m->m_len < ip->ip_len) { + ipstat.ips_tooshort++; + goto bad; + } + /* Should drop packet if SLIRPmbuf too long? hmmm... */ + if (m->m_len > ip->ip_len) + m_adj(m, ip->ip_len - m->m_len); + + /* check ip_ttl for a correct ICMP reply */ + if(ip->ip_ttl==0 || ip->ip_ttl==1) { + icmp_error(m, ICMP_TIMXCEED,ICMP_TIMXCEED_INTRANS, 0,"ttl"); + goto bad; + } + + /* + * Process options and, if not destined for us, + * ship it on. ip_dooptions returns 1 when an + * error was detected (causing an icmp message + * to be sent and the original packet to be freed). + */ +/* We do no IP options */ +/* if (hlen > sizeof (struct ip) && ip_dooptions(m)) + * goto next; + */ + /* + * If offset or IP_MF are set, must reassemble. + * Otherwise, nothing need be done. + * (We could look in the reassembly queue to see + * if the packet was previously fragmented, + * but it's not worth the time; just let them time out.) + * + * XXX This should fail, don't fragment yet + */ + if (ip->ip_off &~ IP_DF) { + register struct ipq *fp; + /* + * Look for queue of fragments + * of this datagram. + */ + for (fp = (struct ipq *) ipq.next; fp != &ipq; + fp = (struct ipq *) fp->next) + if (ip->ip_id == fp->ipq_id && + ip->ip_src.s_addr == fp->ipq_src.s_addr && + ip->ip_dst.s_addr == fp->ipq_dst.s_addr && + ip->ip_p == fp->ipq_p) + goto found; + fp = 0; + found: + + /* + * Adjust ip_len to not reflect header, + * set ip_mff if more fragments are expected, + * convert offset of this to bytes. + */ + ip->ip_len -= hlen; + if (ip->ip_off & IP_MF) + ((struct ipasfrag *)ip)->ipf_mff |= 1; + else + ((struct ipasfrag *)ip)->ipf_mff &= ~1; + + ip->ip_off <<= 3; + + /* + * If datagram marked as having more fragments + * or if this is not the first fragment, + * attempt reassembly; if it succeeds, proceed. + */ + if (((struct ipasfrag *)ip)->ipf_mff & 1 || ip->ip_off) { + ipstat.ips_fragments++; + ip = ip_reass((struct ipasfrag *)ip, fp); + if (ip == 0) + return; + ipstat.ips_reassembled++; + m = dtom(ip); + } else + if (fp) + ip_freef(fp); + + } else + ip->ip_len -= hlen; + + /* + * Switch out to protocol's input routine. + */ + ipstat.ips_delivered++; + switch (ip->ip_p) { + case IPPROTO_TCP: + tcp_input(m, hlen, (struct SLIRPsocket *)NULL); + break; + case IPPROTO_UDP: + udp_input(m, hlen); + break; + case IPPROTO_ICMP: + icmp_input(m, hlen); + break; + default: + ipstat.ips_noproto++; + m_free(m); + } + return; +bad: + m_freem(m); + return; +} + +/* + * Take incoming datagram fragment and try to + * reassemble it into whole datagram. If a chain for + * reassembly of this datagram already exists, then it + * is given as fp; otherwise have to make a chain. + */ +struct ip * +ip_reass(ip, fp) + register struct ipasfrag *ip; + register struct ipq *fp; +{ + register struct SLIRPmbuf *m = dtom(ip); + register struct ipasfrag *q; + int hlen = ip->ip_hl << 2; + int i, next; + + DEBUG_CALL("ip_reass"); + DEBUG_ARG("ip = %lx", (long)ip); + DEBUG_ARG("fp = %lx", (long)fp); + DEBUG_ARG("m = %lx", (long)m); + + /* + * Presence of header sizes in SLIRPmbufs + * would confuse code below. + * Fragment m_data is concatenated. + */ + m->m_data += hlen; + m->m_len -= hlen; + + /* + * If first fragment to arrive, create a reassembly queue. + */ + if (fp == 0) { + struct SLIRPmbuf *t; + if ((t = m_get()) == NULL) goto dropfrag; + fp = mtod(t, struct ipq *); + insque_32(fp, &ipq); + fp->ipq_ttl = IPFRAGTTL; + fp->ipq_p = ip->ip_p; + fp->ipq_id = ip->ip_id; + fp->ipq_next = fp->ipq_prev = (ipasfragp_32)fp; + fp->ipq_src = ((struct ip *)ip)->ip_src; + fp->ipq_dst = ((struct ip *)ip)->ip_dst; + q = (struct ipasfrag *)fp; + goto insert; + } + + /* + * Find a segment which begins after this one does. + */ + for (q = (struct ipasfrag *)fp->ipq_next; q != (struct ipasfrag *)fp; + q = (struct ipasfrag *)q->ipf_next) + if (q->ip_off > ip->ip_off) + break; + + /* + * If there is a preceding segment, it may provide some of + * our data already. If so, drop the data from the incoming + * segment. If it provides all of our data, drop us. + */ + if (q->ipf_prev != (ipasfragp_32)fp) { + i = ((struct ipasfrag *)(q->ipf_prev))->ip_off + + ((struct ipasfrag *)(q->ipf_prev))->ip_len - ip->ip_off; + if (i > 0) { + if (i >= ip->ip_len) + goto dropfrag; + m_adj(dtom(ip), i); + ip->ip_off += i; + ip->ip_len -= i; + } + } + + /* + * While we overlap succeeding segments trim them or, + * if they are completely covered, dequeue them. + */ + while (q != (struct ipasfrag *)fp && ip->ip_off + ip->ip_len > q->ip_off) { + i = (ip->ip_off + ip->ip_len) - q->ip_off; + if (i < q->ip_len) { + q->ip_len -= i; + q->ip_off += i; + m_adj(dtom(q), i); + break; + } + q = (struct ipasfrag *) q->ipf_next; + m_freem(dtom((struct ipasfrag *) q->ipf_prev)); + ip_deq((struct ipasfrag *) q->ipf_prev); + } + +insert: + /* + * Stick new segment in its place; + * check for complete reassembly. + */ + ip_enq(ip, (struct ipasfrag *) q->ipf_prev); + next = 0; + for (q = (struct ipasfrag *) fp->ipq_next; q != (struct ipasfrag *)fp; + q = (struct ipasfrag *) q->ipf_next) { + if (q->ip_off != next) + return (0); + next += q->ip_len; + } + if (((struct ipasfrag *)(q->ipf_prev))->ipf_mff & 1) + return (0); + + /* + * Reassembly is complete; concatenate fragments. + */ + q = (struct ipasfrag *) fp->ipq_next; + m = dtom(q); + + q = (struct ipasfrag *) q->ipf_next; + while (q != (struct ipasfrag *)fp) { + struct SLIRPmbuf *t; + t = dtom(q); + q = (struct ipasfrag *) q->ipf_next; + m_cat(m, t); + } + + /* + * Create header for new ip packet by + * modifying header of first packet; + * dequeue and discard fragment reassembly header. + * Make header visible. + */ + ip = (struct ipasfrag *) fp->ipq_next; + + /* + * If the fragments concatenated to an SLIRPmbuf that's + * bigger than the total size of the fragment, then and + * m_ext buffer was alloced. But fp->ipq_next points to + * the old buffer (in the SLIRPmbuf), so we must point ip + * into the new buffer. + */ + if (m->m_flags & M_EXT) { + int delta; + delta = (char *)ip - m->m_dat; + ip = (struct ipasfrag *)(m->m_ext + delta); + } + + /* DEBUG_ARG("ip = %lx", (long)ip); + * ip=(struct ipasfrag *)m->m_data; */ + + ip->ip_len = next; + ip->ipf_mff &= ~1; + ((struct ip *)ip)->ip_src = fp->ipq_src; + ((struct ip *)ip)->ip_dst = fp->ipq_dst; + remque_32(fp); + (void) m_free(dtom(fp)); + m = dtom(ip); + m->m_len += (ip->ip_hl << 2); + m->m_data -= (ip->ip_hl << 2); + + return ((struct ip *)ip); + +dropfrag: + ipstat.ips_fragdropped++; + m_freem(m); + return (0); +} + +/* + * Free a fragment reassembly header and all + * associated datagrams. + */ +void +ip_freef(fp) + struct ipq *fp; +{ + register struct ipasfrag *q, *p; + + for (q = (struct ipasfrag *) fp->ipq_next; q != (struct ipasfrag *)fp; + q = p) { + p = (struct ipasfrag *) q->ipf_next; + ip_deq(q); + m_freem(dtom(q)); + } + remque_32(fp); + (void) m_free(dtom(fp)); +} + +/* + * Put an ip fragment on a reassembly chain. + * Like insque, but pointers in middle of structure. + */ +void +ip_enq(p, prev) + register struct ipasfrag *p, *prev; +{ + DEBUG_CALL("ip_enq"); + DEBUG_ARG("prev = %lx", (long)prev); + p->ipf_prev = (ipasfragp_32) prev; + p->ipf_next = prev->ipf_next; + ((struct ipasfrag *)(prev->ipf_next))->ipf_prev = (ipasfragp_32) p; + prev->ipf_next = (ipasfragp_32) p; +} + +/* + * To ip_enq as remque is to insque. + */ +void +ip_deq(p) + register struct ipasfrag *p; +{ + ((struct ipasfrag *)(p->ipf_prev))->ipf_next = p->ipf_next; + ((struct ipasfrag *)(p->ipf_next))->ipf_prev = p->ipf_prev; +} + +/* + * IP timer processing; + * if a timer expires on a reassembly + * queue, discard it. + */ +void +ip_slowtimo() +{ + register struct ipq *fp; + + DEBUG_CALL("ip_slowtimo"); + + fp = (struct ipq *) ipq.next; + if (fp == 0) + return; + + while (fp != &ipq) { + --fp->ipq_ttl; + fp = (struct ipq *) fp->next; + if (((struct ipq *)(fp->prev))->ipq_ttl == 0) { + ipstat.ips_fragtimeout++; + ip_freef((struct ipq *) fp->prev); + } + } +} + +/* + * Do option processing on a datagram, + * possibly discarding it if bad options are encountered, + * or forwarding it if source-routed. + * Returns 1 if packet has been forwarded/freed, + * 0 if the packet should be processed further. + */ + +#ifdef notdef + +int +ip_dooptions(m) + struct SLIRPmbuf *m; +{ + register struct ip *ip = mtod(m, struct ip *); + register u_char *cp; + register struct ip_timestamp *ipt; + register struct in_ifaddr *ia; +/* int opt, optlen, cnt, off, code, type = ICMP_PARAMPROB, forward = 0; */ + int opt, optlen, cnt, off, code, type, forward = 0; + struct in_addr *sin, dst; +typedef u_int32_t n_time; + n_time ntime; + + dst = ip->ip_dst; + cp = (u_char *)(ip + 1); + cnt = (ip->ip_hl << 2) - sizeof (struct ip); + for (; cnt > 0; cnt -= optlen, cp += optlen) { + opt = cp[IPOPT_OPTVAL]; + if (opt == IPOPT_EOL) + break; + if (opt == IPOPT_NOP) + optlen = 1; + else { + optlen = cp[IPOPT_OLEN]; + if (optlen <= 0 || optlen > cnt) { + code = &cp[IPOPT_OLEN] - (u_char *)ip; + goto bad; + } + } + switch (opt) { + + default: + break; + + /* + * Source routing with record. + * Find interface with current destination address. + * If none on this machine then drop if strictly routed, + * or do nothing if loosely routed. + * Record interface address and bring up next address + * component. If strictly routed make sure next + * address is on directly accessible net. + */ + case IPOPT_LSRR: + case IPOPT_SSRR: + if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { + code = &cp[IPOPT_OFFSET] - (u_char *)ip; + goto bad; + } + ipaddr.sin_addr = ip->ip_dst; + ia = (struct in_ifaddr *) + ifa_ifwithaddr((struct sockaddr *)&ipaddr); + if (ia == 0) { + if (opt == IPOPT_SSRR) { + type = ICMP_UNREACH; + code = ICMP_UNREACH_SRCFAIL; + goto bad; + } + /* + * Loose routing, and not at next destination + * yet; nothing to do except forward. + */ + break; + } + off--; / * 0 origin * / + if (off > optlen - sizeof(struct in_addr)) { + /* + * End of source route. Should be for us. + */ + save_rte(cp, ip->ip_src); + break; + } + /* + * locate outgoing interface + */ + bcopy((SLIRPcaddr_t)(cp + off), (SLIRPcaddr_t)&ipaddr.sin_addr, + sizeof(ipaddr.sin_addr)); + if (opt == IPOPT_SSRR) { +#define INA struct in_ifaddr * +#define SA struct sockaddr * + if ((ia = (INA)ifa_ifwithdstaddr((SA)&ipaddr)) == 0) + ia = (INA)ifa_ifwithnet((SA)&ipaddr); + } else + ia = ip_rtaddr(ipaddr.sin_addr); + if (ia == 0) { + type = ICMP_UNREACH; + code = ICMP_UNREACH_SRCFAIL; + goto bad; + } + ip->ip_dst = ipaddr.sin_addr; + bcopy((SLIRPcaddr_t)&(IA_SIN(ia)->sin_addr), + (SLIRPcaddr_t)(cp + off), sizeof(struct in_addr)); + cp[IPOPT_OFFSET] += sizeof(struct in_addr); + /* + * Let ip_intr's mcast routing check handle mcast pkts + */ + forward = !IN_MULTICAST(ntohl(ip->ip_dst.s_addr)); + break; + + case IPOPT_RR: + if ((off = cp[IPOPT_OFFSET]) < IPOPT_MINOFF) { + code = &cp[IPOPT_OFFSET] - (u_char *)ip; + goto bad; + } + /* + * If no space remains, ignore. + */ + off--; * 0 origin * + if (off > optlen - sizeof(struct in_addr)) + break; + bcopy((SLIRPcaddr_t)(&ip->ip_dst), (SLIRPcaddr_t)&ipaddr.sin_addr, + sizeof(ipaddr.sin_addr)); + /* + * locate outgoing interface; if we're the destination, + * use the incoming interface (should be same). + */ + if ((ia = (INA)ifa_ifwithaddr((SA)&ipaddr)) == 0 && + (ia = ip_rtaddr(ipaddr.sin_addr)) == 0) { + type = ICMP_UNREACH; + code = ICMP_UNREACH_HOST; + goto bad; + } + bcopy((SLIRPcaddr_t)&(IA_SIN(ia)->sin_addr), + (SLIRPcaddr_t)(cp + off), sizeof(struct in_addr)); + cp[IPOPT_OFFSET] += sizeof(struct in_addr); + break; + + case IPOPT_TS: + code = cp - (u_char *)ip; + ipt = (struct ip_timestamp *)cp; + if (ipt->ipt_len < 5) + goto bad; + if (ipt->ipt_ptr > ipt->ipt_len - sizeof (int32_t)) { + if (++ipt->ipt_oflw == 0) + goto bad; + break; + } + sin = (struct in_addr *)(cp + ipt->ipt_ptr - 1); + switch (ipt->ipt_flg) { + + case IPOPT_TS_TSONLY: + break; + + case IPOPT_TS_TSANDADDR: + if (ipt->ipt_ptr + sizeof(n_time) + + sizeof(struct in_addr) > ipt->ipt_len) + goto bad; + ipaddr.sin_addr = dst; + ia = (INA)ifaof_ i f p foraddr((SA)&ipaddr, + m->m_pkthdr.rcvif); + if (ia == 0) + continue; + bcopy((SLIRPcaddr_t)&IA_SIN(ia)->sin_addr, + (SLIRPcaddr_t)sin, sizeof(struct in_addr)); + ipt->ipt_ptr += sizeof(struct in_addr); + break; + + case IPOPT_TS_PRESPEC: + if (ipt->ipt_ptr + sizeof(n_time) + + sizeof(struct in_addr) > ipt->ipt_len) + goto bad; + bcopy((SLIRPcaddr_t)sin, (SLIRPcaddr_t)&ipaddr.sin_addr, + sizeof(struct in_addr)); + if (ifa_ifwithaddr((SA)&ipaddr) == 0) + continue; + ipt->ipt_ptr += sizeof(struct in_addr); + break; + + default: + goto bad; + } + ntime = iptime(); + bcopy((SLIRPcaddr_t)&ntime, (SLIRPcaddr_t)cp + ipt->ipt_ptr - 1, + sizeof(n_time)); + ipt->ipt_ptr += sizeof(n_time); + } + } + if (forward) { + ip_forward(m, 1); + return (1); + } + } + } + return (0); +bad: + /* ip->ip_len -= ip->ip_hl << 2; XXX icmp_error adds in hdr length */ + +/* Not yet */ + icmp_error(m, type, code, 0, 0); + + ipstat.ips_badoptions++; + return (1); +} + +#endif /* notdef */ + +/* + * Strip out IP options, at higher + * level protocol in the kernel. + * Second argument is buffer to which options + * will be moved, and return value is their length. + * (XXX) should be deleted; last arg currently ignored. + */ +void +ip_stripoptions(m, mopt) + struct SLIRPmbuf *m; + struct SLIRPmbuf *mopt; +{ + register int i; + struct ip *ip = mtod(m, struct ip *); + register SLIRPcaddr_t opts; + int olen; + + olen = (ip->ip_hl<<2) - sizeof (struct ip); + opts = (SLIRPcaddr_t)(ip + 1); + i = m->m_len - (sizeof (struct ip) + olen); + memcpy(opts, opts + olen, (unsigned)i); + m->m_len -= olen; + + ip->ip_hl = sizeof(struct ip) >> 2; +} diff --git a/src/slirp/ip_output.c b/src/slirp/ip_output.c new file mode 100644 index 000000000..c3f243e76 --- /dev/null +++ b/src/slirp/ip_output.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)ip_output.c 8.3 (Berkeley) 1/21/94 + * ip_output.c,v 1.9 1994/11/16 10:17:10 jkh Exp + */ + +/* + * Changes and additions relating to SLiRP are + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#include "slirp.h" + +u_int16_t ip_id; + +/* + * IP output. The packet in SLIRPmbuf chain m contains a skeletal IP + * header (with len, off, ttl, proto, tos, src, dst). + * The SLIRPmbuf chain containing the packet will be freed. + * The SLIRPmbuf opt, if present, will not be freed. + */ +int +ip_output(so, m0) + struct SLIRPsocket *so; + struct SLIRPmbuf *m0; +{ + struct ip *ip; + struct SLIRPmbuf *m = m0; + u_int hlen = sizeof(struct ip ); + u_int len, off; + int error = 0; + + DEBUG_CALL("ip_output"); + DEBUG_ARG("so = %lx", (long)so); + DEBUG_ARG("m0 = %lx", (long)m0); + + /* We do no options */ +/* if (opt) { + * m = ip_insertoptions(m, opt, &len); + * hlen = len; + * } + */ + ip = mtod(m, struct ip *); + /* + * Fill in IP header. + */ + ip->ip_v = IPVERSION; + ip->ip_off &= IP_DF; + ip->ip_id = htons(ip_id++); + ip->ip_hl = hlen >> 2; + ipstat.ips_localout++; + + /* + * Verify that we have any chance at all of being able to queue + * the packet or packet fragments + */ + /* XXX Hmmm... */ +/* if (if_queued > if_thresh && towrite <= 0) { + * error = ENOBUFS; + * goto bad; + * } + */ + + /* + * If small enough for interface, can just send directly. + */ + if ((u_int16_t)ip->ip_len <= if_mtu) { + ip->ip_len = htons((u_int16_t)ip->ip_len); + ip->ip_off = htons((u_int16_t)ip->ip_off); + ip->ip_sum = 0; + ip->ip_sum = cksum(m, hlen); + + if_output(so, m); + goto done; + } + + /* + * Too large for interface; fragment if possible. + * Must be able to put at least 8 bytes per fragment. + */ + if (ip->ip_off & IP_DF) { + error = -1; + ipstat.ips_cantfrag++; + goto bad; + } + + len = (if_mtu - hlen) &~ 7; /* ip databytes per packet */ + if (len < 8) { + error = -1; + goto bad; + } + + { + int mhlen, firstlen = len; + struct SLIRPmbuf **mnext = &m->m_nextpkt; + + /* + * Loop through length of segment after first fragment, + * make new header and copy data of each part and link onto chain. + */ + m0 = m; + mhlen = sizeof (struct ip); + for (off = hlen + len; off < ip->ip_len; off += len) { + struct ip *mhip; + m = m_get(); + if (m == 0) { + error = -1; + ipstat.ips_odropped++; + goto sendorfree; + } + m->m_data += if_maxlinkhdr; + mhip = mtod(m, struct ip *); + *mhip = *ip; + + /* No options */ +/* if (hlen > sizeof (struct ip)) { + * mhlen = ip_optcopy(ip, mhip) + sizeof (struct ip); + * mhip->ip_hl = mhlen >> 2; + * } + */ + m->m_len = mhlen; + mhip->ip_off = ((off - hlen) >> 3) + (ip->ip_off & ~IP_MF); + if (ip->ip_off & IP_MF) + mhip->ip_off |= IP_MF; + if (off + len >= (u_int16_t)ip->ip_len) + len = (u_int16_t)ip->ip_len - off; + else + mhip->ip_off |= IP_MF; + mhip->ip_len = htons((u_int16_t)(len + mhlen)); + + if (m_copy(m, m0, off, len) < 0) { + error = -1; + goto sendorfree; + } + + mhip->ip_off = htons((u_int16_t)mhip->ip_off); + mhip->ip_sum = 0; + mhip->ip_sum = cksum(m, mhlen); + *mnext = m; + mnext = &m->m_nextpkt; + ipstat.ips_ofragments++; + } + /* + * Update first fragment by trimming what's been copied out + * and updating header, then send each fragment (in order). + */ + m = m0; + m_adj(m, hlen + firstlen - ip->ip_len); + ip->ip_len = htons((u_int16_t)m->m_len); + ip->ip_off = htons((u_int16_t)(ip->ip_off | IP_MF)); + ip->ip_sum = 0; + ip->ip_sum = cksum(m, hlen); +sendorfree: + for (m = m0; m; m = m0) { + m0 = m->m_nextpkt; + m->m_nextpkt = 0; + if (error == 0) + if_output(so, m); + else + m_freem(m); + } + + if (error == 0) + ipstat.ips_fragmented++; + } + +done: + return (error); + +bad: + m_freem(m0); + goto done; +} diff --git a/src/slirp/libslirp.h b/src/slirp/libslirp.h new file mode 100644 index 000000000..8a1aa31e6 --- /dev/null +++ b/src/slirp/libslirp.h @@ -0,0 +1,41 @@ +#ifndef _LIBSLIRP_H +#define _LIBSLIRP_H + +#ifdef _WIN32 +#include +int inet_aton(const char *cp, struct in_addr *ia); +#else +#include +#include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +int slirp_init(void); + +int slirp_select_fill(int *pnfds, + fd_set *readfds, fd_set *writefds, fd_set *xfds); + +void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds); + +void slirp_input(const uint8 *pkt, int pkt_len); + +/* you must provide the following functions: */ +int slirp_can_output(void); +void slirp_output(const uint8 *pkt, int pkt_len); + +int slirp_redir(int is_udp, int host_port, + struct in_addr guest_addr, int guest_port); +int slirp_add_exec(int do_pty, const char *args, int addr_low_byte, + int guest_port); + +extern const char *tftp_prefix; +extern char slirp_hostname[33]; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/slirp/main.h b/src/slirp/main.h new file mode 100644 index 000000000..181b6ae88 --- /dev/null +++ b/src/slirp/main.h @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#ifdef HAVE_SYS_SELECT_H +#include +#endif + +#define TOWRITEMAX 512 + +extern struct timeval tt; +extern int link_up; +extern int slirp_socket; +extern int slirp_socket_unit; +extern int slirp_socket_port; +extern u_int32_t slirp_socket_addr; +extern char *slirp_socket_passwd; +extern int ctty_closed; + +/* + * Get the difference in 2 times from updtim() + * Allow for wraparound times, "just in case" + * x is the greater of the 2 (current time) and y is + * what it's being compared against. + */ +#define TIME_DIFF(x,y) (x)-(y) < 0 ? ~0-(y)+(x) : (x)-(y) + +extern char *slirp_tty; +extern char *exec_shell; +extern u_int curtime; +extern fd_set *global_readfds, *global_writefds, *global_xfds; +extern struct in_addr ctl_addr; +extern struct in_addr special_addr; +extern struct in_addr alias_addr; +extern struct in_addr our_addr; +extern struct in_addr loopback_addr; +extern struct in_addr dns_addr; +extern char *username; +extern char *socket_path; +extern int towrite_max; +extern int ppp_exit; +extern int so_options; +extern int tcp_keepintvl; +extern uint8_t client_ethaddr[6]; + +#define PROTO_SLIP 0x1 +#ifdef USE_PPP +#define PROTO_PPP 0x2 +#endif + +void if_encap(const uint8_t *ip_data, int ip_data_len); diff --git a/src/slirp/mbuf.c b/src/slirp/mbuf.c new file mode 100644 index 000000000..c7f3f3fe8 --- /dev/null +++ b/src/slirp/mbuf.c @@ -0,0 +1,248 @@ +/* + * Copyright (c) 1995 Danny Gasparovski + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +/* + * mbuf's in SLiRP are much simpler than the real mbufs in + * FreeBSD. They are fixed size, determined by the MTU, + * so that one whole packet can fit. Mbuf's cannot be + * chained together. If there's more data than the mbuf + * could hold, an external malloced buffer is pointed to + * by m_ext (and the data pointers) and M_EXT is set in + * the flags + */ + +#include +#include "slirp.h" + +struct mbuf *mbutl; +char *mclrefcnt; +int mbuf_alloced = 0; +struct SLIRPmbuf m_freelist, m_usedlist; +int mbuf_thresh = 30; +int mbuf_max = 0; +size_t msize; + +void +m_init() +{ + m_freelist.m_next = m_freelist.m_prev = &m_freelist; + m_usedlist.m_next = m_usedlist.m_prev = &m_usedlist; + msize_init(); +} + +void msize_init() +{ + /* + * Find a nice value for msize + * XXX if_maxlinkhdr already in mtu + */ + msize = (if_mtu>if_mru?if_mtu:if_mru) + + if_maxlinkhdr + sizeof(struct m_hdr ) + 6; +} + +/* + * Get an mbuf from the free list, if there are none + * malloc one + * + * Because fragmentation can occur if we alloc new mbufs and + * free old mbufs, we mark all mbufs above mbuf_thresh as M_DOFREE, + * which tells m_free to actually free() it + */ +struct SLIRPmbuf * m_get() +{ + struct SLIRPmbuf *m; + int flags = 0; + + DEBUG_CALL("m_get"); + + if (m_freelist.m_next == &m_freelist) { + m = (struct SLIRPmbuf *)malloc(msize); + if (m == NULL) goto end_error; + mbuf_alloced++; + if (mbuf_alloced > mbuf_thresh) + flags = M_DOFREE; + if (mbuf_alloced > mbuf_max) + mbuf_max = mbuf_alloced; + } else { + m = m_freelist.m_next; + remque(m); + } + + /* Insert it in the used list */ + insque(m,&m_usedlist); + m->m_flags = (flags | M_USEDLIST); + + /* Initialise it */ + m->m_size = msize - sizeof(struct m_hdr); + m->m_data = m->m_dat; + m->m_len = 0; + m->m_nextpkt = 0; + m->m_prevpkt = 0; +end_error: + DEBUG_ARG("m = %lx", (long )m); + return m; +} + +//For some reason this fails in GDB saying tehre is no m_flags member +void +m_free(m) + struct SLIRPmbuf *m; +{ + + DEBUG_CALL("m_free"); + DEBUG_ARG("m = %lx", (long )m); + + if(m) { + /* Remove from m_usedlist */ + if (m->m_flags & M_USEDLIST) + remque(m); + + + + /* If it's M_EXT, free() it */ + if (m->m_flags & M_EXT) + free(m->m_ext); + + /* + * Either free() it or put it on the free list + */ + if (m->m_flags & M_DOFREE) { + free(m); + mbuf_alloced--; + } else if ((m->m_flags & M_FREELIST) == 0) { + insque(m,&m_freelist); + m->m_flags = M_FREELIST; /* Clobber other flags */ + } + } /* if(m) */ +} + +/* + * Copy data from one mbuf to the end of + * the other.. if result is too big for one mbuf, malloc() + * an M_EXT data segment + */ +void +m_cat(m, n) + struct SLIRPmbuf *m, *n; +{ + /* + * If there's no room, realloc + */ + if (M_FREEROOM(m) < n->m_len) + m_inc(m,m->m_size+MINCSIZE); + + memcpy(m->m_data+m->m_len, n->m_data, n->m_len); + m->m_len += n->m_len; + + m_free(n); +} + + +/* make m size bytes large */ +void +m_inc(m, size) + struct SLIRPmbuf *m; + int size; +{ + int datasize; + + /* some compiles throw up on gotos. This one we can fake. */ + if(m->m_size>size) return; + + if (m->m_flags & M_EXT) { + datasize = m->m_data - m->m_ext; + m->m_ext = (char *)realloc(m->m_ext,size); +/* if (m->m_ext == NULL) + * return (struct SLIRPmbuf *)NULL; + */ + m->m_data = m->m_ext + datasize; + } else { + char *dat; + datasize = m->m_data - m->m_dat; + dat = (char *)malloc(size); +/* if (dat == NULL) + * return (struct SLIRPmbuf *)NULL; + */ + memcpy(dat, m->m_dat, m->m_size); + + m->m_ext = dat; + m->m_data = m->m_ext + datasize; + m->m_flags |= M_EXT; + } + + m->m_size = size; + +} + + + +void +m_adj(m, len) + struct SLIRPmbuf *m; + int len; +{ + if (m == NULL) + return; + if (len >= 0) { + /* Trim from head */ + m->m_data += len; + m->m_len -= len; + } else { + /* Trim from tail */ + len = -len; + m->m_len -= len; + } +} + + +/* + * Copy len bytes from m, starting off bytes into n + */ +int +m_copy(n, m, off, len) + struct SLIRPmbuf *n, *m; + int off, len; +{ + if (len > M_FREEROOM(n)) + return -1; + + memcpy((n->m_data + n->m_len), (m->m_data + off), len); + n->m_len += len; + return 0; +} + + +/* + * Given a pointer into an mbuf, return the mbuf + * XXX This is a kludge, I should eliminate the need for it + * Fortunately, it's not used often + */ +struct SLIRPmbuf * +dtom(dat) + void *dat; +{ + struct SLIRPmbuf *m; + + DEBUG_CALL("dtom"); + DEBUG_ARG("dat = %lx", (long )dat); + + /* bug corrected for M_EXT buffers */ + for (m = m_usedlist.m_next; m != &m_usedlist; m = m->m_next) { + if (m->m_flags & M_EXT) { + if( (char *)dat>=m->m_ext && (char *)dat<(m->m_ext + m->m_size) ) + return m; + } else { + if( (char *)dat >= m->m_dat && (char *)dat<(m->m_dat + m->m_size) ) + return m; + } + } + + DEBUG_ERROR((dfd, "dtom failed")); + + return (struct SLIRPmbuf *)0; +} + diff --git a/src/slirp/mbuf.h b/src/slirp/mbuf.h new file mode 100644 index 000000000..13ef81523 --- /dev/null +++ b/src/slirp/mbuf.h @@ -0,0 +1,143 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)mbuf.h 8.3 (Berkeley) 1/21/94 + * mbuf.h,v 1.9 1994/11/14 13:54:20 bde Exp + */ + +#ifndef _MBUF_H_ +#define _MBUF_H_ + +#define m_freem m_free + + +#define MINCSIZE 4096 /* Amount to increase mbuf if too small */ + +/* + * Macros for type conversion + * mtod(m,t) - convert mbuf pointer to data pointer of correct type + * dtom(x) - convert data pointer within mbuf to mbuf pointer (XXX) + */ +#define mtod(m,t) ((t)(m)->m_data) +/* #define dtom(x) ((struct SLIRPmbuf *)((int)(x) & ~(M_SIZE-1))) */ + +/* XXX About mbufs for slirp: + * Only one mbuf is ever used in a chain, for each "cell" of data. + * m_nextpkt points to the next packet, if fragmented. + * If the data is too large, the M_EXT is used, and a larger block + * is alloced. Therefore, m_free[m] must check for M_EXT and if set + * free the m_ext. This is inefficient memory-wise, but who cares. + */ + +/* XXX should union some of these! */ +/* header at beginning of each mbuf: */ +struct m_hdr { + struct SLIRPmbuf *mh_next; /* Linked list of mbufs */ + struct SLIRPmbuf *mh_prev; + struct SLIRPmbuf *mh_nextpkt; /* Next packet in queue/record */ + struct SLIRPmbuf *mh_prevpkt; /* Flags aren't used in the output queue */ + int mh_flags; /* Misc flags */ + + size_t mh_size; /* Size of data */ + struct SLIRPsocket *mh_so; + + SLIRPcaddr_t mh_data; /* Location of data */ + size_t mh_len; /* Amount of data in this mbuf */ +}; + +/* + * How much room is in the mbuf, from m_data to the end of the mbuf + */ +#define M_ROOM(m) ((m->m_flags & M_EXT)? \ + (((m)->m_ext + (m)->m_size) - (m)->m_data) \ + : \ + (((m)->m_dat + (m)->m_size) - (m)->m_data)) + +/* + * How much free room there is + */ +#define M_FREEROOM(m) (M_ROOM(m) - (m)->m_len) +#define M_TRAILINGSPACE M_FREEROOM + +struct SLIRPmbuf { + struct m_hdr m_hdr; + union M_dat { + char m_dat_[1]; /* ANSI don't like 0 sized arrays */ + char *m_ext_; + } M_dat; +}; + +#define m_next m_hdr.mh_next +#define m_prev m_hdr.mh_prev +#define m_nextpkt m_hdr.mh_nextpkt +#define m_prevpkt m_hdr.mh_prevpkt +#define m_flags m_hdr.mh_flags +#define m_len m_hdr.mh_len +#define m_data m_hdr.mh_data +#define m_size m_hdr.mh_size +#define m_dat M_dat.m_dat_ +#define m_ext M_dat.m_ext_ +#define m_so m_hdr.mh_so + +#define ifq_prev m_prev +#define ifq_next m_next +#define ifs_prev m_prevpkt +#define ifs_next m_nextpkt +#define ifq_so m_so + +#define M_EXT 0x01 /* m_ext points to more (malloced) data */ +#define M_FREELIST 0x02 /* mbuf is on free list */ +#define M_USEDLIST 0x04 /* XXX mbuf is on used list (for dtom()) */ +#define M_DOFREE 0x08 /* when m_free is called on the mbuf, free() + * it rather than putting it on the free list */ + +/* + * Mbuf statistics. XXX + */ + +struct mbstat { + int mbs_alloced; /* Number of mbufs allocated */ + +}; + +extern struct mbstat mbstat; +extern int mbuf_alloced; +extern struct SLIRPmbuf m_freelist, m_usedlist; +extern int mbuf_max; + +void m_init _P((void)); +void msize_init _P((void)); +struct SLIRPmbuf * m_get _P((void)); +void m_free _P((struct SLIRPmbuf *)); +void m_cat _P((register struct SLIRPmbuf *, register struct SLIRPmbuf *)); +void m_inc _P((struct SLIRPmbuf *, int)); +void m_adj _P((struct SLIRPmbuf *, int)); +int m_copy _P((struct SLIRPmbuf *, struct SLIRPmbuf *, int, int)); +struct SLIRPmbuf * dtom _P((void *)); + +#endif diff --git a/src/slirp/misc.c b/src/slirp/misc.c new file mode 100644 index 000000000..88c0c13e0 --- /dev/null +++ b/src/slirp/misc.c @@ -0,0 +1,970 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#define WANT_SYS_IOCTL_H +#include +#include "slirp.h" + +u_int curtime, time_fasttimo, last_slowtimo, detach_time; +u_int detach_wait = 600000; /* 10 minutes */ + +#if 0 +int x_port = -1; +int x_display = 0; +int x_screen = 0; + +int +show_x(buff, inso) + char *buff; + struct SLIRPsocket *inso; +{ + if (x_port < 0) { + lprint("X Redir: X not being redirected.\r\n"); + } else { + lprint("X Redir: In sh/bash/zsh/etc. type: DISPLAY=%s:%d.%d; export DISPLAY\r\n", + inet_ntoa(our_addr), x_port, x_screen); + lprint("X Redir: In csh/tcsh/etc. type: setenv DISPLAY %s:%d.%d\r\n", + inet_ntoa(our_addr), x_port, x_screen); + if (x_display) + lprint("X Redir: Redirecting to display %d\r\n", x_display); + } + + return CFG_OK; +} + + +/* + * XXX Allow more than one X redirection? + */ +void +redir_x(inaddr, start_port, display, screen) + u_int32_t inaddr; + int start_port; + int display; + int screen; +{ + int i; + + if (x_port >= 0) { + lprint("X Redir: X already being redirected.\r\n"); + show_x(0, 0); + } else { + for (i = 6001 + (start_port-1); i <= 6100; i++) { + if (solisten(htons(i), inaddr, htons(6000 + display), 0)) { + /* Success */ + x_port = i - 6000; + x_display = display; + x_screen = screen; + show_x(0, 0); + return; + } + } + lprint("X Redir: Error: Couldn't redirect a port for X. Weird.\r\n"); + } +} +#endif + +#ifndef HAVE_INET_ATON +int +inet_aton(cp, ia) + const char *cp; + struct in_addr *ia; +{ + u_int32_t addr = inet_addr(cp); + if (addr == 0xffffffff) + return 0; + ia->s_addr = addr; + return 1; +} +#endif + +/* + * Get our IP address and put it in our_addr + */ +void +getouraddr() +{ + char buff[512]; + struct hostent *he = NULL; +#define ANCIENT + #ifdef ANCIENT + if (gethostname(&buff,500) == 0) + he = gethostbyname(&buff); + if (he) + our_addr = *(struct in_addr *)he->h_addr; + if (our_addr.s_addr == 0) + our_addr.s_addr = loopback_addr.s_addr; + #else + if (gethostname(buff,256) == 0) + { + struct addrinfo hints = { 0 }; + hints.ai_flags = AI_NUMERICHOST; + hints.ai_family = AF_INET; + struct addrinfo* ai; + if (getaddrinfo(buff, NULL, &hints, &ai) == 0) + { + our_addr = *(struct in_addr *)ai->ai_addr->sa_data; + freeaddrinfo(ai); + } + } + if (our_addr.s_addr == 0) + our_addr.s_addr = loopback_addr.s_addr; + #endif + #undef ANCIENT +} + +//#if SIZEOF_CHAR_P == 8 +//what?! + +struct quehead_32 { + u_int32_t qh_link; + u_int32_t qh_rlink; +}; + +inline void +insque_32(a, b) + void *a; + void *b; +{ + register struct quehead_32 *element = (struct quehead_32 *) a; + register struct quehead_32 *head = (struct quehead_32 *) b; + element->qh_link = head->qh_link; + head->qh_link = (u_int32_t)element; + element->qh_rlink = (u_int32_t)head; + ((struct quehead_32 *)(element->qh_link))->qh_rlink + = (u_int32_t)element; +} + +inline void +remque_32(a) + void *a; +{ + register struct quehead_32 *element = (struct quehead_32 *) a; + ((struct quehead_32 *)(element->qh_link))->qh_rlink = element->qh_rlink; + ((struct quehead_32 *)(element->qh_rlink))->qh_link = element->qh_link; + element->qh_rlink = 0; +} + +//#endif /* SIZEOF_CHAR_P == 8 */ +//Should be for 64bit + +struct quehead { + struct quehead *qh_link; + struct quehead *qh_rlink; +}; + +void +insque(a, b) + void *a, *b; +{ + register struct quehead *element = (struct quehead *) a; + register struct quehead *head = (struct quehead *) b; + element->qh_link = head->qh_link; + head->qh_link = (struct quehead *)element; + element->qh_rlink = (struct quehead *)head; + ((struct quehead *)(element->qh_link))->qh_rlink + = (struct quehead *)element; +} + +void +remque(a) + void *a; +{ + register struct quehead *element = (struct quehead *) a; + ((struct quehead *)(element->qh_link))->qh_rlink = element->qh_rlink; + ((struct quehead *)(element->qh_rlink))->qh_link = element->qh_link; + element->qh_rlink = NULL; + /* element->qh_link = NULL; TCP FIN1 crashes if you do this. Why ? */ +} + +/* #endif */ + + +int +add_exec(ex_ptr, do_pty, exec, addr, port) + struct ex_list **ex_ptr; + int do_pty; + char *exec; + int addr; + int port; +{ + struct ex_list *tmp_ptr; + + /* First, check if the port is "bound" */ + for (tmp_ptr = *ex_ptr; tmp_ptr; tmp_ptr = tmp_ptr->ex_next) { + if (port == tmp_ptr->ex_fport && addr == tmp_ptr->ex_addr) + return -1; + } + + tmp_ptr = *ex_ptr; + *ex_ptr = (struct ex_list *)malloc(sizeof(struct ex_list)); + (*ex_ptr)->ex_fport = port; + (*ex_ptr)->ex_addr = addr; + (*ex_ptr)->ex_pty = do_pty; + (*ex_ptr)->ex_exec = strdup(exec); + (*ex_ptr)->ex_next = tmp_ptr; + return 0; +} + +#ifndef HAVE_STRERROR + +/* + * For systems with no strerror + */ + +#ifdef WIN32 +//extern int sys_nerr; +//extern char *sys_errlist[]; +#endif + +char * +SLIRPstrerror(error) + int error; +{ + if (error < sys_nerr) + return sys_errlist[error]; + else + return "Unknown error."; +} + +#endif + + +#ifdef _WIN32 + +int +fork_exec(so, ex, do_pty) + struct SLIRPsocket *so; + char *ex; + int do_pty; +{ + /* not implemented */ + return 0; +} + +#else + +int +slirp_openpty(amaster, aslave) + int *amaster, *aslave; +{ + register int master, slave; + +#ifdef HAVE_GRANTPT + char *ptr; + + if ((master = open("/dev/ptmx", O_RDWR)) < 0 || + grantpt(master) < 0 || + unlockpt(master) < 0 || + (ptr = ptsname(master)) == NULL) { + close(master); + return -1; + } + + if ((slave = open(ptr, O_RDWR)) < 0 || + ioctl(slave, I_PUSH, "ptem") < 0 || + ioctl(slave, I_PUSH, "ldterm") < 0 || + ioctl(slave, I_PUSH, "ttcompat") < 0) { + close(master); + close(slave); + return -1; + } + + *amaster = master; + *aslave = slave; + return 0; + +#else + + static char line[] = "/dev/ptyXX"; + register const char *cp1, *cp2; + + for (cp1 = "pqrsPQRS"; *cp1; cp1++) { + line[8] = *cp1; + for (cp2 = "0123456789abcdefghijklmnopqrstuv"; *cp2; cp2++) { + line[9] = *cp2; + if ((master = open(line, O_RDWR, 0)) == -1) { + if (errno == ENOENT) + return (-1); /* out of ptys */ + } else { + line[5] = 't'; + /* These will fail */ + (void) chown(line, getuid(), 0); + (void) chmod(line, S_IRUSR|S_IWUSR|S_IWGRP); +#ifdef HAVE_REVOKE + (void) revoke(line); +#endif + if ((slave = open(line, O_RDWR, 0)) != -1) { + *amaster = master; + *aslave = slave; + return 0; + } + (void) close(master); + line[5] = 'p'; + } + } + } + errno = ENOENT; /* out of ptys */ + return (-1); +#endif +} + +/* + * XXX This is ugly + * We create and bind a socket, then fork off to another + * process, which connects to this socket, after which we + * exec the wanted program. If something (strange) happens, + * the accept() call could block us forever. + * + * do_pty = 0 Fork/exec inetd style + * do_pty = 1 Fork/exec using slirp.telnetd + * do_ptr = 2 Fork/exec using pty + */ +int +fork_exec(so, ex, do_pty) + struct SLIRPsocket *so; + char *ex; + int do_pty; +{ + int s; + struct sockaddr_in addr; + socklen_t addrlen = sizeof(addr); + int opt; + int master; + char *argv[256]; +#if 0 + char buff[256]; +#endif + /* don't want to clobber the original */ + char *bptr; + char *curarg; + int c, i, ret; + + DEBUG_CALL("fork_exec"); + DEBUG_ARG("so = %lx", (long)so); + DEBUG_ARG("ex = %lx", (long)ex); + DEBUG_ARG("do_pty = %lx", (long)do_pty); + + if (do_pty == 2) { + if (slirp_openpty(&master, &s) == -1) { + lprint("Error: openpty failed: %s\n", strerror(errno)); + return 0; + } + } else { + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_port = 0; + addr.sin_addr.s_addr = INADDR_ANY; + + if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0 || + bind(s, (struct sockaddr *)&addr, addrlen) < 0 || + listen(s, 1) < 0) { + lprint("Error: inet socket: %s\n", strerror(errno)); + closesocket(s); + + return 0; + } + } + + switch(fork()) { + case -1: + lprint("Error: fork failed: %s\n", strerror(errno)); + close(s); + if (do_pty == 2) + close(master); + return 0; + + case 0: + /* Set the DISPLAY */ + if (do_pty == 2) { + (void) close(master); +#ifdef TIOCSCTTY /* XXXXX */ + (void) setsid(); + ioctl(s, TIOCSCTTY, (char *)NULL); +#endif + } else { + getsockname(s, (struct sockaddr *)&addr, &addrlen); + close(s); + /* + * Connect to the socket + * XXX If any of these fail, we're in trouble! + */ + s = socket(AF_INET, SOCK_STREAM, 0); + addr.sin_addr = loopback_addr; + do { + ret = connect(s, (struct sockaddr *)&addr, addrlen); + } while (ret < 0 && errno == EINTR); + } + +#if 0 + if (x_port >= 0) { +#ifdef HAVE_SETENV + sprintf(buff, "%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); + setenv("DISPLAY", buff, 1); +#else + sprintf(buff, "DISPLAY=%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); + putenv(buff); +#endif + } +#endif + dup2(s, 0); + dup2(s, 1); + dup2(s, 2); + for (s = 3; s <= 255; s++) + close(s); + + i = 0; + bptr = strdup(ex); /* No need to free() this */ + if (do_pty == 1) { + /* Setup "slirp.telnetd -x" */ + argv[i++] = "slirp.telnetd"; + argv[i++] = "-x"; + argv[i++] = bptr; + } else + do { + /* Change the string into argv[] */ + curarg = bptr; + while (*bptr != ' ' && *bptr != (char)0) + bptr++; + c = *bptr; + *bptr++ = (char)0; + argv[i++] = strdup(curarg); + } while (c); + + argv[i] = 0; + execvp(argv[0], argv); + + /* Ooops, failed, let's tell the user why */ + { + char buff[256]; + + sprintf(buff, "Error: execvp of %s failed: %s\n", + argv[0], strerror(errno)); + write(2, buff, strlen(buff)+1); + } + close(0); close(1); close(2); /* XXX */ + exit(1); + + default: + if (do_pty == 2) { + close(s); + so->s = master; + } else { + /* + * XXX this could block us... + * XXX Should set a timer here, and if accept() doesn't + * return after X seconds, declare it a failure + * The only reason this will block forever is if socket() + * of connect() fail in the child process + */ + do { + so->s = accept(s, (struct sockaddr *)&addr, &addrlen); + } while (so->s < 0 && errno == EINTR); + closesocket(s); + opt = 1; + setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); + opt = 1; + setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); + } + fd_nonblock(so->s); + + /* Append the telnet options now */ + if (so->so_m != 0 && do_pty == 1) { + sbappend(so, so->so_m); + so->so_m = 0; + } + + return 1; + } +} +#endif + +#ifndef HAVE_STRDUP +char * strdup(char *str) +{ + char *bptr; + + bptr = (char *)malloc(strlen(str)+1); + strcpy(bptr, str); + + return bptr; +} +#endif + +#if 0 +void +snooze_hup(num) + int num; +{ + int s, ret; +#ifndef NO_UNIX_SOCKETS + struct sockaddr_un sock_un; +#endif + struct sockaddr_in sock_in; + char buff[256]; + + ret = -1; + if (slirp_socket_passwd) { + s = socket(AF_INET, SOCK_STREAM, 0); + if (s < 0) + slirp_exit(1); + sock_in.sin_family = AF_INET; + sock_in.sin_addr.s_addr = slirp_socket_addr; + sock_in.sin_port = htons(slirp_socket_port); + if (connect(s, (struct sockaddr *)&sock_in, sizeof(sock_in)) != 0) + slirp_exit(1); /* just exit...*/ + sprintf(buff, "kill %s:%d", slirp_socket_passwd, slirp_socket_unit); + write(s, buff, strlen(buff)+1); + } +#ifndef NO_UNIX_SOCKETS + else { + s = socket(AF_UNIX, SOCK_STREAM, 0); + if (s < 0) + slirp_exit(1); + sock_un.sun_family = AF_UNIX; + strcpy(sock_un.sun_path, socket_path); + if (connect(s, (struct sockaddr *)&sock_un, + sizeof(sock_un.sun_family) + sizeof(sock_un.sun_path)) != 0) + slirp_exit(1); + sprintf(buff, "kill none:%d", slirp_socket_unit); + write(s, buff, strlen(buff)+1); + } +#endif + slirp_exit(0); +} + + +void +snooze() +{ + sigset_t s; + int i; + + /* Don't need our data anymore */ + /* XXX This makes SunOS barf */ +/* brk(0); */ + + /* Close all fd's */ + for (i = 255; i >= 0; i--) + close(i); + + signal(SIGQUIT, slirp_exit); + signal(SIGHUP, snooze_hup); + sigemptyset(&s); + + /* Wait for any signal */ + sigsuspend(&s); + + /* Just in case ... */ + exit(255); +} + +void +relay(s) + int s; +{ + char buf[8192]; + int n; + fd_set readfds; + struct ttys *ttyp; + + /* Don't need our data anymore */ + /* XXX This makes SunOS barf */ +/* brk(0); */ + + signal(SIGQUIT, slirp_exit); + signal(SIGHUP, slirp_exit); + signal(SIGINT, slirp_exit); + signal(SIGTERM, slirp_exit); + + /* Fudge to get term_raw and term_restore to work */ + if (NULL == (ttyp = tty_attach (0, slirp_tty))) { + lprint ("Error: tty_attach failed in misc.c:relay()\r\n"); + slirp_exit (1); + } + ttyp->fd = 0; + ttyp->flags |= TTY_CTTY; + term_raw(ttyp); + + while (1) { + FD_ZERO(&readfds); + + FD_SET(0, &readfds); + FD_SET(s, &readfds); + + n = select(s+1, &readfds, (fd_set *)0, (fd_set *)0, (struct timeval *)0); + + if (n <= 0) + slirp_exit(0); + + if (FD_ISSET(0, &readfds)) { + n = read(0, buf, 8192); + if (n <= 0) + slirp_exit(0); + n = writen(s, buf, n); + if (n <= 0) + slirp_exit(0); + } + + if (FD_ISSET(s, &readfds)) { + n = read(s, buf, 8192); + if (n <= 0) + slirp_exit(0); + n = writen(0, buf, n); + if (n <= 0) + slirp_exit(0); + } + } + + /* Just in case.... */ + exit(1); +} +#endif + +int (*lprint_print) _P((void *, const char *, va_list)); +char *lprint_ptr, *lprint_ptr2, **lprint_arg; + +#ifdef _MSC_VER //aren't we +#define __STDC__ +#endif + +void +#ifdef __STDC__ +lprint(const char *format, ...) +#else +lprint(va_alist) va_dcl +#endif +{ + va_list args; + +#ifdef __STDC__ + va_start(args, format); +#else + char *format; + va_start(args); + format = va_arg(args, char *); +#endif +#if 0 + /* If we're printing to an sbuf, make sure there's enough room */ + /* XXX +100? */ + if (lprint_sb) { + if ((lprint_ptr - lprint_sb->sb_wptr) >= + (lprint_sb->sb_datalen - (strlen(format) + 100))) { + int deltaw = lprint_sb->sb_wptr - lprint_sb->sb_data; + int deltar = lprint_sb->sb_rptr - lprint_sb->sb_data; + int deltap = lprint_ptr - lprint_sb->sb_data; + + lprint_sb->sb_data = (char *)realloc(lprint_sb->sb_data, + lprint_sb->sb_datalen + TCP_SNDSPACE); + + /* Adjust all values */ + lprint_sb->sb_wptr = lprint_sb->sb_data + deltaw; + lprint_sb->sb_rptr = lprint_sb->sb_data + deltar; + lprint_ptr = lprint_sb->sb_data + deltap; + + lprint_sb->sb_datalen += TCP_SNDSPACE; + } + } +#endif + if (lprint_print) + lprint_ptr += (*lprint_print)(*lprint_arg, format, args); + + /* Check if they want output to be logged to file as well */ + if (lfd) { + /* + * Remove \r's + * otherwise you'll get ^M all over the file + */ + int len = strlen(format); + char *bptr1, *bptr2; + + bptr1 = bptr2 = strdup(format); + + while (len--) { + if (*bptr1 == '\r') + memcpy(bptr1, bptr1+1, len+1); + else + bptr1++; + } + vfprintf(lfd, bptr2, args); + free(bptr2); + } + va_end(args); +} + +void +add_emu(buff) + char *buff; +{ + u_int lport, fport; + u_int8_t tos = 0, emu = 0; + char buff1[256], buff2[256], buff4[128]; + char *buff3 = buff4; + struct emu_t *emup; + struct SLIRPsocket *so; + + if (sscanf(buff, "%256s %256s", buff2, buff1) != 2) { + lprint("Error: Bad arguments\r\n"); + return; + } + + if (sscanf(buff1, "%d:%d", &lport, &fport) != 2) { + lport = 0; + if (sscanf(buff1, "%d", &fport) != 1) { + lprint("Error: Bad first argument\r\n"); + return; + } + } + + if (sscanf(buff2, "%128[^:]:%128s", buff1, buff3) != 2) { + buff3 = 0; + if (sscanf(buff2, "%256s", buff1) != 1) { + lprint("Error: Bad second argument\r\n"); + return; + } + } + + if (buff3) { + if (strcmp(buff3, "lowdelay") == 0) + tos = IPTOS_LOWDELAY; + else if (strcmp(buff3, "throughput") == 0) + tos = IPTOS_THROUGHPUT; + else { + lprint("Error: Expecting \"lowdelay\"/\"throughput\"\r\n"); + return; + } + } + + if (strcmp(buff1, "ftp") == 0) + emu = EMU_FTP; + else if (strcmp(buff1, "irc") == 0) + emu = EMU_IRC; + else if (strcmp(buff1, "none") == 0) + emu = EMU_NONE; /* ie: no emulation */ + else { + lprint("Error: Unknown service\r\n"); + return; + } + + /* First, check that it isn't already emulated */ + for (emup = tcpemu; emup; emup = emup->next) { + if (emup->lport == lport && emup->fport == fport) { + lprint("Error: port already emulated\r\n"); + return; + } + } + + /* link it */ + emup = (struct emu_t *)malloc(sizeof (struct emu_t)); + emup->lport = (u_int16_t)lport; + emup->fport = (u_int16_t)fport; + emup->tos = tos; + emup->emu = emu; + emup->next = tcpemu; + tcpemu = emup; + + /* And finally, mark all current sessions, if any, as being emulated */ + for (so = tcb.so_next; so != &tcb; so = so->so_next) { + if ((lport && lport == ntohs(so->so_lport)) || + (fport && fport == ntohs(so->so_fport))) { + if (emu) + so->so_emu = emu; + if (tos) + so->so_iptos = tos; + } + } + + lprint("Adding emulation for %s to port %d/%d\r\n", buff1, emup->lport, emup->fport); +} + +#ifdef BAD_SPRINTF + +#undef vsprintf +#undef sprintf + +/* + * Some BSD-derived systems have a sprintf which returns char * + */ + +int +vsprintf_len(string, format, args) + char *string; + const char *format; + va_list args; +{ + vsprintf(string, format, args); + return strlen(string); +} + +int +#ifdef __STDC__ +sprintf_len(char *string, const char *format, ...) +#else +sprintf_len(va_alist) va_dcl +#endif +{ + va_list args; +#ifdef __STDC__ + va_start(args, format); +#else + char *string; + char *format; + va_start(args); + string = va_arg(args, char *); + format = va_arg(args, char *); +#endif + vsprintf(string, format, args); + return strlen(string); +} + +#endif + +void +u_sleep(usec) + int usec; +{ + struct timeval t; + fd_set fdset; + + FD_ZERO(&fdset); + + t.tv_sec = 0; + t.tv_usec = usec * 1000; + + select(0, &fdset, &fdset, &fdset, &t); +} + +/* + * Set fd blocking and non-blocking + */ + +void +fd_nonblock(fd) + int fd; +{ +#if defined USE_FIONBIO && defined FIONBIO + ioctlsockopt_t opt = 1; + + ioctlsocket(fd, FIONBIO, &opt); +#else + int opt; + + opt = fcntl(fd, F_GETFL, 0); + opt |= O_NONBLOCK; + fcntl(fd, F_SETFL, opt); +#endif +} + +void +fd_block(fd) + int fd; +{ +#if defined USE_FIONBIO && defined FIONBIO + ioctlsockopt_t opt = 0; + + ioctlsocket(fd, FIONBIO, &opt); +#else + int opt; + + opt = fcntl(fd, F_GETFL, 0); + opt &= ~O_NONBLOCK; + fcntl(fd, F_SETFL, opt); +#endif +} + + +#if 0 +/* + * invoke RSH + */ +int +rsh_exec(so,ns, user, host, args) + struct SLIRPsocket *so; + struct SLIRPsocket *ns; + char *user; + char *host; + char *args; +{ + int fd[2]; + int fd0[2]; + int s; + char buff[256]; + + DEBUG_CALL("rsh_exec"); + DEBUG_ARG("so = %lx", (long)so); + + if (pipe(fd)<0) { + lprint("Error: pipe failed: %s\n", strerror(errno)); + return 0; + } +/* #ifdef HAVE_SOCKETPAIR */ +#if 1 + if (socketpair(PF_UNIX,SOCK_STREAM,0, fd0) == -1) { + close(fd[0]); + close(fd[1]); + lprint("Error: openpty failed: %s\n", strerror(errno)); + return 0; + } +#else + if (slirp_openpty(&fd0[0], &fd0[1]) == -1) { + close(fd[0]); + close(fd[1]); + lprint("Error: openpty failed: %s\n", strerror(errno)); + return 0; + } +#endif + + switch(fork()) { + case -1: + lprint("Error: fork failed: %s\n", strerror(errno)); + close(fd[0]); + close(fd[1]); + close(fd0[0]); + close(fd0[1]); + return 0; + + case 0: + close(fd[0]); + close(fd0[0]); + + /* Set the DISPLAY */ + if (x_port >= 0) { +#ifdef HAVE_SETENV + sprintf(buff, "%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); + setenv("DISPLAY", buff, 1); +#else + sprintf(buff, "DISPLAY=%s:%d.%d", inet_ntoa(our_addr), x_port, x_screen); + putenv(buff); +#endif + } + + dup2(fd0[1], 0); + dup2(fd0[1], 1); + dup2(fd[1], 2); + for (s = 3; s <= 255; s++) + close(s); + + execlp("rsh","rsh","-l", user, host, args, NULL); + + /* Ooops, failed, let's tell the user why */ + + sprintf(buff, "Error: execlp of %s failed: %s\n", + "rsh", strerror(errno)); + write(2, buff, strlen(buff)+1); + close(0); close(1); close(2); /* XXX */ + exit(1); + + default: + close(fd[1]); + close(fd0[1]); + ns->s=fd[0]; + so->s=fd0[0]; + + return 1; + } +} +#endif diff --git a/src/slirp/misc.h b/src/slirp/misc.h new file mode 100644 index 000000000..c509deb92 --- /dev/null +++ b/src/slirp/misc.h @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#ifndef _MISC_H_ +#define _MISC_H_ + +struct ex_list { + int ex_pty; /* Do we want a pty? */ + int ex_addr; /* The last byte of the address */ + int ex_fport; /* Port to telnet to */ + char *ex_exec; /* Command line of what to exec */ + struct ex_list *ex_next; +}; + +extern struct ex_list *exec_list; +extern u_int curtime, time_fasttimo, last_slowtimo, detach_time, detach_wait; + +extern int (*lprint_print) _P((void *, const char *, va_list)); +extern char *lprint_ptr, *lprint_ptr2, **lprint_arg; +extern struct sbuf *lprint_sb; + +#ifndef HAVE_STRDUP +char *strdup _P((const char *)); +#endif + +void do_wait _P((int)); + +#define EMU_NONE 0x0 + +/* TCP emulations */ +#define EMU_CTL 0x1 +#define EMU_FTP 0x2 +#define EMU_KSH 0x3 +#define EMU_IRC 0x4 +#define EMU_REALAUDIO 0x5 +#define EMU_RLOGIN 0x6 +#define EMU_IDENT 0x7 +#define EMU_RSH 0x8 + +#define EMU_NOCONNECT 0x10 /* Don't connect */ + +/* UDP emulations */ +#define EMU_TALK 0x1 +#define EMU_NTALK 0x2 +#define EMU_CUSEEME 0x3 + +struct tos_t { + u_int16_t lport; + u_int16_t fport; + u_int8_t tos; + u_int8_t emu; +}; + +struct emu_t { + u_int16_t lport; + u_int16_t fport; + u_int8_t tos; + u_int8_t emu; + struct emu_t *next; +}; + +extern struct emu_t *tcpemu; + +extern int x_port, x_server, x_display; + +int show_x _P((char *, struct SLIRPsocket *)); +void redir_x _P((u_int32_t, int, int, int)); +void getouraddr _P((void)); +void slirp_insque _P((void *, void *)); +void slirp_remque _P((void *)); +int add_exec _P((struct ex_list **, int, char *, int, int)); +int slirp_openpty _P((int *, int *)); +int fork_exec _P((struct SLIRPsocket *, char *, int)); +void snooze_hup _P((int)); +void snooze _P((void)); +void relay _P((int)); +void add_emu _P((char *)); +void u_sleep _P((int)); +void fd_nonblock _P((int)); +void fd_block _P((int)); +int rsh_exec _P((struct SLIRPsocket *, struct SLIRPsocket *, char *, char *, char *)); + +#endif diff --git a/src/slirp/queue.c b/src/slirp/queue.c new file mode 100644 index 000000000..d91004ad4 --- /dev/null +++ b/src/slirp/queue.c @@ -0,0 +1,116 @@ +/* + * File: queue.c + * Author: Robert I. Pitts + * Last Modified: March 9, 2000 + * Topic: Queue - Array Implementation + * ---------------------------------------------------------------- + */ + +#include +#include +#include "queue.h" + +/* + * Constants + * --------- + * MAX_QUEUE_SIZE = Largest number of items queue can hold. + */ + +#define MAX_QUEUE_SIZE 100 + +/* + * struct queueCDT gives the implementation of a queue. + * It holds the information that we need for each queue. + */ +typedef struct queueCDT { + queueElementT contents[MAX_QUEUE_SIZE]; + int front; + int count; +} queueCDT; + +queueADT QueueCreate(void) +{ + queueADT queue; + + queue = (queueADT)malloc(sizeof(queueCDT)); + + if (queue == NULL) { + fprintf(stderr, "Insufficient Memory for new Queue.\n"); + exit(ERROR_MEMORY); /* Exit program, returning error code. */ + } + + queue->front = 0; + queue->count = 0; + + return queue; +} + +void QueueDestroy(queueADT queue) +{ + free(queue); +} + +void QueueEnter(queueADT queue, queueElementT element) +{ + int newElementIndex; + + if (queue->count >= MAX_QUEUE_SIZE) { +// fprintf(stderr, "QueueEnter on Full Queue.\n"); +// exit(ERROR_QUEUE); /* Exit program, returning error code. */ + return; + } + + /* + * Calculate index at which to put + * next element. + */ + newElementIndex = (queue->front + queue->count) + % MAX_QUEUE_SIZE; + queue->contents[newElementIndex] = element; +//printf("element %d, pointer to %d, [%s]\n",newElementIndex,element,element); + + queue->count++; +} + +int QueuePeek(queueADT queue) +{ +return queue->count; +} + +queueElementT QueueDelete(queueADT queue) +{ + queueElementT oldElement; + + if (queue->count <= 0) { + //fprintf(stderr, "QueueDelete on Empty Queue.\n"); + //exit(ERROR_QUEUE); /* Exit program, returning error code. */ + return NULL; + } + + /* Save the element so we can return it. */ + oldElement = queue->contents[queue->front]; + + /* + * Advance the index of the front, + * making sure it wraps around the + * array properly. + */ + queue->front++; + queue->front %= MAX_QUEUE_SIZE; + +//printf("dequing @%d [%s]\n",oldElement,oldElement); + + queue->count--; + + return oldElement; +} + +int QueueIsEmpty(queueADT queue) +{ + return queue->count <= 0; +} + +int QueueIsFull(queueADT queue) +{ + return queue->count >= MAX_QUEUE_SIZE; +} diff --git a/src/slirp/queue.h b/src/slirp/queue.h new file mode 100644 index 000000000..534dcb84b --- /dev/null +++ b/src/slirp/queue.h @@ -0,0 +1,99 @@ +/* + * File: queue.h + * Author: Robert I. Pitts + * Last Modified: March 9, 2000 + * Topic: Queue - Array Implementation + * ---------------------------------------------------------------- + */ + +#ifndef _QUEUE_H +#define _QUEUE_H + +/* + * Constants + * --------- + * ERROR_* These signal error conditions in queue functions + * and are used as exit codes for the program. + */ +#define ERROR_QUEUE 2 +#define ERROR_MEMORY 3 + +/* + * Type: queueElementT + * ------------------- + * This is the type of objects held in the queue. + */ + +/*typedef char queueElementT; +typedef unsigned char *queueElementT; +*/ + +struct queuepacket{ + int len; + unsigned char data[2000]; +}; +typedef struct queuepacket *queueElementT; + +/* + * Type: queueADT + * -------------- + * The actual implementation of a queue is completely + * hidden. Client will work with queueADT which is a + * pointer to underlying queueCDT. + */ + +/* + * NOTE: need word struct below so that the compiler + * knows at least that a queueCDT will be some sort + * of struct. + */ + +typedef struct queueCDT *queueADT; + +/* + * Function: QueueCreate + * Usage: queue = QueueCreate(); + * ------------------------- + * A new empty queue is created and returned. + */ + +queueADT QueueCreate(void); + +/* Function: QueueDestroy + * Usage: QueueDestroy(queue); + * ----------------------- + * This function frees all memory associated with + * the queue. "queue" may not be used again unless + * queue = QueueCreate() is called first. + */ + +void QueueDestroy(queueADT queue); + +/* + * Functions: QueueEnter, QueueDelete + * Usage: QueueEnter(queue, element); + * element = QueueDelete(queue); + * -------------------------------------------- + * These are the fundamental queue operations that enter + * elements in and delete elements from the queue. A call + * to QueueDelete() on an empty queue or to QueueEnter() + * on a full queue is an error. Make use of QueueIsFull() + * and QueueIsEmpty() (see below) to avoid these errors. + */ + +void QueueEnter(queueADT queue, queueElementT element); +queueElementT QueueDelete(queueADT queue); + + +/* + * Functions: QueueIsEmpty, QueueIsFull + * Usage: if (QueueIsEmpty(queue)) ... + * ----------------------------------- + * These return a true/false value based on whether + * the queue is empty or full, respectively. + */ + +int QueueIsEmpty(queueADT queue); +int QueueIsFull(queueADT queue); + +#endif /* not defined _QUEUE_H */ diff --git a/src/slirp/sbuf.c b/src/slirp/sbuf.c new file mode 100644 index 000000000..b9baa4181 --- /dev/null +++ b/src/slirp/sbuf.c @@ -0,0 +1,202 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#include +#include "slirp.h" + +/* Done as a macro in socket.h */ +/* int + * sbspace(struct sockbuff *sb) + * { + * return SB_DATALEN - sb->sb_cc; + * } + */ + +void +sbfree(sb) + struct sbuf *sb; +{ + free(sb->sb_data); +} + +void +sbdrop(sb, num) + struct sbuf *sb; + int num; +{ + /* + * We can only drop how much we have + * This should never succeed + */ + if(num > sb->sb_cc) + num = sb->sb_cc; + sb->sb_cc -= num; + sb->sb_rptr += num; + if(sb->sb_rptr >= sb->sb_data + sb->sb_datalen) + sb->sb_rptr -= sb->sb_datalen; + +} + +void +sbreserve(sb, size) + struct sbuf *sb; + int size; +{ + if (sb->sb_data) { + /* Already alloced, realloc if necessary */ + if (sb->sb_datalen != size) { + sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)realloc(sb->sb_data, size); + sb->sb_cc = 0; + if (sb->sb_wptr) + sb->sb_datalen = size; + else + sb->sb_datalen = 0; + } + } else { + sb->sb_wptr = sb->sb_rptr = sb->sb_data = (char *)malloc(size); + sb->sb_cc = 0; + if (sb->sb_wptr) + sb->sb_datalen = size; + else + sb->sb_datalen = 0; + } +} + +/* + * Try and write() to the socket, whatever doesn't get written + * append to the buffer... for a host with a fast net connection, + * this prevents an unnecessary copy of the data + * (the socket is non-blocking, so we won't hang) + */ +void +sbappend(so, m) + struct SLIRPsocket *so; + struct SLIRPmbuf *m; +{ + int ret = 0; + + DEBUG_CALL("sbappend"); + DEBUG_ARG("so = %lx", (long)so); + DEBUG_ARG("m = %lx", (long)m); + DEBUG_ARG("m->m_len = %d", m->m_len); + + /* Shouldn't happen, but... e.g. foreign host closes connection */ + if (m->m_len <= 0) { + m_free(m); + return; + } + + /* + * If there is urgent data, call sosendoob + * if not all was sent, sowrite will take care of the rest + * (The rest of this function is just an optimisation) + */ + if (so->so_urgc) { + sbappendsb(&so->so_rcv, m); + m_free(m); + sosendoob(so); + return; + } + + /* + * We only write if there's nothing in the buffer, + * ottherwise it'll arrive out of order, and hence corrupt + */ + if (!so->so_rcv.sb_cc) + ret = send(so->s, m->m_data, m->m_len, 0); + + if (ret <= 0) { + /* + * Nothing was written + * It's possible that the socket has closed, but + * we don't need to check because if it has closed, + * it will be detected in the normal way by soread() + */ + sbappendsb(&so->so_rcv, m); + } else if (ret != m->m_len) { + /* + * Something was written, but not everything.. + * sbappendsb the rest + */ + m->m_len -= ret; + m->m_data += ret; + sbappendsb(&so->so_rcv, m); + } /* else */ + /* Whatever happened, we free the SLIRPmbuf */ + m_free(m); +} + +/* + * Copy the data from m into sb + * The caller is responsible to make sure there's enough room + */ +void +sbappendsb(sb, m) + struct sbuf *sb; + struct SLIRPmbuf *m; +{ + int len, n, nn; + + len = m->m_len; + + if (sb->sb_wptr < sb->sb_rptr) { + n = sb->sb_rptr - sb->sb_wptr; + if (n > len) n = len; + memcpy(sb->sb_wptr, m->m_data, n); + } else { + /* Do the right edge first */ + n = sb->sb_data + sb->sb_datalen - sb->sb_wptr; + if (n > len) n = len; + memcpy(sb->sb_wptr, m->m_data, n); + len -= n; + if (len) { + /* Now the left edge */ + nn = sb->sb_rptr - sb->sb_data; + if (nn > len) nn = len; + memcpy(sb->sb_data,m->m_data+n,nn); + n += nn; + } + } + + sb->sb_cc += n; + sb->sb_wptr += n; + if (sb->sb_wptr >= sb->sb_data + sb->sb_datalen) + sb->sb_wptr -= sb->sb_datalen; +} + +/* + * Copy data from sbuf to a normal, straight buffer + * Don't update the sbuf rptr, this will be + * done in sbdrop when the data is acked + */ +void +sbcopy(sb, off, len, to) + struct sbuf *sb; + int off; + int len; + char *to; +{ + char *from; + + from = sb->sb_rptr + off; + if (from >= sb->sb_data + sb->sb_datalen) + from -= sb->sb_datalen; + + if (from < sb->sb_wptr) { + if (len > sb->sb_cc) len = sb->sb_cc; + memcpy(to,from,len); + } else { + /* re-use off */ + off = (sb->sb_data + sb->sb_datalen) - from; + if (off > len) off = len; + memcpy(to,from,off); + len -= off; + if (len) + memcpy(to+off,sb->sb_data,len); + } +} + diff --git a/src/slirp/sbuf.h b/src/slirp/sbuf.h new file mode 100644 index 000000000..aa4724df7 --- /dev/null +++ b/src/slirp/sbuf.h @@ -0,0 +1,31 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#ifndef _SBUF_H_ +#define _SBUF_H_ + +#define sbflush(sb) sbdrop((sb),(sb)->sb_cc) +#define sbspace(sb) ((sb)->sb_datalen - (sb)->sb_cc) + +struct sbuf { + u_int sb_cc; /* actual chars in buffer */ + u_int sb_datalen; /* Length of data */ + char *sb_wptr; /* write pointer. points to where the next + * bytes should be written in the sbuf */ + char *sb_rptr; /* read pointer. points to where the next + * byte should be read from the sbuf */ + char *sb_data; /* Actual data */ +}; + +void sbfree _P((struct sbuf *)); +void sbdrop _P((struct sbuf *, int)); +void sbreserve _P((struct sbuf *, int)); +void sbappend _P((struct SLIRPsocket *, struct SLIRPmbuf *)); +void sbappendsb _P((struct sbuf *, struct SLIRPmbuf *)); +void sbcopy _P((struct sbuf *, int, int, char *)); + +#endif diff --git a/src/slirp/slirp.c b/src/slirp/slirp.c new file mode 100644 index 000000000..dc912c960 --- /dev/null +++ b/src/slirp/slirp.c @@ -0,0 +1,682 @@ +#include "slirp.h" + +/* host address */ +struct in_addr our_addr; +/* host dns address */ +struct in_addr dns_addr; +/* host loopback address */ +struct in_addr loopback_addr; + +/* address for slirp virtual addresses */ +struct in_addr special_addr; +/* virtual address alias for host */ +struct in_addr alias_addr; + +const uint8_t special_ethaddr[6] = { + 0x52, 0x54, 0x00, 0x12, 0x35, 0x00 +}; + +uint8_t client_ethaddr[6]; + +int do_slowtimo; +int link_up; +struct timeval tt; +FILE *lfd; +struct ex_list *exec_list; + +/* XXX: suppress those select globals */ +fd_set *global_readfds, *global_writefds, *global_xfds; + +char slirp_hostname[33]; + +#ifdef _WIN32 + +static int get_dns_addr(struct in_addr *pdns_addr) +{ + FIXED_INFO *FixedInfo=NULL; + ULONG BufLen; + DWORD ret; + IP_ADDR_STRING *pIPAddr; + struct in_addr tmp_addr; + + FixedInfo = (FIXED_INFO *)GlobalAlloc(GPTR, sizeof(FIXED_INFO)); + BufLen = sizeof(FIXED_INFO); + + if (ERROR_BUFFER_OVERFLOW == GetNetworkParams(FixedInfo, &BufLen)) { + if (FixedInfo) { + GlobalFree(FixedInfo); + FixedInfo = NULL; + } + FixedInfo = GlobalAlloc(GPTR, BufLen); + } + + if ((ret = GetNetworkParams(FixedInfo, &BufLen)) != ERROR_SUCCESS) { + printf("GetNetworkParams failed. ret = %08x\n", (u_int)ret ); + if (FixedInfo) { + GlobalFree(FixedInfo); + FixedInfo = NULL; + } + return -1; + } + + pIPAddr = &(FixedInfo->DnsServerList); + inet_aton(pIPAddr->IpAddress.String, &tmp_addr); + *pdns_addr = tmp_addr; +#if 0 + printf( "DNS Servers:\n" ); + printf( "DNS Addr:%s\n", pIPAddr->IpAddress.String ); + + pIPAddr = FixedInfo -> DnsServerList.Next; + while ( pIPAddr ) { + printf( "DNS Addr:%s\n", pIPAddr ->IpAddress.String ); + pIPAddr = pIPAddr ->Next; + } +#endif + if (FixedInfo) { + GlobalFree(FixedInfo); + FixedInfo = NULL; + } + return 0; +} + +#else + +static int get_dns_addr(struct in_addr *pdns_addr) +{ + char buff[512]; + char buff2[256]; + FILE *f; + int found = 0; + struct in_addr tmp_addr; + + f = fopen("/etc/resolv.conf", "r"); + if (!f) + return -1; + + lprint("IP address of your DNS(s): "); + while (fgets(buff, 512, f) != NULL) { + if (sscanf(buff, "nameserver%*[ \t]%256s", buff2) == 1) { + if (!inet_aton(buff2, &tmp_addr)) + continue; + if (tmp_addr.s_addr == loopback_addr.s_addr) + tmp_addr = our_addr; + /* If it's the first one, set it to dns_addr */ + if (!found) + *pdns_addr = tmp_addr; + else + lprint(", "); + if (++found > 3) { + lprint("(more)"); + break; + } else + lprint("%s", inet_ntoa(tmp_addr)); + } + } + fclose(f); + if (!found) + return -1; + return 0; +} + +#endif + +#ifdef _WIN32 +void slirp_cleanup(void) +{ + WSACleanup(); +} +#endif + +int slirp_init(void) +{ +#ifdef SLIRP_DEBUG + // debug_init("/tmp/slirp.log", DEBUG_DEFAULT); + // debug_init("slirplog.txt",DEBUG_DEFAULT); + //debug_init("slirplog.txt",DBG_CALL); +debug_init("slirplog.txt",DEBUG_DEFAULT); +#endif + +#ifdef _WIN32 + { + WSADATA Data; + WSAStartup(MAKEWORD(2,0), &Data); + atexit(slirp_cleanup); + } +#endif + + link_up = 1; + + if_init(); + ip_init(); + + /* Initialise mbufs *after* setting the MTU */ + m_init(); + + /* set default addresses */ + inet_aton("127.0.0.1", &loopback_addr); + + if (get_dns_addr(&dns_addr) < 0) + return -1; + + inet_aton(CTL_SPECIAL, &special_addr); + alias_addr.s_addr = special_addr.s_addr | htonl(CTL_ALIAS); + getouraddr(); + return 0; +} + +#define CONN_CANFSEND(so) (((so)->so_state & (SS_FCANTSENDMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED) +#define CONN_CANFRCV(so) (((so)->so_state & (SS_FCANTRCVMORE|SS_ISFCONNECTED)) == SS_ISFCONNECTED) +#define UPD_NFDS(x) if (nfds < (x)) nfds = (x) + +/* + * curtime kept to an accuracy of 1ms + */ +#ifdef _WIN32 +static void updtime(void) +{ + struct _timeb tb; + + _ftime(&tb); + curtime = (u_int)tb.time * (u_int)1000; + curtime += (u_int)tb.millitm; +} +#else +static void updtime(void) +{ + gettimeofday(&tt, 0); + + curtime = (u_int)tt.tv_sec * (u_int)1000; + curtime += (u_int)tt.tv_usec / (u_int)1000; + + if ((tt.tv_usec % 1000) >= 500) + curtime++; +} +#endif + +int slirp_select_fill(int *pnfds, + fd_set *readfds, fd_set *writefds, fd_set *xfds) +{ + struct SLIRPsocket *so, *so_next; + int nfds; + int timeout, tmp_time; + + /* fail safe */ + global_readfds = NULL; + global_writefds = NULL; + global_xfds = NULL; + + nfds = *pnfds; + /* + * First, TCP sockets + */ + do_slowtimo = 0; + if (link_up) { + /* + * *_slowtimo needs calling if there are IP fragments + * in the fragment queue, or there are TCP connections active + */ + do_slowtimo = ((tcb.so_next != &tcb) || + ((struct ipasfrag *)&ipq != (struct ipasfrag *)ipq.next)); + + for (so = tcb.so_next; (so != &tcb); so = so_next) { + so_next = so->so_next; + + + /* + * See if we need a tcp_fasttimo + */ + if(&so->so_tcpcb->t_flags!=0x0){ //This is to prevent a common lockup. + if (time_fasttimo == 0 && so->so_tcpcb->t_flags & TF_DELACK) + time_fasttimo = curtime; }/* Flag when we want a fasttimo */ + + + /* + * NOFDREF can include still connecting to local-host, + * newly socreated() sockets etc. Don't want to select these. + */ + if (so->so_state & SS_NOFDREF || so->s == -1) + continue; + + /* + * Set for reading sockets which are accepting + */ + if (so->so_state & SS_FACCEPTCONN) { + FD_SET(so->s, readfds); + UPD_NFDS(so->s); + continue; + } + + /* + * Set for writing sockets which are connecting + */ + if (so->so_state & SS_ISFCONNECTING) { + FD_SET(so->s, writefds); + UPD_NFDS(so->s); + continue; + } + + /* + * Set for writing if we are connected, can send more, and + * we have something to send + */ + if (CONN_CANFSEND(so) && so->so_rcv.sb_cc) { + FD_SET(so->s, writefds); + UPD_NFDS(so->s); + } + + /* + * Set for reading (and urgent data) if we are connected, can + * receive more, and we have room for it XXX /2 ? + */ + if (CONN_CANFRCV(so) && (so->so_snd.sb_cc < (so->so_snd.sb_datalen/2))) { + FD_SET(so->s, readfds); + FD_SET(so->s, xfds); + UPD_NFDS(so->s); + } + } + + /* + * UDP sockets + */ + for (so = udb.so_next; so != &udb; so = so_next) { + so_next = so->so_next; + + /* + * See if it's timed out + */ + if (so->so_expire) { + if (so->so_expire <= curtime) { + udp_detach(so); + continue; + } else + do_slowtimo = 1; /* Let socket expire */ + } + + /* + * When UDP packets are received from over the + * link, they're sendto()'d straight away, so + * no need for setting for writing + * Limit the number of packets queued by this session + * to 4. Note that even though we try and limit this + * to 4 packets, the session could have more queued + * if the packets needed to be fragmented + * (XXX <= 4 ?) + */ + if ((so->so_state & SS_ISFCONNECTED) && so->so_queued <= 4) { + FD_SET(so->s, readfds); + UPD_NFDS(so->s); + } + } + } + + /* + * Setup timeout to use minimum CPU usage, especially when idle + */ + + timeout = -1; + + /* + * If a slowtimo is needed, set timeout to 5ms from the last + * slow timeout. If a fast timeout is needed, set timeout within + * 2ms of when it was requested. + */ +# define SLOW_TIMO 5 +# define FAST_TIMO 2 + if (do_slowtimo) { + timeout = (SLOW_TIMO - (curtime - last_slowtimo)) * 1000; + if (timeout < 0) + timeout = 0; + else if (timeout > (SLOW_TIMO * 1000)) + timeout = SLOW_TIMO * 1000; + + /* Can only fasttimo if we also slowtimo */ + if (time_fasttimo) { + tmp_time = (FAST_TIMO - (curtime - time_fasttimo)) * 1000; + if (tmp_time < 0) + tmp_time = 0; + + /* Choose the smallest of the 2 */ + if (tmp_time < timeout) + timeout = tmp_time; + } + } + *pnfds = nfds; + + /* + * Adjust the timeout to make the minimum timeout + * 2ms (XXX?) to lessen the CPU load + */ + if (timeout < (FAST_TIMO * 1000)) + timeout = FAST_TIMO * 1000; + + return timeout; +} + +void slirp_select_poll(fd_set *readfds, fd_set *writefds, fd_set *xfds) +{ + struct SLIRPsocket *so, *so_next; + int ret; + + global_readfds = readfds; + global_writefds = writefds; + global_xfds = xfds; + + /* Update time */ + updtime(); + + /* + * See if anything has timed out + */ + if (link_up) { + if (time_fasttimo && ((curtime - time_fasttimo) >= FAST_TIMO)) { + tcp_fasttimo(); + time_fasttimo = 0; + } + if (do_slowtimo && ((curtime - last_slowtimo) >= SLOW_TIMO)) { + ip_slowtimo(); + tcp_slowtimo(); + last_slowtimo = curtime; + } + } + + /* + * Check sockets + */ + if (link_up) { + /* + * Check TCP sockets + */ + for (so = tcb.so_next; so != &tcb; so = so_next) { + so_next = so->so_next; + + /* + * FD_ISSET is meaningless on these sockets + * (and they can crash the program) + */ + if (so->so_state & SS_NOFDREF || so->s == -1) + continue; + + /* + * Check for URG data + * This will soread as well, so no need to + * test for readfds below if this succeeds + */ + if (FD_ISSET(so->s, xfds)) + sorecvoob(so); + /* + * Check sockets for reading + */ + else if (FD_ISSET(so->s, readfds)) { + /* + * Check for incoming connections + */ + if (so->so_state & SS_FACCEPTCONN) { + tcp_connect(so); + continue; + } /* else */ + ret = soread(so); + + /* Output it if we read something */ + if (ret > 0) + tcp_output(sototcpcb(so)); + } + + /* + * Check sockets for writing + */ + if (FD_ISSET(so->s, writefds)) { + /* + * Check for non-blocking, still-connecting sockets + */ + if (so->so_state & SS_ISFCONNECTING) { + /* Connected */ + so->so_state &= ~SS_ISFCONNECTING; + + //ret = send(so->s, &ret, 0, 0); + //winsock2.h:549:32: note: expected 'const char *' but argument is of type 'int *' + //WINSOCK_API_LINKAGE int PASCAL send(SOCKET,const char*,int,int); JASON + //ret = send(so->s, "a", 1, 0); WHY THE HELL WAS THIS HERE?! + ret = send(so->s, &ret, 0, 0); //This is what it should be. + if (ret < 0) { + /* XXXXX Must fix, zero bytes is a NOP */ + if (errno == EAGAIN || errno == EWOULDBLOCK || + errno == EINPROGRESS || errno == ENOTCONN) + continue; + + /* else failed */ + so->so_state = SS_NOFDREF; + } + /* else so->so_state &= ~SS_ISFCONNECTING; */ + + /* + * Continue tcp_input + */ + tcp_input((struct SLIRPmbuf *)NULL, sizeof(struct ip), so); + /* continue; */ + } else + ret = sowrite(so); + /* + * XXXXX If we wrote something (a lot), there + * could be a need for a window update. + * In the worst case, the remote will send + * a window probe to get things going again + */ + } + + /* + * Probe a still-connecting, non-blocking socket + * to check if it's still alive + */ +#ifdef PROBE_CONN + if (so->so_state & SS_ISFCONNECTING) { + ret = recv(so->s, (char *)&ret, 0,0); + + if (ret < 0) { + /* XXX */ + if (errno == EAGAIN || errno == EWOULDBLOCK || + errno == EINPROGRESS || errno == ENOTCONN) + continue; /* Still connecting, continue */ + + /* else failed */ + so->so_state = SS_NOFDREF; + + /* tcp_input will take care of it */ + } else { + ret = send(so->s, &ret, 0,0); + if (ret < 0) { + /* XXX */ + if (errno == EAGAIN || errno == EWOULDBLOCK || + errno == EINPROGRESS || errno == ENOTCONN) + continue; + /* else failed */ + so->so_state = SS_NOFDREF; + } else + so->so_state &= ~SS_ISFCONNECTING; + + } + tcp_input((struct SLIRPmbuf *)NULL, sizeof(struct ip),so); + } /* SS_ISFCONNECTING */ +#endif + } + + /* + * Now UDP sockets. + * Incoming packets are sent straight away, they're not buffered. + * Incoming UDP data isn't buffered either. + */ + for (so = udb.so_next; so != &udb; so = so_next) { + so_next = so->so_next; + + if (so->s != -1 && FD_ISSET(so->s, readfds)) { + sorecvfrom(so); + } + } + } + + /* + * See if we can start outputting + */ + if (if_queued && link_up) + if_start(); + + /* clear global file descriptor sets. + * these reside on the stack in vl.c + * so they're unusable if we're not in + * slirp_select_fill or slirp_select_poll. + */ + global_readfds = NULL; + global_writefds = NULL; + global_xfds = NULL; +} + +#define ETH_ALEN 6 +#define ETH_HLEN 14 + +#define ETH_P_IP 0x0800 /* Internet Protocol packet */ +#define ETH_P_ARP 0x0806 /* Address Resolution packet */ + +#define ARPOP_REQUEST 1 /* ARP request */ +#define ARPOP_REPLY 2 /* ARP reply */ + +struct ethhdr +{ + unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ + unsigned char h_source[ETH_ALEN]; /* source ether addr */ + unsigned short h_proto; /* packet type ID field */ +}; + +struct arphdr +{ + unsigned short ar_hrd; /* format of hardware address */ + unsigned short ar_pro; /* format of protocol address */ + unsigned char ar_hln; /* length of hardware address */ + unsigned char ar_pln; /* length of protocol address */ + unsigned short ar_op; /* ARP opcode (command) */ + + /* + * Ethernet looks like this : This bit is variable sized however... + */ + unsigned char ar_sha[ETH_ALEN]; /* sender hardware address */ + unsigned char ar_sip[4]; /* sender IP address */ + unsigned char ar_tha[ETH_ALEN]; /* target hardware address */ + unsigned char ar_tip[4]; /* target IP address */ +}; + +void arp_input(const uint8_t *pkt, int pkt_len) +{ + struct ethhdr *eh = (struct ethhdr *)pkt; + struct arphdr *ah = (struct arphdr *)(pkt + ETH_HLEN); + uint8_t arp_reply[ETH_HLEN + sizeof(struct arphdr)]; + struct ethhdr *reh = (struct ethhdr *)arp_reply; + struct arphdr *rah = (struct arphdr *)(arp_reply + ETH_HLEN); + int ar_op; + struct ex_list *ex_ptr; + + ar_op = ntohs(ah->ar_op); + switch(ar_op) { + case ARPOP_REQUEST: + if (!memcmp(ah->ar_tip, &special_addr, 3)) { + if (ah->ar_tip[3] == CTL_DNS || ah->ar_tip[3] == CTL_ALIAS) + goto arp_ok; + for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { + if (ex_ptr->ex_addr == ah->ar_tip[3]) + goto arp_ok; + } + return; + arp_ok: + /* XXX: make an ARP request to have the client address */ + memcpy(client_ethaddr, eh->h_source, ETH_ALEN); + + /* ARP request for alias/dns mac address */ + memcpy(reh->h_dest, pkt + ETH_ALEN, ETH_ALEN); + memcpy(reh->h_source, special_ethaddr, ETH_ALEN - 1); + reh->h_source[5] = ah->ar_tip[3]; + reh->h_proto = htons(ETH_P_ARP); + + rah->ar_hrd = htons(1); + rah->ar_pro = htons(ETH_P_IP); + rah->ar_hln = ETH_ALEN; + rah->ar_pln = 4; + rah->ar_op = htons(ARPOP_REPLY); + memcpy(rah->ar_sha, reh->h_source, ETH_ALEN); + memcpy(rah->ar_sip, ah->ar_tip, 4); + memcpy(rah->ar_tha, ah->ar_sha, ETH_ALEN); + memcpy(rah->ar_tip, ah->ar_sip, 4); + slirp_output(arp_reply, sizeof(arp_reply)); + } + break; + default: + break; + } +} + +void slirp_input(const uint8_t *pkt, int pkt_len) +{ + struct SLIRPmbuf *m; + int proto; + + if (pkt_len < ETH_HLEN) + return; + + proto = (pkt[12] << 8) | pkt[13]; + switch(proto) { + case ETH_P_ARP: + arp_input(pkt, pkt_len); + break; + case ETH_P_IP: + m = m_get(); + if (!m) + return; + /* Note: we add to align the IP header */ + m->m_len = pkt_len + 2; + memcpy(m->m_data + 2, pkt, pkt_len); + + m->m_data += 2 + ETH_HLEN; + m->m_len -= 2 + ETH_HLEN; + + ip_input(m); + break; + default: + break; + } +} + +/* output the IP packet to the ethernet device */ +void if_encap(const uint8_t *ip_data, int ip_data_len) +{ + uint8_t buf[1600]; + struct ethhdr *eh = (struct ethhdr *)buf; + + if (ip_data_len + ETH_HLEN > sizeof(buf)) + return; + + memcpy(eh->h_dest, client_ethaddr, ETH_ALEN); + memcpy(eh->h_source, special_ethaddr, ETH_ALEN - 1); + /* XXX: not correct */ + eh->h_source[5] = CTL_ALIAS; + eh->h_proto = htons(ETH_P_IP); + memcpy(buf + sizeof(struct ethhdr), ip_data, ip_data_len); + slirp_output(buf, ip_data_len + ETH_HLEN); +} + +int slirp_redir(int is_udp, int host_port, + struct in_addr guest_addr, int guest_port) +{ + if (is_udp) { + if (!udp_listen(htons(host_port), guest_addr.s_addr, + htons(guest_port), 0)) + return -1; + } else { + if (!solisten(htons(host_port), guest_addr.s_addr, + htons(guest_port), 0)) + return -1; + } + return 0; +} + +int slirp_add_exec(int do_pty, const char *args, int addr_low_byte, + int guest_port) +{ + return add_exec(&exec_list, do_pty, (char *)args, + addr_low_byte, htons(guest_port)); +} diff --git a/src/slirp/slirp.h b/src/slirp/slirp.h new file mode 100644 index 000000000..92cfe2fc9 --- /dev/null +++ b/src/slirp/slirp.h @@ -0,0 +1,415 @@ +#ifndef __COMMON_H__ +#define __COMMON_H__ + +#define SLIRP_VERSION "Cockatrice special" + +#define CONFIG_QEMU + +#ifndef CONFIG_QEMU +#include "version.h" +#endif +#include "config.h" +#include "slirp_config.h" + +#ifdef _WIN32 +#ifdef __GNUC__ //MINGW? +# include +typedef uint8_t u_int8_t; +typedef uint16_t u_int16_t; +typedef uint32_t u_int32_t; +typedef uint64_t u_int64_t; +typedef char *SLIRPcaddr_t; +typedef int socklen_t; +typedef unsigned long ioctlsockopt_t; +#else +typedef unsigned char u_int8_t; +typedef char int8_t; +typedef unsigned char uint8_t; +typedef unsigned short u_int16_t; +typedef unsigned short uint16_t; +typedef short int16_t; +typedef unsigned int u_int32_t; +typedef unsigned int uint32_t; +typedef int int32_t; + +typedef unsigned __int64 u_int64_t; +typedef char *SLIRPcaddr_t; +typedef int socklen_t; +typedef unsigned long ioctlsockopt_t; + +#endif + +# include //needs to be on top otherwise, it'll pull in winsock1 +# include + +# include +# include + +# define USE_FIONBIO 1 +# define EWOULDBLOCK WSAEWOULDBLOCK +# define EINPROGRESS WSAEINPROGRESS +# define ENOTCONN WSAENOTCONN +# define EHOSTUNREACH WSAEHOSTUNREACH +# define ENETUNREACH WSAENETUNREACH +# define ECONNREFUSED WSAECONNREFUSED + +/* Basilisk II Router defines those */ +# define udp_read_completion slirp_udp_read_completion +# define write_udp slirp_write_udp +# define init_udp slirp_init_udp +# define final_udp slirp_final_udp +#else +typedef int ioctlsockopt_t; +# define ioctlsocket ioctl +# define closesocket(s) close(s) +# define O_BINARY 0 +#endif + +#include +#ifdef HAVE_SYS_BITYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif + +#ifndef _MSC_VER +#include +#else +#include +#endif + +#ifdef NEED_TYPEDEFS +typedef char int8_t; +typedef unsigned char u_int8_t; + +# if SIZEOF_SHORT == 2 + typedef short int16_t; + typedef unsigned short u_int16_t; +# else +# if SIZEOF_INT == 2 + typedef int int16_t; + typedef unsigned int u_int16_t; +# else + #error Cannot find a type with sizeof() == 2 +# endif +# endif + +# if SIZEOF_SHORT == 4 + typedef short int32_t; + typedef unsigned short u_int32_t; +# else +# if SIZEOF_INT == 4 + typedef int int32_t; + typedef unsigned int u_int32_t; +# else + #error Cannot find a type with sizeof() == 4 +# endif +# endif +#endif /* NEED_TYPEDEFS */ + +/* Basilisk II types glue */ +typedef u_int8_t uint8; +typedef u_int16_t uint16; +typedef u_int32_t uint32; + +#ifdef HAVE_UNISTD_H +# include +#endif + +#ifdef HAVE_STDLIB_H +# include +#endif + +#include +#include + +#ifndef HAVE_MEMMOVE +#define memmove(x, y, z) bcopy(y, x, z) +#endif + +#if TIME_WITH_SYS_TIME +# include +# include +#else +# if HAVE_SYS_TIME_H +# include +# else +# include +# endif +#endif + +#ifdef HAVE_STRING_H +# include +#else +#ifndef _MSC_VER +# include +#else +#include +#endif +#endif + +#ifndef _WIN32 +#include +#endif + +#ifndef _P +#ifndef NO_PROTOTYPES +# define _P(x) x +#else +# define _P(x) () +#endif +#endif + +#ifndef _WIN32 +#include +#include +#endif + +#ifdef GETTIMEOFDAY_ONE_ARG +#define gettimeofday(x, y) gettimeofday(x) +#endif + +/* Systems lacking strdup() definition in . */ +#if defined(ultrix) +char *strdup _P((const char *)); +#endif + +/* Systems lacking malloc() definition in . */ +#if defined(ultrix) || defined(hcx) +void *malloc _P((size_t arg)); +void free _P((void *ptr)); +#endif + +#ifndef HAVE_INET_ATON +int inet_aton _P((const char *cp, struct in_addr *ia)); +#endif + +#include +#ifndef NO_UNIX_SOCKETS +#include +#endif +#include +#ifdef HAVE_SYS_SIGNAL_H +# include +#endif +#ifndef _WIN32 +#include +#endif + +#if defined(HAVE_SYS_IOCTL_H) +# include +#endif + +#ifdef HAVE_SYS_SELECT_H +# include +#endif + +#ifdef HAVE_SYS_WAIT_H +# include +#endif + +#ifdef HAVE_SYS_FILIO_H +# include +#endif + +#ifdef USE_PPP +#include +#endif + +#ifdef __STDC__ +#include +#else +#include +#endif + +#include + +/* Avoid conflicting with the libc insque() and remque(), which + have different prototypes. */ +#define insque slirp_insque +#define remque slirp_remque + +#ifdef HAVE_SYS_STROPTS_H +#include +#endif + +#include "debug.h" + +#if defined __GNUC__ +#define PACKED__ __attribute__ ((packed)) +#elif defined __sgi +#define PRAGMA_PACK_SUPPORTED 1 +#define PACK_END 0 +#define PACKED__ +#elif _MSC_VER +//#define PRAGMA_PACK_SUPPORTED 1 +//#define PACK_END 4 +#define PACKED__ +#else +#error "Packed attribute or pragma shall be supported" +#endif + +#if defined(_MSC_VER) +#pragma pack(push, 1) +#endif + +#include "ip.h" +#include "tcp.h" +#include "tcp_timer.h" +#include "tcp_var.h" +#include "tcpip.h" +#include "udp.h" +#include "icmp_var.h" +#include "mbuf.h" +#include "sbuf.h" +#include "socket.h" +#include "if.h" +#include "main.h" +#include "misc.h" +#include "ctl.h" +#ifdef USE_PPP +#include "ppp/pppd.h" +#include "ppp/ppp.h" +#endif + +#include "bootp.h" +#include "tftp.h" +#include "libslirp.h" + +extern struct ttys *ttys_unit[MAX_INTERFACES]; + +#ifndef NULL +#define NULL (void *)0 +#endif + +#ifndef FULL_BOLT +void if_start _P((void)); +#else +void if_start _P((struct ttys *)); +#endif + +#ifdef BAD_SPRINTF +# define vsprintf vsprintf_len +# define sprintf sprintf_len + extern int vsprintf_len _P((char *, const char *, va_list)); + extern int sprintf_len _P((char *, const char *, ...)); +#endif + +#ifdef DECLARE_SPRINTF +# ifndef BAD_SPRINTF + extern int vsprintf _P((char *, const char *, va_list)); +# endif + extern int vfprintf _P((FILE *, const char *, va_list)); +#endif + +#ifndef HAVE_STRERROR +#ifndef _MSC_VER + extern char *strerror _P((int error)); + #define HAVE_STRERROR +#endif +#endif + +#ifndef HAVE_INDEX + char *index _P((const char *, int)); +#endif + +#ifndef HAVE_GETHOSTID + long gethostid _P((void)); +#endif + +void lprint _P((const char *, ...)); + +extern int do_echo; + +#ifdef _MSC_VER +#define inline +#endif + +#if SIZEOF_CHAR_P == 4 +# define insque_32 insque +# define remque_32 remque +#else + extern inline void insque_32 _P((void *, void *)); + extern inline void remque_32 _P((void *)); +#endif + +#ifndef _WIN32 +#include +#endif + +#define DEFAULT_BAUD 115200 + +/* cksum.c */ +int cksum(struct SLIRPmbuf *m, int len); + +/* if.c */ +void if_init _P((void)); +void if_output _P((struct SLIRPsocket *, struct SLIRPmbuf *)); + +/* ip_input.c */ +void ip_init _P((void)); +void ip_input _P((struct SLIRPmbuf *)); +struct ip * ip_reass _P((register struct ipasfrag *, register struct ipq *)); +void ip_freef _P((struct ipq *)); +void ip_enq _P((register struct ipasfrag *, register struct ipasfrag *)); +void ip_deq _P((register struct ipasfrag *)); +void ip_slowtimo _P((void)); +void ip_stripoptions _P((register struct SLIRPmbuf *, struct SLIRPmbuf *)); + +/* ip_output.c */ +int ip_output _P((struct SLIRPsocket *, struct SLIRPmbuf *)); + +/* tcp_input.c */ +int tcp_reass _P((register struct tcpcb *, register struct tcpiphdr *, struct SLIRPmbuf *)); +void tcp_input _P((register struct SLIRPmbuf *, int, struct SLIRPsocket *)); +void tcp_dooptions _P((struct tcpcb *, u_char *, int, struct tcpiphdr *)); +void tcp_xmit_timer _P((register struct tcpcb *, int)); +int tcp_mss _P((register struct tcpcb *, u_int)); + +/* tcp_output.c */ +int tcp_output _P((register struct tcpcb *)); +void tcp_setpersist _P((register struct tcpcb *)); + +/* tcp_subr.c */ +void tcp_init _P((void)); +void tcp_template _P((struct tcpcb *)); +void tcp_respond _P((struct tcpcb *, register struct tcpiphdr *, register struct SLIRPmbuf *, tcp_seq, tcp_seq, int)); +struct tcpcb * tcp_newtcpcb _P((struct SLIRPsocket *)); +struct tcpcb * tcp_close _P((register struct tcpcb *)); +void tcp_drain _P((void)); +void tcp_sockclosed _P((struct tcpcb *)); +int tcp_fconnect _P((struct SLIRPsocket *)); +void tcp_connect _P((struct SLIRPsocket *)); +int tcp_attach _P((struct SLIRPsocket *)); +u_int8_t tcp_tos _P((struct SLIRPsocket *)); +int tcp_emu _P((struct SLIRPsocket *, struct SLIRPmbuf *)); +int tcp_ctl _P((struct SLIRPsocket *)); +struct tcpcb *tcp_drop(struct tcpcb *tp, int err); + + +#if defined(_MSC_VER) +#pragma pack(pop) +#endif + +#ifdef USE_PPP +#define MIN_MRU MINMRU +#define MAX_MRU MAXMRU +#else +#define MIN_MRU 128 +#define MAX_MRU 16384 +#endif + +#ifndef _WIN32 +#define min(x,y) ((x) < (y) ? (x) : (y)) +#define max(x,y) ((x) > (y) ? (x) : (y)) +#endif + +#ifdef _WIN32 +#undef errno +#define errno (WSAGetLastError()) +#endif + +#define PROBE_CONN + +#endif diff --git a/src/slirp/slirp_config.h b/src/slirp/slirp_config.h new file mode 100644 index 000000000..e583dcc80 --- /dev/null +++ b/src/slirp/slirp_config.h @@ -0,0 +1,135 @@ +/* + * User definable configuration options + */ + +/* Undefine if you don't want talk emulation */ +#undef EMULATE_TALK + +/* Define if you want the connection to be probed */ +/* XXX Not working yet, so ignore this for now */ +#undef PROBE_CONN + +/* Define to 1 if you want KEEPALIVE timers */ +#define DO_KEEPALIVE 0 + +/* Define to MAX interfaces you expect to use at once */ +/* MAX_INTERFACES determines the max. TOTAL number of interfaces (SLIP and PPP) */ +/* MAX_PPP_INTERFACES determines max. number of PPP interfaces */ +#define MAX_INTERFACES 1 +#define MAX_PPP_INTERFACES 1 + +/* Define if you want slirp's socket in /tmp */ +/* XXXXXX Do this in ./configure */ +#undef USE_TMPSOCKET + +/* Define if you want slirp to use cfsetXspeed() on the terminal */ +#undef DO_CFSETSPEED + +/* Define this if you want slirp to write to the tty as fast as it can */ +/* This should only be set if you are using load-balancing, slirp does a */ +/* pretty good job on single modems already, and seting this will make */ +/* interactive sessions less responsive */ +/* XXXXX Talk about having fast modem as unit 0 */ +#undef FULL_BOLT + +/* + * Define if you want slirp to use less CPU + * You will notice a small lag in interactive sessions, but it's not that bad + * Things like Netscape/ftp/etc. are completely unaffected + * This is mainly for sysadmins who have many slirp users + */ +#undef USE_LOWCPU + +/* Define this if your compiler doesn't like prototypes */ +#ifndef __STDC__ +#define NO_PROTOTYPES +#endif + +/*********************************************************/ +/* + * Autoconf defined configuration options + * You shouldn't need to touch any of these + */ + +/* Ignore this */ +#undef DUMMY_PPP + +/* XXX: Define according to how time.h should be included */ +#undef TIME_WITH_SYS_TIME +#define TIME_WITH_SYS_TIME 0 +#undef HAVE_SYS_TIME_H + +/* Define if your sprintf returns char * instead of int */ +#undef BAD_SPRINTF + +/* Define if you have readv */ +#undef HAVE_READV + +/* Define if iovec needs to be declared */ +#undef DECLARE_IOVEC +#ifdef _WIN32 +#define DECLARE_IOVEC +#endif + +/* Define if a declaration of sprintf/fprintf is needed */ +#undef DECLARE_SPRINTF + +/* Define if you have sys/stropts.h */ +#undef HAVE_SYS_STROPTS_H + +/* Define if your compiler doesn't like prototypes */ +#undef NO_PROTOTYPES + +/* Define if you don't have u_int32_t etc. typedef'd */ +#undef NEED_TYPEDEFS +#ifdef __sun__ +#define NEED_TYPEDEFS +#endif + +/* Define to sizeof(char *) */ +#define SIZEOF_CHAR_P SIZEOF_VOID_P + +/* Define if you have random() */ +#undef HAVE_RANDOM + +/* Define if you have srandom() */ +#undef HAVE_SRANDOM + +/* Define if you have setenv */ +#undef HAVE_SETENV + +/* Define if you have index() */ +#undef HAVE_INDEX + +/* Define if you have bcmp() */ +#undef HAVE_BCMP + +/* Define if you have drand48 */ +#undef HAVE_DRAND48 + +/* Define if you have memmove */ +#define HAVE_MEMMOVE + +/* Define if you have gethostid */ +#undef HAVE_GETHOSTID + +/* Define if you DON'T have unix-domain sockets */ +#undef NO_UNIX_SOCKETS +#ifdef _WIN32 +#define NO_UNIX_SOCKETS +#endif + +/* Define if gettimeofday only takes one argument */ +#undef GETTIMEOFDAY_ONE_ARG + +/* Define if you have revoke() */ +#undef HAVE_REVOKE + +/* Define if you have the sysv method of opening pty's (/dev/ptmx, etc.) */ +#undef HAVE_GRANTPT + +/* Define if you have fchmod */ +#undef HAVE_FCHMOD + +/* Define if you have */ +#undef HAVE_SYS_TYPES32_H diff --git a/src/slirp/socket.c b/src/slirp/socket.c new file mode 100644 index 000000000..5e6fb2dc0 --- /dev/null +++ b/src/slirp/socket.c @@ -0,0 +1,731 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#define WANT_SYS_IOCTL_H +#include +#include "slirp.h" +#include "ip_icmp.h" +#include "main.h" +#ifdef __sun__ +#include +#endif + +#ifndef FIONREAD +#include +#endif + +void +so_init() +{ + /* Nothing yet */ +} + + +struct SLIRPsocket * +solookup(head, laddr, lport, faddr, fport) + struct SLIRPsocket *head; + struct in_addr laddr; + u_int lport; + struct in_addr faddr; + u_int fport; +{ + struct SLIRPsocket *so; + + for (so = head->so_next; so != head; so = so->so_next) { + if (so->so_lport == lport && + so->so_laddr.s_addr == laddr.s_addr && + so->so_faddr.s_addr == faddr.s_addr && + so->so_fport == fport) + break; + } + + if (so == head) + return (struct SLIRPsocket *)NULL; + return so; + +} + +/* + * Create a new socket, initialise the fields + * It is the responsibility of the caller to + * insque() it into the correct linked-list + */ +struct SLIRPsocket * +socreate() +{ + struct SLIRPsocket *so; + + so = (struct SLIRPsocket *)malloc(sizeof(struct SLIRPsocket)); + if(so) { + memset(so, 0, sizeof(struct SLIRPsocket)); + so->so_state = SS_NOFDREF; + so->s = -1; + } + return(so); +} + +/* + * remque and free a socket, clobber cache + */ +void +sofree(so) + struct SLIRPsocket *so; +{ + if (so->so_emu==EMU_RSH && so->extra) { + sofree(so->extra); + so->extra=NULL; + } + if (so == tcp_last_so) + tcp_last_so = &tcb; + else if (so == udp_last_so) + udp_last_so = &udb; + + if(so->so_m!=NULL) + m_free(so->so_m); + + if(so->so_next && so->so_prev) + remque(so); /* crashes if so is not in a queue */ + + free(so); +} + +/* + * Read from so's socket into sb_snd, updating all relevant sbuf fields + * NOTE: This will only be called if it is select()ed for reading, so + * a read() of 0 (or less) means it's disconnected + */ +int +soread(so) + struct SLIRPsocket *so; +{ + int n, nn, lss, total; + struct sbuf *sb = &so->so_snd; + int len = sb->sb_datalen - sb->sb_cc; + struct iovec iov[2]; + int mss; + if(!so->so_tcpcb) + return 0; + + mss = so->so_tcpcb->t_maxseg; + + DEBUG_CALL("soread"); + DEBUG_ARG("so = %lx", (long )so); + + /* + * No need to check if there's enough room to read. + * soread wouldn't have been called if there weren't + */ + + len = sb->sb_datalen - sb->sb_cc; + + iov[0].iov_base = sb->sb_wptr; + if (sb->sb_wptr < sb->sb_rptr) { + iov[0].iov_len = sb->sb_rptr - sb->sb_wptr; + /* Should never succeed, but... */ + if (iov[0].iov_len > len) + iov[0].iov_len = len; + if (iov[0].iov_len > mss) + iov[0].iov_len -= iov[0].iov_len%mss; + n = 1; + } else { + iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_wptr; + /* Should never succeed, but... */ + if (iov[0].iov_len > len) iov[0].iov_len = len; + len -= iov[0].iov_len; + if (len) { + iov[1].iov_base = sb->sb_data; + iov[1].iov_len = sb->sb_rptr - sb->sb_data; + if(iov[1].iov_len > len) + iov[1].iov_len = len; + total = iov[0].iov_len + iov[1].iov_len; + if (total > mss) { + lss = total%mss; + if (iov[1].iov_len > lss) { + iov[1].iov_len -= lss; + n = 2; + } else { + lss -= iov[1].iov_len; + iov[0].iov_len -= lss; + n = 1; + } + } else + n = 2; + } else { + if (iov[0].iov_len > mss) + iov[0].iov_len -= iov[0].iov_len%mss; + n = 1; + } + } + +#ifdef HAVE_READV + nn = readv(so->s, (struct iovec *)iov, n); + DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn)); +#else + nn = recv(so->s, iov[0].iov_base, iov[0].iov_len,0); +#endif + if (nn <= 0) { + if (nn < 0 && (errno == EINTR || errno == EAGAIN)) + return 0; + else { + DEBUG_MISC((dfd, " --- soread() disconnected, nn = %d, errno = %d-%s\n", nn, errno,strerror(errno))); + sofcantrcvmore(so); + tcp_sockclosed(sototcpcb(so)); + return -1; + } + } + +#ifndef HAVE_READV + /* + * If there was no error, try and read the second time round + * We read again if n = 2 (ie, there's another part of the buffer) + * and we read as much as we could in the first read + * We don't test for <= 0 this time, because there legitimately + * might not be any more data (since the socket is non-blocking), + * a close will be detected on next iteration. + * A return of -1 wont (shouldn't) happen, since it didn't happen above + */ + if (n == 2 && nn == iov[0].iov_len) { + int ret; + ret = recv(so->s, iov[1].iov_base, iov[1].iov_len,0); + if (ret > 0) + nn += ret; + } + + DEBUG_MISC((dfd, " ... read nn = %d bytes\n", nn)); +#endif + + /* Update fields */ + sb->sb_cc += nn; + sb->sb_wptr += nn; + if (sb->sb_wptr >= (sb->sb_data + sb->sb_datalen)) + sb->sb_wptr -= sb->sb_datalen; + return nn; +} + +/* + * Get urgent data + * + * When the socket is created, we set it SO_OOBINLINE, + * so when OOB data arrives, we soread() it and everything + * in the send buffer is sent as urgent data + */ +void +sorecvoob(so) + struct SLIRPsocket *so; +{ + struct tcpcb *tp = sototcpcb(so); + + DEBUG_CALL("sorecvoob"); + DEBUG_ARG("so = %lx", (long)so); + + /* + * We take a guess at how much urgent data has arrived. + * In most situations, when urgent data arrives, the next + * read() should get all the urgent data. This guess will + * be wrong however if more data arrives just after the + * urgent data, or the read() doesn't return all the + * urgent data. + */ + soread(so); + tp->snd_up = tp->snd_una + so->so_snd.sb_cc; + tp->t_force = 1; + tcp_output(tp); + tp->t_force = 0; +} + +/* + * Send urgent data + * There's a lot duplicated code here, but... + */ +int +sosendoob(so) + struct SLIRPsocket *so; +{ + struct sbuf *sb = &so->so_rcv; + char buff[2048]; /* XXX Shouldn't be sending more oob data than this */ + + int n, len; + + DEBUG_CALL("sosendoob"); + DEBUG_ARG("so = %lx", (long)so); + DEBUG_ARG("sb->sb_cc = %d", sb->sb_cc); + + if (so->so_urgc > 2048) + so->so_urgc = 2048; /* XXXX */ + + if (sb->sb_rptr < sb->sb_wptr) { + /* We can send it directly */ + n = send(so->s, sb->sb_rptr, so->so_urgc, (MSG_OOB)); /* |MSG_DONTWAIT)); */ + so->so_urgc -= n; + + DEBUG_MISC((dfd, " --- sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc)); + } else { + /* + * Since there's no sendv or sendtov like writev, + * we must copy all data to a linear buffer then + * send it all + */ + len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr; + if (len > so->so_urgc) len = so->so_urgc; + memcpy(buff, sb->sb_rptr, len); + so->so_urgc -= len; + if (so->so_urgc) { + n = sb->sb_wptr - sb->sb_data; + if (n > so->so_urgc) n = so->so_urgc; + memcpy((buff + len), sb->sb_data, n); + so->so_urgc -= n; + len += n; + } + n = send(so->s, buff, len, (MSG_OOB)); /* |MSG_DONTWAIT)); */ +#ifdef SLIRP_DEBUG + if (n != len) + DEBUG_ERROR((dfd, "Didn't send all data urgently XXXXX\n")); +#endif + DEBUG_MISC((dfd, " ---2 sent %d bytes urgent data, %d urgent bytes left\n", n, so->so_urgc)); + } + + sb->sb_cc -= n; + sb->sb_rptr += n; + if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen)) + sb->sb_rptr -= sb->sb_datalen; + + return n; +} + +/* + * Write data from so_rcv to so's socket, + * updating all sbuf field as necessary + */ +int +sowrite(so) + struct SLIRPsocket *so; +{ + int n,nn; + struct sbuf *sb = &so->so_rcv; + int len = sb->sb_cc; + struct iovec iov[2]; + + DEBUG_CALL("sowrite"); + DEBUG_ARG("so = %lx", (long)so); + + if (so->so_urgc) { + sosendoob(so); + if (sb->sb_cc == 0) + return 0; + } + + /* + * No need to check if there's something to write, + * sowrite wouldn't have been called otherwise + */ + + len = sb->sb_cc; + + iov[0].iov_base = sb->sb_rptr; + if (sb->sb_rptr < sb->sb_wptr) { + iov[0].iov_len = sb->sb_wptr - sb->sb_rptr; + /* Should never succeed, but... */ + if (iov[0].iov_len > len) iov[0].iov_len = len; + n = 1; + } else { + iov[0].iov_len = (sb->sb_data + sb->sb_datalen) - sb->sb_rptr; + if (iov[0].iov_len > len) iov[0].iov_len = len; + len -= iov[0].iov_len; + if (len) { + iov[1].iov_base = sb->sb_data; + iov[1].iov_len = sb->sb_wptr - sb->sb_data; + if (iov[1].iov_len > len) iov[1].iov_len = len; + n = 2; + } else + n = 1; + } + /* Check if there's urgent data to send, and if so, send it */ + +#ifdef HAVE_READV + nn = writev(so->s, (const struct iovec *)iov, n); + + DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn)); +#else + nn = send(so->s, iov[0].iov_base, iov[0].iov_len,0); +#endif + /* This should never happen, but people tell me it does *shrug* */ + if (nn < 0 && (errno == EAGAIN || errno == EINTR)) + return 0; + + if (nn <= 0) { + DEBUG_MISC((dfd, " --- sowrite disconnected, so->so_state = %x, errno = %d\n", + so->so_state, errno)); + sofcantsendmore(so); + tcp_sockclosed(sototcpcb(so)); + return -1; + } + +#ifndef HAVE_READV + if (n == 2 && nn == iov[0].iov_len) { + int ret; + ret = send(so->s, iov[1].iov_base, iov[1].iov_len,0); + if (ret > 0) + nn += ret; + } + DEBUG_MISC((dfd, " ... wrote nn = %d bytes\n", nn)); +#endif + + /* Update sbuf */ + sb->sb_cc -= nn; + sb->sb_rptr += nn; + if (sb->sb_rptr >= (sb->sb_data + sb->sb_datalen)) + sb->sb_rptr -= sb->sb_datalen; + + /* + * If in DRAIN mode, and there's no more data, set + * it CANTSENDMORE + */ + if ((so->so_state & SS_FWDRAIN) && sb->sb_cc == 0) + sofcantsendmore(so); + + return nn; +} + +/* + * recvfrom() a UDP socket + */ +void +sorecvfrom(so) + struct SLIRPsocket *so; +{ + struct sockaddr_in addr; + socklen_t addrlen = sizeof(struct sockaddr_in); + + DEBUG_CALL("sorecvfrom"); + DEBUG_ARG("so = %lx", (long)so); + + if (so->so_type == IPPROTO_ICMP) { /* This is a "ping" reply */ + char buff[256]; + int len; + + len = recvfrom(so->s, buff, 256, 0, + (struct sockaddr *)&addr, &addrlen); + /* XXX Check if reply is "correct"? */ + + if(len == -1 || len == 0) { + u_char code=ICMP_UNREACH_PORT; + + if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST; + else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET; + + DEBUG_MISC((dfd," udp icmp rx errno = %d-%s\n", + errno,strerror(errno))); + icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno)); + } else { + icmp_reflect(so->so_m); + so->so_m = 0; /* Don't m_free() it again! */ + } + /* No need for this socket anymore, udp_detach it */ + udp_detach(so); + } else { /* A "normal" UDP packet */ + struct SLIRPmbuf *m; + int len; + ioctlsockopt_t n; + + if (!(m = m_get())) return; + m->m_data += if_maxlinkhdr; + + /* + * XXX Shouldn't FIONREAD packets destined for port 53, + * but I don't know the max packet size for DNS lookups + */ + len = M_FREEROOM(m); + /* if (so->so_fport != htons(53)) { */ + ioctlsocket(so->s, FIONREAD, &n); + + if (n > len) { + n = (m->m_data - m->m_dat) + m->m_len + n + 1; + m_inc(m, n); + len = M_FREEROOM(m); + } + /* } */ + + m->m_len = recvfrom(so->s, m->m_data, len, 0, + (struct sockaddr *)&addr, &addrlen); + DEBUG_MISC((dfd, " did recvfrom %d, errno = %d-%s\n", + m->m_len, errno,strerror(errno))); + if(m->m_len<0) { + u_char code=ICMP_UNREACH_PORT; + + if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST; + else if(errno == ENETUNREACH) code=ICMP_UNREACH_NET; + + DEBUG_MISC((dfd," rx error, tx icmp ICMP_UNREACH:%i\n", code)); + icmp_error(so->so_m, ICMP_UNREACH,code, 0,strerror(errno)); + m_free(m); + } else { + /* + * Hack: domain name lookup will be used the most for UDP, + * and since they'll only be used once there's no need + * for the 4 minute (or whatever) timeout... So we time them + * out much quicker (10 seconds for now...) + */ + if (so->so_expire) { + if (so->so_fport == htons(53)) + so->so_expire = curtime + SO_EXPIREFAST; + else + so->so_expire = curtime + SO_EXPIRE; + } + + /* if (m->m_len == len) { + * m_inc(m, MINCSIZE); + * m->m_len = 0; + * } + */ + + /* + * If this packet was destined for CTL_ADDR, + * make it look like that's where it came from, done by udp_output + */ + udp_output(so, m, &addr); + } /* rx error */ + } /* if ping packet */ +} + +/* + * sendto() a socket + */ +int +sosendto(so, m) + struct SLIRPsocket *so; + struct SLIRPmbuf *m; +{ + int ret; + struct sockaddr_in addr; + + DEBUG_CALL("sosendto"); + DEBUG_ARG("so = %lx", (long)so); + DEBUG_ARG("m = %lx", (long)m); + + addr.sin_family = AF_INET; + if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { + /* It's an alias */ + switch(ntohl(so->so_faddr.s_addr) & 0xff) { + case CTL_DNS: + addr.sin_addr = dns_addr; + break; + case CTL_ALIAS: + default: + addr.sin_addr = loopback_addr; + break; + } + } else + addr.sin_addr = so->so_faddr; + addr.sin_port = so->so_fport; + + DEBUG_MISC((dfd, " sendto()ing, addr.sin_port=%d, addr.sin_addr.s_addr=%.16s\n", ntohs(addr.sin_port), inet_ntoa(addr.sin_addr))); + + /* Don't care what port we get */ + ret = sendto(so->s, m->m_data, m->m_len, 0, + (struct sockaddr *)&addr, sizeof (struct sockaddr)); + if (ret < 0) + return -1; + + /* + * Kill the socket if there's no reply in 4 minutes, + * but only if it's an expirable socket + */ + if (so->so_expire) + so->so_expire = curtime + SO_EXPIRE; + so->so_state = SS_ISFCONNECTED; /* So that it gets select()ed */ + return 0; +} + +/* + * XXX This should really be tcp_listen + */ +struct SLIRPsocket * +solisten(port, laddr, lport, flags) + u_int port; + u_int32_t laddr; + u_int lport; + int flags; +{ + struct sockaddr_in addr; + struct SLIRPsocket *so; + int s; + socklen_t addrlen = sizeof(addr); + int opt = 1; + + DEBUG_CALL("solisten"); + DEBUG_ARG("port = %d", port); + DEBUG_ARG("laddr = %x", laddr); + DEBUG_ARG("lport = %d", lport); + DEBUG_ARG("flags = %x", flags); + + if ((so = socreate()) == NULL) { + /* free(so); Not sofree() ??? free(NULL) == NOP */ + return NULL; + } + + /* Don't tcp_attach... we don't need so_snd nor so_rcv */ + if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) { + free(so); + return NULL; + } + insque(so,&tcb); + + /* + * SS_FACCEPTONCE sockets must time out. + */ + if (flags & SS_FACCEPTONCE) + so->so_tcpcb->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT*2; + + so->so_state = (SS_FACCEPTCONN|flags); + so->so_lport = lport; /* Kept in network format */ + so->so_laddr.s_addr = laddr; /* Ditto */ + + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = port; + + if (((s = socket(AF_INET,SOCK_STREAM,0)) < 0) || + (setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)) < 0) || + (bind(s,(struct sockaddr *)&addr, sizeof(addr)) < 0) || + (listen(s,1) < 0)) { + int tmperrno = errno; /* Don't clobber the real reason we failed */ + + close(s); + sofree(so); + /* Restore the real errno */ +#ifdef _WIN32 + WSASetLastError(tmperrno); +#else + errno = tmperrno; +#endif + return NULL; + } + setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); + + getsockname(s,(struct sockaddr *)&addr,&addrlen); + so->so_fport = addr.sin_port; + if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr) + so->so_faddr = alias_addr; + else + so->so_faddr = addr.sin_addr; + + so->s = s; + return so; +} + +/* + * Data is available in so_rcv + * Just write() the data to the socket + * XXX not yet... + */ +void +sorwakeup(so) + struct SLIRPsocket *so; +{ +/* sowrite(so); */ +/* FD_CLR(so->s,&writefds); */ +} + +/* + * Data has been freed in so_snd + * We have room for a read() if we want to + * For now, don't read, it'll be done in the main loop + */ +void +sowwakeup(so) + struct SLIRPsocket *so; +{ + /* Nothing, yet */ +} + +/* + * Various session state calls + * XXX Should be #define's + * The socket state stuff needs work, these often get call 2 or 3 + * times each when only 1 was needed + */ +void +soisfconnecting(so) + register struct SLIRPsocket *so; +{ + so->so_state &= ~(SS_NOFDREF|SS_ISFCONNECTED|SS_FCANTRCVMORE| + SS_FCANTSENDMORE|SS_FWDRAIN); + so->so_state |= SS_ISFCONNECTING; /* Clobber other states */ +} + +void +soisfconnected(so) + register struct SLIRPsocket *so; +{ + so->so_state &= ~(SS_ISFCONNECTING|SS_FWDRAIN|SS_NOFDREF); + so->so_state |= SS_ISFCONNECTED; /* Clobber other states */ +} + +void +sofcantrcvmore(so) + struct SLIRPsocket *so; +{ + if ((so->so_state & SS_NOFDREF) == 0) { + shutdown(so->s,0); + if(global_writefds) { + FD_CLR(so->s,global_writefds); + } + } + so->so_state &= ~(SS_ISFCONNECTING); + if (so->so_state & SS_FCANTSENDMORE) + so->so_state = SS_NOFDREF; /* Don't select it */ /* XXX close() here as well? */ + else + so->so_state |= SS_FCANTRCVMORE; +} + +void +sofcantsendmore(so) + struct SLIRPsocket *so; +{ + if ((so->so_state & SS_NOFDREF) == 0) { + shutdown(so->s,1); /* send FIN to fhost */ + if (global_readfds) { + FD_CLR(so->s,global_readfds); + } + if (global_xfds) { + FD_CLR(so->s,global_xfds); + } + } + so->so_state &= ~(SS_ISFCONNECTING); + if (so->so_state & SS_FCANTRCVMORE) + so->so_state = SS_NOFDREF; /* as above */ + else + so->so_state |= SS_FCANTSENDMORE; +} + +void +soisfdisconnected(so) + struct SLIRPsocket *so; +{ +/* so->so_state &= ~(SS_ISFCONNECTING|SS_ISFCONNECTED); */ +/* close(so->s); */ +/* so->so_state = SS_ISFDISCONNECTED; */ + /* + * XXX Do nothing ... ? + */ +} + +/* + * Set write drain mode + * Set CANTSENDMORE once all data has been write()n + */ +void +sofwdrain(so) + struct SLIRPsocket *so; +{ + if (so->so_rcv.sb_cc) + so->so_state |= SS_FWDRAIN; + else + sofcantsendmore(so); +} + diff --git a/src/slirp/socket.h b/src/slirp/socket.h new file mode 100644 index 000000000..3a777934a --- /dev/null +++ b/src/slirp/socket.h @@ -0,0 +1,104 @@ +/* + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +/* MINE */ + +#ifndef _SLIRP_SOCKET_H_ +#define _SLIRP_SOCKET_H_ + +#define SO_EXPIRE 240000 +#define SO_EXPIREFAST 10000 + +/* + * Our socket structure + */ + +struct SLIRPsocket { + struct SLIRPsocket *so_next,*so_prev; /* For a linked list of sockets */ + + int s; /* The actual socket */ + + /* XXX union these with not-yet-used sbuf params */ + struct SLIRPmbuf *so_m; /* Pointer to the original SYN packet, + * for non-blocking connect()'s, and + * PING reply's */ + struct tcpiphdr *so_ti; /* Pointer to the original ti within + * so_mconn, for non-blocking connections */ + int so_urgc; + struct in_addr so_faddr; /* foreign host table entry */ + struct in_addr so_laddr; /* local host table entry */ + u_int16_t so_fport; /* foreign port */ + u_int16_t so_lport; /* local port */ + + u_int8_t so_iptos; /* Type of service */ + u_int8_t so_emu; /* Is the socket emulated? */ + + u_char so_type; /* Type of socket, UDP or TCP */ + int so_state; /* internal state flags SS_*, below */ + + struct tcpcb *so_tcpcb; /* pointer to TCP protocol control block */ + u_int so_expire; /* When the socket will expire */ + + int so_queued; /* Number of packets queued from this socket */ + int so_nqueued; /* Number of packets queued in a row + * Used to determine when to "downgrade" a session + * from fastq to batchq */ + + struct sbuf so_rcv; /* Receive buffer */ + struct sbuf so_snd; /* Send buffer */ + void * extra; /* Extra pointer */ +}; + + +/* + * Socket state bits. (peer means the host on the Internet, + * local host means the host on the other end of the modem) + */ +#define SS_NOFDREF 0x001 /* No fd reference */ + +#define SS_ISFCONNECTING 0x002 /* Socket is connecting to peer (non-blocking connect()'s) */ +#define SS_ISFCONNECTED 0x004 /* Socket is connected to peer */ +#define SS_FCANTRCVMORE 0x008 /* Socket can't receive more from peer (for half-closes) */ +#define SS_FCANTSENDMORE 0x010 /* Socket can't send more to peer (for half-closes) */ +/* #define SS_ISFDISCONNECTED 0x020*/ /* Socket has disconnected from peer, in 2MSL state */ +#define SS_FWDRAIN 0x040 /* We received a FIN, drain data and set SS_FCANTSENDMORE */ + +#define SS_CTL 0x080 +#define SS_FACCEPTCONN 0x100 /* Socket is accepting connections from a host on the internet */ +#define SS_FACCEPTONCE 0x200 /* If set, the SS_FACCEPTCONN socket will die after one accept */ + +extern struct SLIRPsocket tcb; + + +#if defined(DECLARE_IOVEC) && !defined(HAVE_READV) +struct iovec { + char *iov_base; + size_t iov_len; +}; +#endif + +void so_init _P((void)); +struct SLIRPsocket * solookup _P((struct SLIRPsocket *, struct in_addr, u_int, struct in_addr, u_int)); +struct SLIRPsocket * socreate _P((void)); +void sofree _P((struct SLIRPsocket *)); +int soread _P((struct SLIRPsocket *)); +void sorecvoob _P((struct SLIRPsocket *)); +int sosendoob _P((struct SLIRPsocket *)); +int sowrite _P((struct SLIRPsocket *)); +void sorecvfrom _P((struct SLIRPsocket *)); +int sosendto _P((struct SLIRPsocket *, struct SLIRPmbuf *)); +struct SLIRPsocket * solisten _P((u_int, u_int32_t, u_int, int)); +void sorwakeup _P((struct SLIRPsocket *)); +void sowwakeup _P((struct SLIRPsocket *)); +void soisfconnecting _P((register struct SLIRPsocket *)); +void soisfconnected _P((register struct SLIRPsocket *)); +void sofcantrcvmore _P((struct SLIRPsocket *)); +void sofcantsendmore _P((struct SLIRPsocket *)); +void soisfdisconnected _P((struct SLIRPsocket *)); +void sofwdrain _P((struct SLIRPsocket *)); + +#endif /* _SOCKET_H_ */ diff --git a/src/slirp/tcp.h b/src/slirp/tcp.h new file mode 100644 index 000000000..38c41bbf2 --- /dev/null +++ b/src/slirp/tcp.h @@ -0,0 +1,181 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tcp.h 8.1 (Berkeley) 6/10/93 + * tcp.h,v 1.3 1994/08/21 05:27:34 paul Exp + */ + +#ifndef _TCP_H_ +#define _TCP_H_ + +typedef u_int32_t tcp_seq; + +#define PR_SLOWHZ 2 /* 2 slow timeouts per second (approx) */ +#define PR_FASTHZ 5 /* 5 fast timeouts per second (not important) */ + +extern int tcp_rcvspace; +extern int tcp_sndspace; +extern struct SLIRPsocket *tcp_last_so; + +#define TCP_SNDSPACE 8192 +#define TCP_RCVSPACE 8192 + +/* + * TCP header. + * Per RFC 793, September, 1981. + */ +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(1) +#endif + +struct tcphdr { + u_int16_t th_sport; /* source port */ + u_int16_t th_dport; /* destination port */ + tcp_seq th_seq; /* sequence number */ + tcp_seq th_ack; /* acknowledgement number */ +#ifdef WORDS_BIGENDIAN + u_char th_off:4, /* data offset */ + th_x2:4; /* (unused) */ +#else + u_char th_x2:4, /* (unused) */ + th_off:4; /* data offset */ +#endif + u_int8_t th_flags; +#define TH_FIN 0x01 +#define TH_SYN 0x02 +#define TH_RST 0x04 +#define TH_PUSH 0x08 +#define TH_ACK 0x10 +#define TH_URG 0x20 + u_int16_t th_win; /* window */ + u_int16_t th_sum; /* checksum */ + u_int16_t th_urp; /* urgent pointer */ +} PACKED__; + +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(PACK_END) +#endif + +#include "tcp_var.h" + +#define TCPOPT_EOL 0 +#define TCPOPT_NOP 1 +#define TCPOPT_MAXSEG 2 +#define TCPOLEN_MAXSEG 4 +#define TCPOPT_WINDOW 3 +#define TCPOLEN_WINDOW 3 +#define TCPOPT_SACK_PERMITTED 4 /* Experimental */ +#define TCPOLEN_SACK_PERMITTED 2 +#define TCPOPT_SACK 5 /* Experimental */ +#define TCPOPT_TIMESTAMP 8 +#define TCPOLEN_TIMESTAMP 10 +#define TCPOLEN_TSTAMP_APPA (TCPOLEN_TIMESTAMP+2) /* appendix A */ + +#define TCPOPT_TSTAMP_HDR \ + (TCPOPT_NOP<<24|TCPOPT_NOP<<16|TCPOPT_TIMESTAMP<<8|TCPOLEN_TIMESTAMP) + +/* + * Default maximum segment size for TCP. + * With an IP MSS of 576, this is 536, + * but 512 is probably more convenient. + * This should be defined as MIN(512, IP_MSS - sizeof (struct tcpiphdr)). + * + * We make this 1460 because we only care about Ethernet in the qemu context. + */ +#define TCP_MSS 1460 + +#define TCP_MAXWIN 65535 /* largest value for (unscaled) window */ + +#define TCP_MAX_WINSHIFT 14 /* maximum window shift */ + +/* + * User-settable options (used with setsockopt). + * + * We don't use the system headers on unix because we have conflicting + * local structures. We can't avoid the system definitions on Windows, + * so we undefine them. + */ +#undef TCP_NODELAY +#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */ +#undef TCP_MAXSEG +/* #define TCP_MAXSEG 0x02 */ /* set maximum segment size */ + +/* + * TCP FSM state definitions. + * Per RFC793, September, 1981. + */ + +#define TCP_NSTATES 11 + +#define TCPS_CLOSED 0 /* closed */ +#define TCPS_LISTEN 1 /* listening for connection */ +#define TCPS_SYN_SENT 2 /* active, have sent syn */ +#define TCPS_SYN_RECEIVED 3 /* have send and received syn */ +/* states < TCPS_ESTABLISHED are those where connections not established */ +#define TCPS_ESTABLISHED 4 /* established */ +#define TCPS_CLOSE_WAIT 5 /* rcvd fin, waiting for close */ +/* states > TCPS_CLOSE_WAIT are those where user has closed */ +#define TCPS_FIN_WAIT_1 6 /* have closed, sent fin */ +#define TCPS_CLOSING 7 /* closed xchd FIN; await FIN ACK */ +#define TCPS_LAST_ACK 8 /* had fin and close; await FIN ACK */ +/* states > TCPS_CLOSE_WAIT && < TCPS_FIN_WAIT_2 await ACK of FIN */ +#define TCPS_FIN_WAIT_2 9 /* have closed, fin is acked */ +#define TCPS_TIME_WAIT 10 /* in 2*msl quiet wait after close */ + +#define TCPS_HAVERCVDSYN(s) ((s) >= TCPS_SYN_RECEIVED) +#define TCPS_HAVEESTABLISHED(s) ((s) >= TCPS_ESTABLISHED) +#define TCPS_HAVERCVDFIN(s) ((s) >= TCPS_TIME_WAIT) + +/* + * TCP sequence numbers are 32 bit integers operated + * on with modular arithmetic. These macros can be + * used to compare such integers. + */ +#define SEQ_LT(a,b) ((int)((a)-(b)) < 0) +#define SEQ_LEQ(a,b) ((int)((a)-(b)) <= 0) +#define SEQ_GT(a,b) ((int)((a)-(b)) > 0) +#define SEQ_GEQ(a,b) ((int)((a)-(b)) >= 0) + +/* + * Macros to initialize tcp sequence numbers for + * send and receive from initial send and receive + * sequence numbers. + */ +#define tcp_rcvseqinit(tp) \ + (tp)->rcv_adv = (tp)->rcv_nxt = (tp)->irs + 1 + +#define tcp_sendseqinit(tp) \ + (tp)->snd_una = (tp)->snd_nxt = (tp)->snd_max = (tp)->snd_up = (tp)->iss + +#define TCP_ISSINCR (125*1024) /* increment for tcp_iss each second */ + +extern tcp_seq tcp_iss; /* tcp initial send seq # */ + +extern char *tcpstates[]; + +#endif diff --git a/src/slirp/tcp_input.c b/src/slirp/tcp_input.c new file mode 100644 index 000000000..77006a2d7 --- /dev/null +++ b/src/slirp/tcp_input.c @@ -0,0 +1,1722 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tcp_input.c 8.5 (Berkeley) 4/10/94 + * tcp_input.c,v 1.10 1994/10/13 18:36:32 wollman Exp + */ + +/* + * Changes and additions relating to SLiRP + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#include +#include "slirp.h" +#include "ip_icmp.h" + +struct SLIRPsocket tcb; + +int tcprexmtthresh = 3; +struct SLIRPsocket *tcp_last_so = &tcb; + +tcp_seq tcp_iss; /* tcp initial send seq # */ + +#define TCP_PAWS_IDLE (24 * 24 * 60 * 60 * PR_SLOWHZ) + +/* for modulo comparisons of timestamps */ +#define TSTMP_LT(a,b) ((int)((a)-(b)) < 0) +#define TSTMP_GEQ(a,b) ((int)((a)-(b)) >= 0) + +/* + * Insert segment ti into reassembly queue of tcp with + * control block tp. Return TH_FIN if reassembly now includes + * a segment with FIN. The macro form does the common case inline + * (segment is the next to be received on an established connection, + * and the queue is empty), avoiding linkage into and removal + * from the queue and repetition of various conversions. + * Set DELACK for segments received in order, but ack immediately + * when segments are out of order (so fast retransmit can work). + */ +#ifdef TCP_ACK_HACK +#define TCP_REASS(tp, ti, m, so, flags) {\ + if ((ti)->ti_seq == (tp)->rcv_nxt && \ + (tp)->seg_next == (tcpiphdrp_32)(tp) && \ + (tp)->t_state == TCPS_ESTABLISHED) {\ + if (ti->ti_flags & TH_PUSH) \ + tp->t_flags |= TF_ACKNOW; \ + else \ + tp->t_flags |= TF_DELACK; \ + (tp)->rcv_nxt += (ti)->ti_len; \ + flags = (ti)->ti_flags & TH_FIN; \ + tcpstat.tcps_rcvpack++;\ + tcpstat.tcps_rcvbyte += (ti)->ti_len;\ + if (so->so_emu) { \ + if (tcp_emu((so),(m))) sbappend((so), (m)); \ + } else \ + sbappend((so), (m)); \ +/* sorwakeup(so); */ \ + } else {\ + (flags) = tcp_reass((tp), (ti), (m)); \ + tp->t_flags |= TF_ACKNOW; \ + } \ +} +#else +#define TCP_REASS(tp, ti, m, so, flags) { \ + if ((ti)->ti_seq == (tp)->rcv_nxt && \ + (tp)->seg_next == (tcpiphdrp_32)(tp) && \ + (tp)->t_state == TCPS_ESTABLISHED) { \ + tp->t_flags |= TF_DELACK; \ + (tp)->rcv_nxt += (ti)->ti_len; \ + flags = (ti)->ti_flags & TH_FIN; \ + tcpstat.tcps_rcvpack++;\ + tcpstat.tcps_rcvbyte += (ti)->ti_len;\ + if (so->so_emu) { \ + if (tcp_emu((so),(m))) sbappend(so, (m)); \ + } else \ + sbappend((so), (m)); \ +/* sorwakeup(so); */ \ + } else { \ + (flags) = tcp_reass((tp), (ti), (m)); \ + tp->t_flags |= TF_ACKNOW; \ + } \ +} +#endif + +int +tcp_reass(tp, ti, m) + struct tcpcb *tp; + struct tcpiphdr *ti; + struct SLIRPmbuf *m; +{ + struct tcpiphdr *q; + struct SLIRPsocket *so = tp->t_socket; + int flags; + + /* + * Call with ti==0 after become established to + * force pre-ESTABLISHED data up to user socket. + */ + if (ti == 0) + goto present; + + /* + * Find a segment which begins after this one does. + */ + for (q = (struct tcpiphdr *)tp->seg_next; q != (struct tcpiphdr *)tp; + q = (struct tcpiphdr *)q->ti_next) + if (SEQ_GT(q->ti_seq, ti->ti_seq)) + break; + + /* + * If there is a preceding segment, it may provide some of + * our data already. If so, drop the data from the incoming + * segment. If it provides all of our data, drop us. + */ + if ((struct tcpiphdr *)q->ti_prev != (struct tcpiphdr *)tp) { + int i; + q = (struct tcpiphdr *)q->ti_prev; + /* conversion to int (in i) handles seq wraparound */ + i = q->ti_seq + q->ti_len - ti->ti_seq; + if (i > 0) { + if (i >= ti->ti_len) { + tcpstat.tcps_rcvduppack++; + tcpstat.tcps_rcvdupbyte += ti->ti_len; + m_freem(m); + /* + * Try to present any queued data + * at the left window edge to the user. + * This is needed after the 3-WHS + * completes. + */ + goto present; /* ??? */ + } + m_adj(m, i); + ti->ti_len -= i; + ti->ti_seq += i; + } + q = (struct tcpiphdr *)(q->ti_next); + } + tcpstat.tcps_rcvoopack++; + tcpstat.tcps_rcvoobyte += ti->ti_len; + REASS_MBUF(ti) = (mbufp_32) m; /* XXX */ + + /* + * While we overlap succeeding segments trim them or, + * if they are completely covered, dequeue them. + */ + while (q != (struct tcpiphdr *)tp) { + int i = (ti->ti_seq + ti->ti_len) - q->ti_seq; + if (i <= 0) + break; + if (i < q->ti_len) { + q->ti_seq += i; + q->ti_len -= i; + m_adj((struct SLIRPmbuf *) REASS_MBUF(q), i); + break; + } + q = (struct tcpiphdr *)q->ti_next; + m = (struct SLIRPmbuf *) REASS_MBUF((struct tcpiphdr *)q->ti_prev); + remque_32((void *)(q->ti_prev)); + m_freem(m); + } + + /* + * Stick new segment in its place. + */ + insque_32(ti, (void *)(q->ti_prev)); + +present: + /* + * Present data to user, advancing rcv_nxt through + * completed sequence space. + */ + if (!TCPS_HAVEESTABLISHED(tp->t_state)) + return (0); + ti = (struct tcpiphdr *) tp->seg_next; + if (ti == (struct tcpiphdr *)tp || ti->ti_seq != tp->rcv_nxt) + return (0); + if (tp->t_state == TCPS_SYN_RECEIVED && ti->ti_len) + return (0); + do { + tp->rcv_nxt += ti->ti_len; + flags = ti->ti_flags & TH_FIN; + remque_32(ti); + m = (struct SLIRPmbuf *) REASS_MBUF(ti); /* XXX */ + ti = (struct tcpiphdr *)ti->ti_next; +/* if (so->so_state & SS_FCANTRCVMORE) */ + if (so->so_state & SS_FCANTSENDMORE) + m_freem(m); + else { + if (so->so_emu) { + if (tcp_emu(so,m)) sbappend(so, m); + } else + sbappend(so, m); + } + } while (ti != (struct tcpiphdr *)tp && ti->ti_seq == tp->rcv_nxt); +/* sorwakeup(so); */ + return (flags); +} + +/* + * TCP input routine, follows pages 65-76 of the + * protocol specification dated September, 1981 very closely. + */ +void +tcp_input(m, iphlen, inso) + struct SLIRPmbuf *m; + int iphlen; + struct SLIRPsocket *inso; +{ + struct ip save_ip, *ip; + struct tcpiphdr *ti; + SLIRPcaddr_t optp = NULL; + int optlen = 0; + int len, tlen, off; + struct tcpcb *tp = 0; + int tiflags; + struct SLIRPsocket *so = 0; + int todrop, acked, ourfinisacked, needoutput = 0; +/* int dropsocket = 0; */ + int iss = 0; + u_long tiwin; + int ret; +/* int ts_present = 0; */ + + DEBUG_CALL("tcp_input"); + DEBUG_ARGS((dfd," m = %8lx iphlen = %2d inso = %lx\n", + (long )m, iphlen, (long )inso )); + + /* + * If called with m == 0, then we're continuing the connect + */ + if (m == NULL) { + so = inso; + + /* Re-set a few variables */ + tp = sototcpcb(so); + m = so->so_m; + so->so_m = 0; + ti = so->so_ti; + tiwin = ti->ti_win; + tiflags = ti->ti_flags; + + goto cont_conn; + } + + + tcpstat.tcps_rcvtotal++; + /* + * Get IP and TCP header together in first SLIRPmbuf. + * Note: IP leaves IP header in first SLIRPmbuf. + */ + ti = mtod(m, struct tcpiphdr *); + if (iphlen > sizeof(struct ip )) { + ip_stripoptions(m, (struct SLIRPmbuf *)0); + iphlen=sizeof(struct ip ); + } + /* XXX Check if too short */ + + + /* + * Save a copy of the IP header in case we want restore it + * for sending an ICMP error message in response. + */ + ip=mtod(m, struct ip *); + save_ip = *ip; + save_ip.ip_len+= iphlen; + + /* + * Checksum extended TCP header and data. + */ + tlen = ((struct ip *)ti)->ip_len; + ti->ti_next = ti->ti_prev = 0; + ti->ti_x1 = 0; + ti->ti_len = htons((u_int16_t)tlen); + len = sizeof(struct ip ) + tlen; + /* keep checksum for ICMP reply + * ti->ti_sum = cksum(m, len); + * if (ti->ti_sum) { */ + if(cksum(m, len)) { + tcpstat.tcps_rcvbadsum++; + goto drop; + } + + /* + * Check that TCP offset makes sense, + * pull out TCP options and adjust length. XXX + */ + off = ti->ti_off << 2; + if (off < sizeof (struct tcphdr) || off > tlen) { + tcpstat.tcps_rcvbadoff++; + goto drop; + } + tlen -= off; + ti->ti_len = tlen; + if (off > sizeof (struct tcphdr)) { + optlen = off - sizeof (struct tcphdr); + optp = mtod(m, SLIRPcaddr_t) + sizeof (struct tcpiphdr); + + /* + * Do quick retrieval of timestamp options ("options + * prediction?"). If timestamp is the only option and it's + * formatted as recommended in RFC 1323 appendix A, we + * quickly get the values now and not bother calling + * tcp_dooptions(), etc. + */ +/* if ((optlen == TCPOLEN_TSTAMP_APPA || + * (optlen > TCPOLEN_TSTAMP_APPA && + * optp[TCPOLEN_TSTAMP_APPA] == TCPOPT_EOL)) && + * *(u_int32_t *)optp == htonl(TCPOPT_TSTAMP_HDR) && + * (ti->ti_flags & TH_SYN) == 0) { + * ts_present = 1; + * ts_val = ntohl(*(u_int32_t *)(optp + 4)); + * ts_ecr = ntohl(*(u_int32_t *)(optp + 8)); + * optp = NULL; / * we've parsed the options * / + * } + */ + } + tiflags = ti->ti_flags; + + /* + * Convert TCP protocol specific fields to host format. + */ + NTOHL(ti->ti_seq); + NTOHL(ti->ti_ack); + NTOHS(ti->ti_win); + NTOHS(ti->ti_urp); + + /* + * Drop TCP, IP headers and TCP options. + */ + m->m_data += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); + m->m_len -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); + + /* + * Locate pcb for segment. + */ +findso: + so = tcp_last_so; + if (so->so_fport != ti->ti_dport || + so->so_lport != ti->ti_sport || + so->so_laddr.s_addr != ti->ti_src.s_addr || + so->so_faddr.s_addr != ti->ti_dst.s_addr) { + so = solookup(&tcb, ti->ti_src, ti->ti_sport, + ti->ti_dst, ti->ti_dport); + if (so) + tcp_last_so = so; + ++tcpstat.tcps_socachemiss; + } + + /* + * If the state is CLOSED (i.e., TCB does not exist) then + * all data in the incoming segment is discarded. + * If the TCB exists but is in CLOSED state, it is embryonic, + * but should either do a listen or a connect soon. + * + * state == CLOSED means we've done socreate() but haven't + * attached it to a protocol yet... + * + * XXX If a TCB does not exist, and the TH_SYN flag is + * the only flag set, then create a session, mark it + * as if it was LISTENING, and continue... + */ + if (so == 0) { + if ((tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) != TH_SYN) + goto dropwithreset; + + if ((so = socreate()) == NULL) + goto dropwithreset; + if (tcp_attach(so) < 0) { + free(so); /* Not sofree (if it failed, it's not insqued) */ + goto dropwithreset; + } + + sbreserve(&so->so_snd, tcp_sndspace); + sbreserve(&so->so_rcv, tcp_rcvspace); + + /* tcp_last_so = so; */ /* XXX ? */ + /* tp = sototcpcb(so); */ + + so->so_laddr = ti->ti_src; + so->so_lport = ti->ti_sport; + so->so_faddr = ti->ti_dst; + so->so_fport = ti->ti_dport; + + if ((so->so_iptos = tcp_tos(so)) == 0) + so->so_iptos = ((struct ip *)ti)->ip_tos; + + tp = sototcpcb(so); + tp->t_state = TCPS_LISTEN; + } + + /* + * If this is a still-connecting socket, this probably + * a retransmit of the SYN. Whether it's a retransmit SYN + * or something else, we nuke it. + */ + if (so->so_state & SS_ISFCONNECTING) + goto drop; + + tp = sototcpcb(so); + + /* XXX Should never fail */ + if (tp == 0) + goto dropwithreset; + if (tp->t_state == TCPS_CLOSED) + goto drop; + + /* Unscale the window into a 32-bit value. */ +/* if ((tiflags & TH_SYN) == 0) + * tiwin = ti->ti_win << tp->snd_scale; + * else + */ + tiwin = ti->ti_win; + + /* + * Segment received on connection. + * Reset idle time and keep-alive timer. + */ + tp->t_idle = 0; + if (so_options) + tp->t_timer[TCPT_KEEP] = tcp_keepintvl; + else + tp->t_timer[TCPT_KEEP] = tcp_keepidle; + + /* + * Process options if not in LISTEN state, + * else do it below (after getting remote address). + */ + if (optp && tp->t_state != TCPS_LISTEN) + tcp_dooptions(tp, (u_char *)optp, optlen, ti); +/* , */ +/* &ts_present, &ts_val, &ts_ecr); */ + + /* + * Header prediction: check for the two common cases + * of a uni-directional data xfer. If the packet has + * no control flags, is in-sequence, the window didn't + * change and we're not retransmitting, it's a + * candidate. If the length is zero and the ack moved + * forward, we're the sender side of the xfer. Just + * free the data acked & wake any higher level process + * that was blocked waiting for space. If the length + * is non-zero and the ack didn't move, we're the + * receiver side. If we're getting packets in-order + * (the reassembly queue is empty), add the data to + * the socket buffer and note that we need a delayed ack. + * + * XXX Some of these tests are not needed + * eg: the tiwin == tp->snd_wnd prevents many more + * predictions.. with no *real* advantage.. + */ + if (tp->t_state == TCPS_ESTABLISHED && + (tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK && +/* (!ts_present || TSTMP_GEQ(ts_val, tp->ts_recent)) && */ + ti->ti_seq == tp->rcv_nxt && + tiwin && tiwin == tp->snd_wnd && + tp->snd_nxt == tp->snd_max) { + /* + * If last ACK falls within this segment's sequence numbers, + * record the timestamp. + */ +/* if (ts_present && SEQ_LEQ(ti->ti_seq, tp->last_ack_sent) && + * SEQ_LT(tp->last_ack_sent, ti->ti_seq + ti->ti_len)) { + * tp->ts_recent_age = tcp_now; + * tp->ts_recent = ts_val; + * } + */ + if (ti->ti_len == 0) { + if (SEQ_GT(ti->ti_ack, tp->snd_una) && + SEQ_LEQ(ti->ti_ack, tp->snd_max) && + tp->snd_cwnd >= tp->snd_wnd) { + /* + * this is a pure ack for outstanding data. + */ + ++tcpstat.tcps_predack; +/* if (ts_present) + * tcp_xmit_timer(tp, tcp_now-ts_ecr+1); + * else + */ if (tp->t_rtt && + SEQ_GT(ti->ti_ack, tp->t_rtseq)) + tcp_xmit_timer(tp, tp->t_rtt); + acked = ti->ti_ack - tp->snd_una; + tcpstat.tcps_rcvackpack++; + tcpstat.tcps_rcvackbyte += acked; + sbdrop(&so->so_snd, acked); + tp->snd_una = ti->ti_ack; + m_freem(m); + + /* + * If all outstanding data are acked, stop + * retransmit timer, otherwise restart timer + * using current (possibly backed-off) value. + * If process is waiting for space, + * wakeup/selwakeup/signal. If data + * are ready to send, let tcp_output + * decide between more output or persist. + */ + if (tp->snd_una == tp->snd_max) + tp->t_timer[TCPT_REXMT] = 0; + else if (tp->t_timer[TCPT_PERSIST] == 0) + tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; + + /* + * There's room in so_snd, sowwakup will read() + * from the socket if we can + */ +/* if (so->so_snd.sb_flags & SB_NOTIFY) + * sowwakeup(so); + */ + /* + * This is called because sowwakeup might have + * put data into so_snd. Since we don't so sowwakeup, + * we don't need this.. XXX??? + */ + if (so->so_snd.sb_cc) + (void) tcp_output(tp); + + return; + } + } else if (ti->ti_ack == tp->snd_una && + tp->seg_next == (tcpiphdrp_32)tp && + ti->ti_len <= sbspace(&so->so_rcv)) { + /* + * this is a pure, in-sequence data packet + * with nothing on the reassembly queue and + * we have enough buffer space to take it. + */ + ++tcpstat.tcps_preddat; + tp->rcv_nxt += ti->ti_len; + tcpstat.tcps_rcvpack++; + tcpstat.tcps_rcvbyte += ti->ti_len; + /* + * Add data to socket buffer. + */ + if (so->so_emu) { + if (tcp_emu(so,m)) sbappend(so, m); + } else + sbappend(so, m); + + /* + * XXX This is called when data arrives. Later, check + * if we can actually write() to the socket + * XXX Need to check? It's be NON_BLOCKING + */ +/* sorwakeup(so); */ + + /* + * If this is a short packet, then ACK now - with Nagel + * congestion avoidance sender won't send more until + * he gets an ACK. + * + * It is better to not delay acks at all to maximize + * TCP throughput. See RFC 2581. + */ + tp->t_flags |= TF_ACKNOW; + tcp_output(tp); + return; + } + } /* header prediction */ + /* + * Calculate amount of space in receive window, + * and then do TCP input processing. + * Receive window is amount of space in rcv queue, + * but not less than advertised window. + */ + { int win; + win = sbspace(&so->so_rcv); + if (win < 0) + win = 0; + tp->rcv_wnd = max(win, (int)(tp->rcv_adv - tp->rcv_nxt)); + } + + switch (tp->t_state) { + + /* + * If the state is LISTEN then ignore segment if it contains an RST. + * If the segment contains an ACK then it is bad and send a RST. + * If it does not contain a SYN then it is not interesting; drop it. + * Don't bother responding if the destination was a broadcast. + * Otherwise initialize tp->rcv_nxt, and tp->irs, select an initial + * tp->iss, and send a segment: + * + * Also initialize tp->snd_nxt to tp->iss+1 and tp->snd_una to tp->iss. + * Fill in remote peer address fields if not previously specified. + * Enter SYN_RECEIVED state, and process any other fields of this + * segment in this state. + */ + case TCPS_LISTEN: { + + if (tiflags & TH_RST) + goto drop; + if (tiflags & TH_ACK) + goto dropwithreset; + if ((tiflags & TH_SYN) == 0) + goto drop; + + /* + * This has way too many gotos... + * But a bit of spaghetti code never hurt anybody :) + */ + + /* + * If this is destined for the control address, then flag to + * tcp_ctl once connected, otherwise connect + */ + if ((so->so_faddr.s_addr&htonl(0xffffff00)) == special_addr.s_addr) { + int lastbyte=ntohl(so->so_faddr.s_addr) & 0xff; + if (lastbyte!=CTL_ALIAS && lastbyte!=CTL_DNS) { +#if 0 + if(lastbyte==CTL_CMD || lastbyte==CTL_EXEC) { + /* Command or exec adress */ + so->so_state |= SS_CTL; + } else +#endif + { + /* May be an add exec */ + struct ex_list *ex_ptr; + for(ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { + if(ex_ptr->ex_fport == so->so_fport && + lastbyte == ex_ptr->ex_addr) { + so->so_state |= SS_CTL; + break; + } + } + } + if(so->so_state & SS_CTL) goto cont_input; + } + /* CTL_ALIAS: Do nothing, tcp_fconnect will be called on it */ + } + + if (so->so_emu & EMU_NOCONNECT) { + so->so_emu &= ~EMU_NOCONNECT; + goto cont_input; + } + + if((tcp_fconnect(so) == -1) && (errno != EINPROGRESS) && (errno != EWOULDBLOCK)) { + u_char code=ICMP_UNREACH_NET; + DEBUG_MISC((dfd," tcp fconnect errno = %d-%s\n", + errno,strerror(errno))); + if(errno == ECONNREFUSED) { + /* ACK the SYN, send RST to refuse the connection */ + tcp_respond(tp, ti, m, ti->ti_seq+1, (tcp_seq)0, + TH_RST|TH_ACK); + } else { + if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST; + HTONL(ti->ti_seq); /* restore tcp header */ + HTONL(ti->ti_ack); + HTONS(ti->ti_win); + HTONS(ti->ti_urp); + m->m_data -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); + m->m_len += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr); + *ip=save_ip; + icmp_error(m, ICMP_UNREACH,code, 0,strerror(errno)); + } + tp = tcp_close(tp); + m_free(m); + } else { + /* + * Haven't connected yet, save the current SLIRPmbuf + * and ti, and return + * XXX Some OS's don't tell us whether the connect() + * succeeded or not. So we must time it out. + */ + so->so_m = m; + so->so_ti = ti; + tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; + tp->t_state = TCPS_SYN_RECEIVED; + } + return; + + cont_conn: + /* m==NULL + * Check if the connect succeeded + */ + if (so->so_state & SS_NOFDREF) { + tp = tcp_close(tp); + goto dropwithreset; + } + cont_input: + tcp_template(tp); + + if (optp) + tcp_dooptions(tp, (u_char *)optp, optlen, ti); + /* , */ + /* &ts_present, &ts_val, &ts_ecr); */ + + if (iss) + tp->iss = iss; + else + tp->iss = tcp_iss; + tcp_iss += TCP_ISSINCR/2; + tp->irs = ti->ti_seq; + tcp_sendseqinit(tp); + tcp_rcvseqinit(tp); + tp->t_flags |= TF_ACKNOW; + tp->t_state = TCPS_SYN_RECEIVED; + tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; + tcpstat.tcps_accepts++; + goto trimthenstep6; + } /* case TCPS_LISTEN */ + + /* + * If the state is SYN_SENT: + * if seg contains an ACK, but not for our SYN, drop the input. + * if seg contains a RST, then drop the connection. + * if seg does not contain SYN, then drop it. + * Otherwise this is an acceptable SYN segment + * initialize tp->rcv_nxt and tp->irs + * if seg contains ack then advance tp->snd_una + * if SYN has been acked change to ESTABLISHED else SYN_RCVD state + * arrange for segment to be acked (eventually) + * continue processing rest of data/controls, beginning with URG + */ + case TCPS_SYN_SENT: + if ((tiflags & TH_ACK) && + (SEQ_LEQ(ti->ti_ack, tp->iss) || + SEQ_GT(ti->ti_ack, tp->snd_max))) + goto dropwithreset; + + if (tiflags & TH_RST) { + if (tiflags & TH_ACK) + tp = tcp_drop(tp,0); /* XXX Check t_softerror! */ + goto drop; + } + + if ((tiflags & TH_SYN) == 0) + goto drop; + if (tiflags & TH_ACK) { + tp->snd_una = ti->ti_ack; + if (SEQ_LT(tp->snd_nxt, tp->snd_una)) + tp->snd_nxt = tp->snd_una; + } + + tp->t_timer[TCPT_REXMT] = 0; + tp->irs = ti->ti_seq; + tcp_rcvseqinit(tp); + tp->t_flags |= TF_ACKNOW; + if (tiflags & TH_ACK && SEQ_GT(tp->snd_una, tp->iss)) { + tcpstat.tcps_connects++; + soisfconnected(so); + tp->t_state = TCPS_ESTABLISHED; + + /* Do window scaling on this connection? */ +/* if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == + * (TF_RCVD_SCALE|TF_REQ_SCALE)) { + * tp->snd_scale = tp->requested_s_scale; + * tp->rcv_scale = tp->request_r_scale; + * } + */ + (void) tcp_reass(tp, (struct tcpiphdr *)0, + (struct SLIRPmbuf *)0); + /* + * if we didn't have to retransmit the SYN, + * use its rtt as our initial srtt & rtt var. + */ + if (tp->t_rtt) + tcp_xmit_timer(tp, tp->t_rtt); + } else + tp->t_state = TCPS_SYN_RECEIVED; + +trimthenstep6: + /* + * Advance ti->ti_seq to correspond to first data byte. + * If data, trim to stay within window, + * dropping FIN if necessary. + */ + ti->ti_seq++; + if (ti->ti_len > tp->rcv_wnd) { + todrop = ti->ti_len - tp->rcv_wnd; + m_adj(m, -todrop); + ti->ti_len = tp->rcv_wnd; + tiflags &= ~TH_FIN; + tcpstat.tcps_rcvpackafterwin++; + tcpstat.tcps_rcvbyteafterwin += todrop; + } + tp->snd_wl1 = ti->ti_seq - 1; + tp->rcv_up = ti->ti_seq; + goto step6; + } /* switch tp->t_state */ + /* + * States other than LISTEN or SYN_SENT. + * First check timestamp, if present. + * Then check that at least some bytes of segment are within + * receive window. If segment begins before rcv_nxt, + * drop leading data (and SYN); if nothing left, just ack. + * + * RFC 1323 PAWS: If we have a timestamp reply on this segment + * and it's less than ts_recent, drop it. + */ +/* if (ts_present && (tiflags & TH_RST) == 0 && tp->ts_recent && + * TSTMP_LT(ts_val, tp->ts_recent)) { + * + */ /* Check to see if ts_recent is over 24 days old. */ +/* if ((int)(tcp_now - tp->ts_recent_age) > TCP_PAWS_IDLE) { + */ /* + * * Invalidate ts_recent. If this segment updates + * * ts_recent, the age will be reset later and ts_recent + * * will get a valid value. If it does not, setting + * * ts_recent to zero will at least satisfy the + * * requirement that zero be placed in the timestamp + * * echo reply when ts_recent isn't valid. The + * * age isn't reset until we get a valid ts_recent + * * because we don't want out-of-order segments to be + * * dropped when ts_recent is old. + * */ +/* tp->ts_recent = 0; + * } else { + * tcpstat.tcps_rcvduppack++; + * tcpstat.tcps_rcvdupbyte += ti->ti_len; + * tcpstat.tcps_pawsdrop++; + * goto dropafterack; + * } + * } + */ + + todrop = tp->rcv_nxt - ti->ti_seq; + if (todrop > 0) { + if (tiflags & TH_SYN) { + tiflags &= ~TH_SYN; + ti->ti_seq++; + if (ti->ti_urp > 1) + ti->ti_urp--; + else + tiflags &= ~TH_URG; + todrop--; + } + /* + * Following if statement from Stevens, vol. 2, p. 960. + */ + if (todrop > ti->ti_len + || (todrop == ti->ti_len && (tiflags & TH_FIN) == 0)) { + /* + * Any valid FIN must be to the left of the window. + * At this point the FIN must be a duplicate or out + * of sequence; drop it. + */ + tiflags &= ~TH_FIN; + + /* + * Send an ACK to resynchronize and drop any data. + * But keep on processing for RST or ACK. + */ + tp->t_flags |= TF_ACKNOW; + todrop = ti->ti_len; + tcpstat.tcps_rcvduppack++; + tcpstat.tcps_rcvdupbyte += todrop; + } else { + tcpstat.tcps_rcvpartduppack++; + tcpstat.tcps_rcvpartdupbyte += todrop; + } + m_adj(m, todrop); + ti->ti_seq += todrop; + ti->ti_len -= todrop; + if (ti->ti_urp > todrop) + ti->ti_urp -= todrop; + else { + tiflags &= ~TH_URG; + ti->ti_urp = 0; + } + } + /* + * If new data are received on a connection after the + * user processes are gone, then RST the other end. + */ + if ((so->so_state & SS_NOFDREF) && + tp->t_state > TCPS_CLOSE_WAIT && ti->ti_len) { + tp = tcp_close(tp); + tcpstat.tcps_rcvafterclose++; + goto dropwithreset; + } + + /* + * If segment ends after window, drop trailing data + * (and PUSH and FIN); if nothing left, just ACK. + */ + todrop = (ti->ti_seq+ti->ti_len) - (tp->rcv_nxt+tp->rcv_wnd); + if (todrop > 0) { + tcpstat.tcps_rcvpackafterwin++; + if (todrop >= ti->ti_len) { + tcpstat.tcps_rcvbyteafterwin += ti->ti_len; + /* + * If a new connection request is received + * while in TIME_WAIT, drop the old connection + * and start over if the sequence numbers + * are above the previous ones. + */ + if (tiflags & TH_SYN && + tp->t_state == TCPS_TIME_WAIT && + SEQ_GT(ti->ti_seq, tp->rcv_nxt)) { + iss = tp->rcv_nxt + TCP_ISSINCR; + tp = tcp_close(tp); + goto findso; + } + /* + * If window is closed can only take segments at + * window edge, and have to drop data and PUSH from + * incoming segments. Continue processing, but + * remember to ack. Otherwise, drop segment + * and ack. + */ + if (tp->rcv_wnd == 0 && ti->ti_seq == tp->rcv_nxt) { + tp->t_flags |= TF_ACKNOW; + tcpstat.tcps_rcvwinprobe++; + } else + goto dropafterack; + } else + tcpstat.tcps_rcvbyteafterwin += todrop; + m_adj(m, -todrop); + ti->ti_len -= todrop; + tiflags &= ~(TH_PUSH|TH_FIN); + } + + /* + * If last ACK falls within this segment's sequence numbers, + * record its timestamp. + */ +/* if (ts_present && SEQ_LEQ(ti->ti_seq, tp->last_ack_sent) && + * SEQ_LT(tp->last_ack_sent, ti->ti_seq + ti->ti_len + + * ((tiflags & (TH_SYN|TH_FIN)) != 0))) { + * tp->ts_recent_age = tcp_now; + * tp->ts_recent = ts_val; + * } + */ + + /* + * If the RST bit is set examine the state: + * SYN_RECEIVED STATE: + * If passive open, return to LISTEN state. + * If active open, inform user that connection was refused. + * ESTABLISHED, FIN_WAIT_1, FIN_WAIT2, CLOSE_WAIT STATES: + * Inform user that connection was reset, and close tcb. + * CLOSING, LAST_ACK, TIME_WAIT STATES + * Close the tcb. + */ + if (tiflags&TH_RST) switch (tp->t_state) { + + case TCPS_SYN_RECEIVED: +/* so->so_error = ECONNREFUSED; */ + goto close; + + case TCPS_ESTABLISHED: + case TCPS_FIN_WAIT_1: + case TCPS_FIN_WAIT_2: + case TCPS_CLOSE_WAIT: +/* so->so_error = ECONNRESET; */ + close: + tp->t_state = TCPS_CLOSED; + tcpstat.tcps_drops++; + tp = tcp_close(tp); + goto drop; + + case TCPS_CLOSING: + case TCPS_LAST_ACK: + case TCPS_TIME_WAIT: + tp = tcp_close(tp); + goto drop; + } + + /* + * If a SYN is in the window, then this is an + * error and we send an RST and drop the connection. + */ + if (tiflags & TH_SYN) { + tp = tcp_drop(tp,0); + goto dropwithreset; + } + + /* + * If the ACK bit is off we drop the segment and return. + */ + if ((tiflags & TH_ACK) == 0) goto drop; + + /* + * Ack processing. + */ + switch (tp->t_state) { + /* + * In SYN_RECEIVED state if the ack ACKs our SYN then enter + * ESTABLISHED state and continue processing, otherwise + * send an RST. una<=ack<=max + */ + case TCPS_SYN_RECEIVED: + + if (SEQ_GT(tp->snd_una, ti->ti_ack) || + SEQ_GT(ti->ti_ack, tp->snd_max)) + goto dropwithreset; + tcpstat.tcps_connects++; + tp->t_state = TCPS_ESTABLISHED; + /* + * The sent SYN is ack'ed with our sequence number +1 + * The first data byte already in the buffer will get + * lost if no correction is made. This is only needed for + * SS_CTL since the buffer is empty otherwise. + * tp->snd_una++; or: + */ + tp->snd_una=ti->ti_ack; + if (so->so_state & SS_CTL) { + /* So tcp_ctl reports the right state */ + ret = tcp_ctl(so); + if (ret == 1) { + soisfconnected(so); + so->so_state &= ~SS_CTL; /* success XXX */ + } else if (ret == 2) { + so->so_state = SS_NOFDREF; /* CTL_CMD */ + } else { + needoutput = 1; + tp->t_state = TCPS_FIN_WAIT_1; + } + } else { + soisfconnected(so); + } + + /* Do window scaling? */ +/* if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) == + * (TF_RCVD_SCALE|TF_REQ_SCALE)) { + * tp->snd_scale = tp->requested_s_scale; + * tp->rcv_scale = tp->request_r_scale; + * } + */ + (void) tcp_reass(tp, (struct tcpiphdr *)0, (struct SLIRPmbuf *)0); + tp->snd_wl1 = ti->ti_seq - 1; + /* Avoid ack processing; snd_una==ti_ack => dup ack */ + goto synrx_to_est; + /* fall into ... */ + + /* + * In ESTABLISHED state: drop duplicate ACKs; ACK out of range + * ACKs. If the ack is in the range + * tp->snd_una < ti->ti_ack <= tp->snd_max + * then advance tp->snd_una to ti->ti_ack and drop + * data from the retransmission queue. If this ACK reflects + * more up to date window information we update our window information. + */ + case TCPS_ESTABLISHED: + case TCPS_FIN_WAIT_1: + case TCPS_FIN_WAIT_2: + case TCPS_CLOSE_WAIT: + case TCPS_CLOSING: + case TCPS_LAST_ACK: + case TCPS_TIME_WAIT: + + if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) { + if (ti->ti_len == 0 && tiwin == tp->snd_wnd) { + tcpstat.tcps_rcvdupack++; + DEBUG_MISC((dfd," dup ack m = %lx so = %lx \n", + (long )m, (long )so)); + /* + * If we have outstanding data (other than + * a window probe), this is a completely + * duplicate ack (ie, window info didn't + * change), the ack is the biggest we've + * seen and we've seen exactly our rexmt + * threshold of them, assume a packet + * has been dropped and retransmit it. + * Kludge snd_nxt & the congestion + * window so we send only this one + * packet. + * + * We know we're losing at the current + * window size so do congestion avoidance + * (set ssthresh to half the current window + * and pull our congestion window back to + * the new ssthresh). + * + * Dup acks mean that packets have left the + * network (they're now cached at the receiver) + * so bump cwnd by the amount in the receiver + * to keep a constant cwnd packets in the + * network. + */ + if (tp->t_timer[TCPT_REXMT] == 0 || + ti->ti_ack != tp->snd_una) + tp->t_dupacks = 0; + else if (++tp->t_dupacks == tcprexmtthresh) { + tcp_seq onxt = tp->snd_nxt; + u_int win = + min(tp->snd_wnd, tp->snd_cwnd) / 2 / + tp->t_maxseg; + + if (win < 2) + win = 2; + tp->snd_ssthresh = win * tp->t_maxseg; + tp->t_timer[TCPT_REXMT] = 0; + tp->t_rtt = 0; + tp->snd_nxt = ti->ti_ack; + tp->snd_cwnd = tp->t_maxseg; + (void) tcp_output(tp); + tp->snd_cwnd = tp->snd_ssthresh + + tp->t_maxseg * tp->t_dupacks; + if (SEQ_GT(onxt, tp->snd_nxt)) + tp->snd_nxt = onxt; + goto drop; + } else if (tp->t_dupacks > tcprexmtthresh) { + tp->snd_cwnd += tp->t_maxseg; + (void) tcp_output(tp); + goto drop; + } + } else + tp->t_dupacks = 0; + break; + } + synrx_to_est: + /* + * If the congestion window was inflated to account + * for the other side's cached packets, retract it. + */ + if (tp->t_dupacks > tcprexmtthresh && + tp->snd_cwnd > tp->snd_ssthresh) + tp->snd_cwnd = tp->snd_ssthresh; + tp->t_dupacks = 0; + if (SEQ_GT(ti->ti_ack, tp->snd_max)) { + tcpstat.tcps_rcvacktoomuch++; + goto dropafterack; + } + acked = ti->ti_ack - tp->snd_una; + tcpstat.tcps_rcvackpack++; + tcpstat.tcps_rcvackbyte += acked; + + /* + * If we have a timestamp reply, update smoothed + * round trip time. If no timestamp is present but + * transmit timer is running and timed sequence + * number was acked, update smoothed round trip time. + * Since we now have an rtt measurement, cancel the + * timer backoff (cf., Phil Karn's retransmit alg.). + * Recompute the initial retransmit timer. + */ +/* if (ts_present) + * tcp_xmit_timer(tp, tcp_now-ts_ecr+1); + * else + */ + if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq)) + tcp_xmit_timer(tp,tp->t_rtt); + + /* + * If all outstanding data is acked, stop retransmit + * timer and remember to restart (more output or persist). + * If there is more data to be acked, restart retransmit + * timer, using current (possibly backed-off) value. + */ + if (ti->ti_ack == tp->snd_max) { + tp->t_timer[TCPT_REXMT] = 0; + needoutput = 1; + } else if (tp->t_timer[TCPT_PERSIST] == 0) + tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; + /* + * When new data is acked, open the congestion window. + * If the window gives us less than ssthresh packets + * in flight, open exponentially (maxseg per packet). + * Otherwise open linearly: maxseg per window + * (maxseg^2 / cwnd per packet). + */ + { + u_int cw = tp->snd_cwnd; + u_int incr = tp->t_maxseg; + + if (cw > tp->snd_ssthresh) + incr = incr * incr / cw; + tp->snd_cwnd = min(cw + incr, TCP_MAXWIN<snd_scale); + } + if (acked > so->so_snd.sb_cc) { + tp->snd_wnd -= so->so_snd.sb_cc; + sbdrop(&so->so_snd, (int )so->so_snd.sb_cc); + ourfinisacked = 1; + } else { + sbdrop(&so->so_snd, acked); + tp->snd_wnd -= acked; + ourfinisacked = 0; + } + /* + * XXX sowwakup is called when data is acked and there's room for + * for more data... it should read() the socket + */ +/* if (so->so_snd.sb_flags & SB_NOTIFY) + * sowwakeup(so); + */ + tp->snd_una = ti->ti_ack; + if (SEQ_LT(tp->snd_nxt, tp->snd_una)) + tp->snd_nxt = tp->snd_una; + + switch (tp->t_state) { + + /* + * In FIN_WAIT_1 STATE in addition to the processing + * for the ESTABLISHED state if our FIN is now acknowledged + * then enter FIN_WAIT_2. + */ + case TCPS_FIN_WAIT_1: + if (ourfinisacked) { + /* + * If we can't receive any more + * data, then closing user can proceed. + * Starting the timer is contrary to the + * specification, but if we don't get a FIN + * we'll hang forever. + */ + if (so->so_state & SS_FCANTRCVMORE) { + soisfdisconnected(so); + tp->t_timer[TCPT_2MSL] = tcp_maxidle; + } + tp->t_state = TCPS_FIN_WAIT_2; + } + break; + + /* + * In CLOSING STATE in addition to the processing for + * the ESTABLISHED state if the ACK acknowledges our FIN + * then enter the TIME-WAIT state, otherwise ignore + * the segment. + */ + case TCPS_CLOSING: + if (ourfinisacked) { + tp->t_state = TCPS_TIME_WAIT; + tcp_canceltimers(tp); + tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; + soisfdisconnected(so); + } + break; + + /* + * In LAST_ACK, we may still be waiting for data to drain + * and/or to be acked, as well as for the ack of our FIN. + * If our FIN is now acknowledged, delete the TCB, + * enter the closed state and return. + */ + case TCPS_LAST_ACK: + if (ourfinisacked) { + tp = tcp_close(tp); + goto drop; + } + break; + + /* + * In TIME_WAIT state the only thing that should arrive + * is a retransmission of the remote FIN. Acknowledge + * it and restart the finack timer. + */ + case TCPS_TIME_WAIT: + tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; + goto dropafterack; + } + } /* switch(tp->t_state) */ + +step6: + /* + * Update window information. + * Don't look at window if no ACK: TAC's send garbage on first SYN. + */ + if ((tiflags & TH_ACK) && + (SEQ_LT(tp->snd_wl1, ti->ti_seq) || + (tp->snd_wl1 == ti->ti_seq && (SEQ_LT(tp->snd_wl2, ti->ti_ack) || + (tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd))))) { + /* keep track of pure window updates */ + if (ti->ti_len == 0 && + tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd) + tcpstat.tcps_rcvwinupd++; + tp->snd_wnd = tiwin; + tp->snd_wl1 = ti->ti_seq; + tp->snd_wl2 = ti->ti_ack; + if (tp->snd_wnd > tp->max_sndwnd) + tp->max_sndwnd = tp->snd_wnd; + needoutput = 1; + } + + /* + * Process segments with URG. + */ + if ((tiflags & TH_URG) && ti->ti_urp && + TCPS_HAVERCVDFIN(tp->t_state) == 0) { + /* + * This is a kludge, but if we receive and accept + * random urgent pointers, we'll crash in + * soreceive. It's hard to imagine someone + * actually wanting to send this much urgent data. + */ + if (ti->ti_urp + so->so_rcv.sb_cc > so->so_rcv.sb_datalen) { + ti->ti_urp = 0; + tiflags &= ~TH_URG; + goto dodata; + } + /* + * If this segment advances the known urgent pointer, + * then mark the data stream. This should not happen + * in CLOSE_WAIT, CLOSING, LAST_ACK or TIME_WAIT STATES since + * a FIN has been received from the remote side. + * In these states we ignore the URG. + * + * According to RFC961 (Assigned Protocols), + * the urgent pointer points to the last octet + * of urgent data. We continue, however, + * to consider it to indicate the first octet + * of data past the urgent section as the original + * spec states (in one of two places). + */ + if (SEQ_GT(ti->ti_seq+ti->ti_urp, tp->rcv_up)) { + tp->rcv_up = ti->ti_seq + ti->ti_urp; + so->so_urgc = so->so_rcv.sb_cc + + (tp->rcv_up - tp->rcv_nxt); /* -1; */ + tp->rcv_up = ti->ti_seq + ti->ti_urp; + + } + } else + /* + * If no out of band data is expected, + * pull receive urgent pointer along + * with the receive window. + */ + if (SEQ_GT(tp->rcv_nxt, tp->rcv_up)) + tp->rcv_up = tp->rcv_nxt; +dodata: + + /* + * Process the segment text, merging it into the TCP sequencing queue, + * and arranging for acknowledgment of receipt if necessary. + * This process logically involves adjusting tp->rcv_wnd as data + * is presented to the user (this happens in tcp_usrreq.c, + * case PRU_RCVD). If a FIN has already been received on this + * connection then we just ignore the text. + */ + if ((ti->ti_len || (tiflags&TH_FIN)) && + TCPS_HAVERCVDFIN(tp->t_state) == 0) { + TCP_REASS(tp, ti, m, so, tiflags); + /* + * Note the amount of data that peer has sent into + * our window, in order to estimate the sender's + * buffer size. + */ + len = so->so_rcv.sb_datalen - (tp->rcv_adv - tp->rcv_nxt); + } else { + m_free(m); + tiflags &= ~TH_FIN; + } + + /* + * If FIN is received ACK the FIN and let the user know + * that the connection is closing. + */ + if (tiflags & TH_FIN) { + if (TCPS_HAVERCVDFIN(tp->t_state) == 0) { + /* + * If we receive a FIN we can't send more data, + * set it SS_FDRAIN + * Shutdown the socket if there is no rx data in the + * buffer. + * soread() is called on completion of shutdown() and + * will got to TCPS_LAST_ACK, and use tcp_output() + * to send the FIN. + */ +/* sofcantrcvmore(so); */ + sofwdrain(so); + + tp->t_flags |= TF_ACKNOW; + tp->rcv_nxt++; + } + switch (tp->t_state) { + + /* + * In SYN_RECEIVED and ESTABLISHED STATES + * enter the CLOSE_WAIT state. + */ + case TCPS_SYN_RECEIVED: + case TCPS_ESTABLISHED: + if(so->so_emu == EMU_CTL) /* no shutdown on socket */ + tp->t_state = TCPS_LAST_ACK; + else + tp->t_state = TCPS_CLOSE_WAIT; + break; + + /* + * If still in FIN_WAIT_1 STATE FIN has not been acked so + * enter the CLOSING state. + */ + case TCPS_FIN_WAIT_1: + tp->t_state = TCPS_CLOSING; + break; + + /* + * In FIN_WAIT_2 state enter the TIME_WAIT state, + * starting the time-wait timer, turning off the other + * standard timers. + */ + case TCPS_FIN_WAIT_2: + tp->t_state = TCPS_TIME_WAIT; + tcp_canceltimers(tp); + tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; + soisfdisconnected(so); + break; + + /* + * In TIME_WAIT state restart the 2 MSL time_wait timer. + */ + case TCPS_TIME_WAIT: + tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL; + break; + } + } + + /* + * If this is a small packet, then ACK now - with Nagel + * congestion avoidance sender won't send more until + * he gets an ACK. + * + * See above. + */ +/* if (ti->ti_len && (unsigned)ti->ti_len < tp->t_maxseg) { + */ +/* if ((ti->ti_len && (unsigned)ti->ti_len < tp->t_maxseg && + * (so->so_iptos & IPTOS_LOWDELAY) == 0) || + * ((so->so_iptos & IPTOS_LOWDELAY) && + * ((struct tcpiphdr_2 *)ti)->first_char == (char)27)) { + */ + if (ti->ti_len && (unsigned)ti->ti_len <= 5 && + ((struct tcpiphdr_2 *)ti)->first_char == (char)27) { + tp->t_flags |= TF_ACKNOW; + } + + /* + * Return any desired output. + */ + if (needoutput || (tp->t_flags & TF_ACKNOW)) { + (void) tcp_output(tp); + } + return; + +dropafterack: + /* + * Generate an ACK dropping incoming segment if it occupies + * sequence space, where the ACK reflects our state. + */ + if (tiflags & TH_RST) + goto drop; + m_freem(m); + tp->t_flags |= TF_ACKNOW; + (void) tcp_output(tp); + return; + +dropwithreset: + /* reuses m if m!=NULL, m_free() unnecessary */ + if (tiflags & TH_ACK) + tcp_respond(tp, ti, m, (tcp_seq)0, ti->ti_ack, TH_RST); + else { + if (tiflags & TH_SYN) ti->ti_len++; + tcp_respond(tp, ti, m, ti->ti_seq+ti->ti_len, (tcp_seq)0, + TH_RST|TH_ACK); + } + + return; + +drop: + /* + * Drop space held by incoming segment and return. + */ + m_free(m); + + return; +} + + /* , ts_present, ts_val, ts_ecr) */ +/* int *ts_present; + * u_int32_t *ts_val, *ts_ecr; + */ +void +tcp_dooptions(tp, cp, cnt, ti) + struct tcpcb *tp; + u_char *cp; + int cnt; + struct tcpiphdr *ti; +{ + u_int16_t mss; + int opt, optlen; + + DEBUG_CALL("tcp_dooptions"); + DEBUG_ARGS((dfd," tp = %lx cnt=%i \n", (long )tp, cnt)); + + for (; cnt > 0; cnt -= optlen, cp += optlen) { + opt = cp[0]; + if (opt == TCPOPT_EOL) + break; + if (opt == TCPOPT_NOP) + optlen = 1; + else { + optlen = cp[1]; + if (optlen <= 0) + break; + } + switch (opt) { + + default: + continue; + + case TCPOPT_MAXSEG: + if (optlen != TCPOLEN_MAXSEG) + continue; + if (!(ti->ti_flags & TH_SYN)) + continue; + memcpy((char *) &mss, (char *) cp + 2, sizeof(mss)); + NTOHS(mss); + (void) tcp_mss(tp, mss); /* sets t_maxseg */ + break; + +/* case TCPOPT_WINDOW: + * if (optlen != TCPOLEN_WINDOW) + * continue; + * if (!(ti->ti_flags & TH_SYN)) + * continue; + * tp->t_flags |= TF_RCVD_SCALE; + * tp->requested_s_scale = min(cp[2], TCP_MAX_WINSHIFT); + * break; + */ +/* case TCPOPT_TIMESTAMP: + * if (optlen != TCPOLEN_TIMESTAMP) + * continue; + * *ts_present = 1; + * memcpy((char *) ts_val, (char *)cp + 2, sizeof(*ts_val)); + * NTOHL(*ts_val); + * memcpy((char *) ts_ecr, (char *)cp + 6, sizeof(*ts_ecr)); + * NTOHL(*ts_ecr); + * + */ /* + * * A timestamp received in a SYN makes + * * it ok to send timestamp requests and replies. + * */ +/* if (ti->ti_flags & TH_SYN) { + * tp->t_flags |= TF_RCVD_TSTMP; + * tp->ts_recent = *ts_val; + * tp->ts_recent_age = tcp_now; + * } + */ break; + } + } +} + + +/* + * Pull out of band byte out of a segment so + * it doesn't appear in the user's data queue. + * It is still reflected in the segment length for + * sequencing purposes. + */ + +#ifdef notdef + +void +tcp_pulloutofband(so, ti, m) + struct SLIRPsocket *so; + struct tcpiphdr *ti; + struct SLIRPmbuf *m; +{ + int cnt = ti->ti_urp - 1; + + while (cnt >= 0) { + if (m->m_len > cnt) { + char *cp = mtod(m, SLIRPcaddr_t) + cnt; + struct tcpcb *tp = sototcpcb(so); + + tp->t_iobc = *cp; + tp->t_oobflags |= TCPOOB_HAVEDATA; + memcpy(sp, cp+1, (unsigned)(m->m_len - cnt - 1)); + m->m_len--; + return; + } + cnt -= m->m_len; + m = m->m_next; /* XXX WRONG! Fix it! */ + if (m == 0) + break; + } + panic("tcp_pulloutofband"); +} + +#endif /* notdef */ + +/* + * Collect new round-trip time estimate + * and update averages and current timeout. + */ + +void +tcp_xmit_timer(tp, rtt) + struct tcpcb *tp; + int rtt; +{ + short delta; + + DEBUG_CALL("tcp_xmit_timer"); + DEBUG_ARG("tp = %lx", (long)tp); + DEBUG_ARG("rtt = %d", rtt); + + tcpstat.tcps_rttupdated++; + if (tp->t_srtt != 0) { + /* + * srtt is stored as fixed point with 3 bits after the + * binary point (i.e., scaled by 8). The following magic + * is equivalent to the smoothing algorithm in rfc793 with + * an alpha of .875 (srtt = rtt/8 + srtt*7/8 in fixed + * point). Adjust rtt to origin 0. + */ + delta = rtt - 1 - (tp->t_srtt >> TCP_RTT_SHIFT); + if ((tp->t_srtt += delta) <= 0) + tp->t_srtt = 1; + /* + * We accumulate a smoothed rtt variance (actually, a + * smoothed mean difference), then set the retransmit + * timer to smoothed rtt + 4 times the smoothed variance. + * rttvar is stored as fixed point with 2 bits after the + * binary point (scaled by 4). The following is + * equivalent to rfc793 smoothing with an alpha of .75 + * (rttvar = rttvar*3/4 + |delta| / 4). This replaces + * rfc793's wired-in beta. + */ + if (delta < 0) + delta = -delta; + delta -= (tp->t_rttvar >> TCP_RTTVAR_SHIFT); + if ((tp->t_rttvar += delta) <= 0) + tp->t_rttvar = 1; + } else { + /* + * No rtt measurement yet - use the unsmoothed rtt. + * Set the variance to half the rtt (so our first + * retransmit happens at 3*rtt). + */ + tp->t_srtt = rtt << TCP_RTT_SHIFT; + tp->t_rttvar = rtt << (TCP_RTTVAR_SHIFT - 1); + } + tp->t_rtt = 0; + tp->t_rxtshift = 0; + + /* + * the retransmit should happen at rtt + 4 * rttvar. + * Because of the way we do the smoothing, srtt and rttvar + * will each average +1/2 tick of bias. When we compute + * the retransmit timer, we want 1/2 tick of rounding and + * 1 extra tick because of +-1/2 tick uncertainty in the + * firing of the timer. The bias will give us exactly the + * 1.5 tick we need. But, because the bias is + * statistical, we have to test that we don't drop below + * the minimum feasible timer (which is 2 ticks). + */ + TCPT_RANGESET(tp->t_rxtcur, TCP_REXMTVAL(tp), + (short)tp->t_rttmin, TCPTV_REXMTMAX); /* XXX */ + + /* + * We received an ack for a packet that wasn't retransmitted; + * it is probably safe to discard any error indications we've + * received recently. This isn't quite right, but close enough + * for now (a route might have failed after we sent a segment, + * and the return path might not be symmetrical). + */ + tp->t_softerror = 0; +} + +/* + * Determine a reasonable value for maxseg size. + * If the route is known, check route for mtu. + * If none, use an mss that can be handled on the outgoing + * interface without forcing IP to fragment; if bigger than + * an SLIRPmbuf cluster (MCLBYTES), round down to nearest multiple of MCLBYTES + * to utilize large SLIRPmbufs. If no route is found, route has no mtu, + * or the destination isn't local, use a default, hopefully conservative + * size (usually 512 or the default IP max size, but no more than the mtu + * of the interface), as we can't discover anything about intervening + * gateways or networks. We also initialize the congestion/slow start + * window to be a single segment if the destination isn't local. + * While looking at the routing entry, we also initialize other path-dependent + * parameters from pre-set or cached values in the routing entry. + */ + +int +tcp_mss(tp, offer) + struct tcpcb *tp; + u_int offer; +{ + struct SLIRPsocket *so = tp->t_socket; + int mss; + + DEBUG_CALL("tcp_mss"); + DEBUG_ARG("tp = %lx", (long)tp); + DEBUG_ARG("offer = %d", offer); + + mss = min(if_mtu, if_mru) - sizeof(struct tcpiphdr); + if (offer) + mss = min(mss, offer); + mss = max(mss, 32); + if (mss < tp->t_maxseg || offer != 0) + tp->t_maxseg = mss; + + tp->snd_cwnd = mss; + + sbreserve(&so->so_snd, tcp_sndspace+((tcp_sndspace%mss)?(mss-(tcp_sndspace%mss)):0)); + sbreserve(&so->so_rcv, tcp_rcvspace+((tcp_rcvspace%mss)?(mss-(tcp_rcvspace%mss)):0)); + + DEBUG_MISC((dfd, " returning mss = %d\n", mss)); + + return mss; +} diff --git a/src/slirp/tcp_output.c b/src/slirp/tcp_output.c new file mode 100644 index 000000000..7d75b64b2 --- /dev/null +++ b/src/slirp/tcp_output.c @@ -0,0 +1,601 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tcp_output.c 8.3 (Berkeley) 12/30/93 + * tcp_output.c,v 1.3 1994/09/15 10:36:55 davidg Exp + */ + +/* + * Changes and additions relating to SLiRP + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#include "slirp.h" + +/* + * Since this is only used in "stats socket", we give meaning + * names instead of the REAL names + */ +char *tcpstates[] = { +/* "CLOSED", "LISTEN", "SYN_SENT", "SYN_RCVD", */ + "REDIRECT", "LISTEN", "SYN_SENT", "SYN_RCVD", + "ESTABLISHED", "CLOSE_WAIT", "FIN_WAIT_1", "CLOSING", + "LAST_ACK", "FIN_WAIT_2", "TIME_WAIT", +}; + +u_char tcp_outflags[TCP_NSTATES] = { + TH_RST|TH_ACK, 0, TH_SYN, TH_SYN|TH_ACK, + TH_ACK, TH_ACK, TH_FIN|TH_ACK, TH_FIN|TH_ACK, + TH_FIN|TH_ACK, TH_ACK, TH_ACK, +}; + + +#define MAX_TCPOPTLEN 32 /* max # bytes that go in options */ + +/* + * Tcp output routine: figure out what should be sent and send it. + */ +int +tcp_output(tp) + struct tcpcb *tp; +{ + struct SLIRPsocket *so = tp->t_socket; + register long len, win; + int off, flags, error; + struct SLIRPmbuf *m; + struct tcpiphdr *ti; + u_char opt[MAX_TCPOPTLEN]; + unsigned optlen, hdrlen; + int idle, sendalot; + + DEBUG_CALL("tcp_output"); + DEBUG_ARG("tp = %lx", (long )tp); + + /* + * Determine length of data that should be transmitted, + * and flags that will be used. + * If there is some data or critical controls (SYN, RST) + * to send, then transmit; otherwise, investigate further. + */ + idle = (tp->snd_max == tp->snd_una); + if (idle && tp->t_idle >= tp->t_rxtcur) + /* + * We have been idle for "a while" and no acks are + * expected to clock out any data we send -- + * slow start to get ack "clock" running again. + */ + tp->snd_cwnd = tp->t_maxseg; +again: + sendalot = 0; + off = tp->snd_nxt - tp->snd_una; + win = min(tp->snd_wnd, tp->snd_cwnd); + + flags = tcp_outflags[tp->t_state]; + + DEBUG_MISC((dfd, " --- tcp_output flags = 0x%x\n",flags)); + + /* + * If in persist timeout with window of 0, send 1 byte. + * Otherwise, if window is small but nonzero + * and timer expired, we will send what we can + * and go to transmit state. + */ + if (tp->t_force) { + if (win == 0) { + /* + * If we still have some data to send, then + * clear the FIN bit. Usually this would + * happen below when it realizes that we + * aren't sending all the data. However, + * if we have exactly 1 byte of unset data, + * then it won't clear the FIN bit below, + * and if we are in persist state, we wind + * up sending the packet without recording + * that we sent the FIN bit. + * + * We can't just blindly clear the FIN bit, + * because if we don't have any more data + * to send then the probe will be the FIN + * itself. + */ + if (off < so->so_snd.sb_cc) + flags &= ~TH_FIN; + win = 1; + } else { + tp->t_timer[TCPT_PERSIST] = 0; + tp->t_rxtshift = 0; + } + } + + len = min(so->so_snd.sb_cc, win) - off; + + if (len < 0) { + /* + * If FIN has been sent but not acked, + * but we haven't been called to retransmit, + * len will be -1. Otherwise, window shrank + * after we sent into it. If window shrank to 0, + * cancel pending retransmit and pull snd_nxt + * back to (closed) window. We will enter persist + * state below. If the window didn't close completely, + * just wait for an ACK. + */ + len = 0; + if (win == 0) { + tp->t_timer[TCPT_REXMT] = 0; + tp->snd_nxt = tp->snd_una; + } + } + + if (len > tp->t_maxseg) { + len = tp->t_maxseg; + sendalot = 1; + } + if (SEQ_LT(tp->snd_nxt + len, tp->snd_una + so->so_snd.sb_cc)) + flags &= ~TH_FIN; + + win = sbspace(&so->so_rcv); + + /* + * Sender silly window avoidance. If connection is idle + * and can send all data, a maximum segment, + * at least a maximum default-size segment do it, + * or are forced, do it; otherwise don't bother. + * If peer's buffer is tiny, then send + * when window is at least half open. + * If retransmitting (possibly after persist timer forced us + * to send into a small window), then must resend. + */ + if (len) { + if (len == tp->t_maxseg) + goto send; + if ((1 || idle || tp->t_flags & TF_NODELAY) && + len + off >= so->so_snd.sb_cc) + goto send; + if (tp->t_force) + goto send; + if (len >= tp->max_sndwnd / 2 && tp->max_sndwnd > 0) + goto send; + if (SEQ_LT(tp->snd_nxt, tp->snd_max)) + goto send; + } + + /* + * Compare available window to amount of window + * known to peer (as advertised window less + * next expected input). If the difference is at least two + * max size segments, or at least 50% of the maximum possible + * window, then want to send a window update to peer. + */ + if (win > 0) { + /* + * "adv" is the amount we can increase the window, + * taking into account that we are limited by + * TCP_MAXWIN << tp->rcv_scale. + */ + long adv = min(win, (long)TCP_MAXWIN << tp->rcv_scale) - + (tp->rcv_adv - tp->rcv_nxt); + + if (adv >= (long) (2 * tp->t_maxseg)) + goto send; + if (2 * adv >= (long) so->so_rcv.sb_datalen) + goto send; + } + + /* + * Send if we owe peer an ACK. + */ + if (tp->t_flags & TF_ACKNOW) + goto send; + if (flags & (TH_SYN|TH_RST)) + goto send; + if (SEQ_GT(tp->snd_up, tp->snd_una)) + goto send; + /* + * If our state indicates that FIN should be sent + * and we have not yet done so, or we're retransmitting the FIN, + * then we need to send. + */ + if (flags & TH_FIN && + ((tp->t_flags & TF_SENTFIN) == 0 || tp->snd_nxt == tp->snd_una)) + goto send; + + /* + * TCP window updates are not reliable, rather a polling protocol + * using ``persist'' packets is used to insure receipt of window + * updates. The three ``states'' for the output side are: + * idle not doing retransmits or persists + * persisting to move a small or zero window + * (re)transmitting and thereby not persisting + * + * tp->t_timer[TCPT_PERSIST] + * is set when we are in persist state. + * tp->t_force + * is set when we are called to send a persist packet. + * tp->t_timer[TCPT_REXMT] + * is set when we are retransmitting + * The output side is idle when both timers are zero. + * + * If send window is too small, there is data to transmit, and no + * retransmit or persist is pending, then go to persist state. + * If nothing happens soon, send when timer expires: + * if window is nonzero, transmit what we can, + * otherwise force out a byte. + */ + if (so->so_snd.sb_cc && tp->t_timer[TCPT_REXMT] == 0 && + tp->t_timer[TCPT_PERSIST] == 0) { + tp->t_rxtshift = 0; + tcp_setpersist(tp); + } + + /* + * No reason to send a segment, just return. + */ + tcpstat.tcps_didnuttin++; + + return (0); + +send: + /* + * Before ESTABLISHED, force sending of initial options + * unless TCP set not to do any options. + * NOTE: we assume that the IP/TCP header plus TCP options + * always fit in a single SLIRPmbuf, leaving room for a maximum + * link header, i.e. + * max_linkhdr + sizeof (struct tcpiphdr) + optlen <= MHLEN + */ + optlen = 0; + hdrlen = sizeof (struct tcpiphdr); + if (flags & TH_SYN) { + tp->snd_nxt = tp->iss; + if ((tp->t_flags & TF_NOOPT) == 0) { + u_int16_t mss; + + opt[0] = TCPOPT_MAXSEG; + opt[1] = 4; + mss = htons((u_int16_t) tcp_mss(tp, 0)); + memcpy((SLIRPcaddr_t)(opt + 2), (SLIRPcaddr_t)&mss, sizeof(mss)); + optlen = 4; + +/* if ((tp->t_flags & TF_REQ_SCALE) && + * ((flags & TH_ACK) == 0 || + * (tp->t_flags & TF_RCVD_SCALE))) { + * *((u_int32_t *) (opt + optlen)) = htonl( + * TCPOPT_NOP << 24 | + * TCPOPT_WINDOW << 16 | + * TCPOLEN_WINDOW << 8 | + * tp->request_r_scale); + * optlen += 4; + * } + */ + } + } + + /* + * Send a timestamp and echo-reply if this is a SYN and our side + * wants to use timestamps (TF_REQ_TSTMP is set) or both our side + * and our peer have sent timestamps in our SYN's. + */ +/* if ((tp->t_flags & (TF_REQ_TSTMP|TF_NOOPT)) == TF_REQ_TSTMP && + * (flags & TH_RST) == 0 && + * ((flags & (TH_SYN|TH_ACK)) == TH_SYN || + * (tp->t_flags & TF_RCVD_TSTMP))) { + * u_int32_t *lp = (u_int32_t *)(opt + optlen); + * + * / * Form timestamp option as shown in appendix A of RFC 1323. * / + * *lp++ = htonl(TCPOPT_TSTAMP_HDR); + * *lp++ = htonl(tcp_now); + * *lp = htonl(tp->ts_recent); + * optlen += TCPOLEN_TSTAMP_APPA; + * } + */ + hdrlen += optlen; + + /* + * Adjust data length if insertion of options will + * bump the packet length beyond the t_maxseg length. + */ + if (len > tp->t_maxseg - optlen) { + len = tp->t_maxseg - optlen; + sendalot = 1; + } + + /* + * Grab a header SLIRPmbuf, attaching a copy of data to + * be transmitted, and initialize the header from + * the template for sends on this connection. + */ + if (len) { + if (tp->t_force && len == 1) + tcpstat.tcps_sndprobe++; + else if (SEQ_LT(tp->snd_nxt, tp->snd_max)) { + tcpstat.tcps_sndrexmitpack++; + tcpstat.tcps_sndrexmitbyte += len; + } else { + tcpstat.tcps_sndpack++; + tcpstat.tcps_sndbyte += len; + } + + m = m_get(); + if (m == NULL) { +/* error = ENOBUFS; */ + error = 1; + goto out; + } + m->m_data += if_maxlinkhdr; + m->m_len = hdrlen; + + /* + * This will always succeed, since we make sure our SLIRPmbufs + * are big enough to hold one MSS packet + header + ... etc. + */ +/* if (len <= MHLEN - hdrlen - max_linkhdr) { */ + + sbcopy(&so->so_snd, off, (int) len, mtod(m, SLIRPcaddr_t) + hdrlen); + m->m_len += len; + +/* } else { + * m->m_next = m_copy(so->so_snd.sb_mb, off, (int) len); + * if (m->m_next == 0) + * len = 0; + * } + */ + /* + * If we're sending everything we've got, set PUSH. + * (This will keep happy those implementations which only + * give data to the user when a buffer fills or + * a PUSH comes in.) + */ + if (off + len == so->so_snd.sb_cc) + flags |= TH_PUSH; + } else { + if (tp->t_flags & TF_ACKNOW) + tcpstat.tcps_sndacks++; + else if (flags & (TH_SYN|TH_FIN|TH_RST)) + tcpstat.tcps_sndctrl++; + else if (SEQ_GT(tp->snd_up, tp->snd_una)) + tcpstat.tcps_sndurg++; + else + tcpstat.tcps_sndwinup++; + + m = m_get(); + if (m == NULL) { +/* error = ENOBUFS; */ + error = 1; + goto out; + } + m->m_data += if_maxlinkhdr; + m->m_len = hdrlen; + } + + ti = mtod(m, struct tcpiphdr *); + + memcpy((SLIRPcaddr_t)ti, &tp->t_template, sizeof (struct tcpiphdr)); + + /* + * Fill in fields, remembering maximum advertised + * window for use in delaying messages about window sizes. + * If resending a FIN, be sure not to use a new sequence number. + */ + if (flags & TH_FIN && tp->t_flags & TF_SENTFIN && + tp->snd_nxt == tp->snd_max) + tp->snd_nxt--; + /* + * If we are doing retransmissions, then snd_nxt will + * not reflect the first unsent octet. For ACK only + * packets, we do not want the sequence number of the + * retransmitted packet, we want the sequence number + * of the next unsent octet. So, if there is no data + * (and no SYN or FIN), use snd_max instead of snd_nxt + * when filling in ti_seq. But if we are in persist + * state, snd_max might reflect one byte beyond the + * right edge of the window, so use snd_nxt in that + * case, since we know we aren't doing a retransmission. + * (retransmit and persist are mutually exclusive...) + */ + if (len || (flags & (TH_SYN|TH_FIN)) || tp->t_timer[TCPT_PERSIST]) + ti->ti_seq = htonl(tp->snd_nxt); + else + ti->ti_seq = htonl(tp->snd_max); + ti->ti_ack = htonl(tp->rcv_nxt); + if (optlen) { + memcpy((SLIRPcaddr_t)(ti + 1), (SLIRPcaddr_t)opt, optlen); + ti->ti_off = (sizeof (struct tcphdr) + optlen) >> 2; + } + ti->ti_flags = flags; + /* + * Calculate receive window. Don't shrink window, + * but avoid silly window syndrome. + */ + if (win < (long)(so->so_rcv.sb_datalen / 4) && win < (long)tp->t_maxseg) + win = 0; + if (win > (long)TCP_MAXWIN << tp->rcv_scale) + win = (long)TCP_MAXWIN << tp->rcv_scale; + if (win < (long)(tp->rcv_adv - tp->rcv_nxt)) + win = (long)(tp->rcv_adv - tp->rcv_nxt); + ti->ti_win = htons((u_int16_t) (win>>tp->rcv_scale)); + + if (SEQ_GT(tp->snd_up, tp->snd_una)) { + ti->ti_urp = htons((u_int16_t)(tp->snd_up - ntohl(ti->ti_seq))); +#ifdef notdef + if (SEQ_GT(tp->snd_up, tp->snd_nxt)) { + ti->ti_urp = htons((u_int16_t)(tp->snd_up - tp->snd_nxt)); +#endif + ti->ti_flags |= TH_URG; + } else + /* + * If no urgent pointer to send, then we pull + * the urgent pointer to the left edge of the send window + * so that it doesn't drift into the send window on sequence + * number wraparound. + */ + tp->snd_up = tp->snd_una; /* drag it along */ + + /* + * Put TCP length in extended header, and then + * checksum extended header and data. + */ + if (len + optlen) + ti->ti_len = htons((u_int16_t)(sizeof (struct tcphdr) + + optlen + len)); + ti->ti_sum = cksum(m, (int)(hdrlen + len)); + + /* + * In transmit state, time the transmission and arrange for + * the retransmit. In persist state, just set snd_max. + */ + if (tp->t_force == 0 || tp->t_timer[TCPT_PERSIST] == 0) { + tcp_seq startseq = tp->snd_nxt; + + /* + * Advance snd_nxt over sequence space of this segment. + */ + if (flags & (TH_SYN|TH_FIN)) { + if (flags & TH_SYN) + tp->snd_nxt++; + if (flags & TH_FIN) { + tp->snd_nxt++; + tp->t_flags |= TF_SENTFIN; + } + } + tp->snd_nxt += len; + if (SEQ_GT(tp->snd_nxt, tp->snd_max)) { + tp->snd_max = tp->snd_nxt; + /* + * Time this transmission if not a retransmission and + * not currently timing anything. + */ + if (tp->t_rtt == 0) { + tp->t_rtt = 1; + tp->t_rtseq = startseq; + tcpstat.tcps_segstimed++; + } + } + + /* + * Set retransmit timer if not currently set, + * and not doing an ack or a keep-alive probe. + * Initial value for retransmit timer is smoothed + * round-trip time + 2 * round-trip time variance. + * Initialize shift counter which is used for backoff + * of retransmit time. + */ + if (tp->t_timer[TCPT_REXMT] == 0 && + tp->snd_nxt != tp->snd_una) { + tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; + if (tp->t_timer[TCPT_PERSIST]) { + tp->t_timer[TCPT_PERSIST] = 0; + tp->t_rxtshift = 0; + } + } + } else + if (SEQ_GT(tp->snd_nxt + len, tp->snd_max)) + tp->snd_max = tp->snd_nxt + len; + + /* + * Fill in IP length and desired time to live and + * send to IP level. There should be a better way + * to handle ttl and tos; we could keep them in + * the template, but need a way to checksum without them. + */ + m->m_len = hdrlen + len; /* XXX Needed? m_len should be correct */ + + { + + ((struct ip *)ti)->ip_len = m->m_len; + + ((struct ip *)ti)->ip_ttl = ip_defttl; + ((struct ip *)ti)->ip_tos = so->so_iptos; + +/* #if BSD >= 43 */ + /* Don't do IP options... */ +/* error = ip_output(m, tp->t_inpcb->inp_options, &tp->t_inpcb->inp_route, + * so->so_options & SO_DONTROUTE, 0); + */ + error = ip_output(so, m); + +/* #else + * error = ip_output(m, (struct SLIRPmbuf *)0, &tp->t_inpcb->inp_route, + * so->so_options & SO_DONTROUTE); + * #endif + */ + } + if (error) { +out: +/* if (error == ENOBUFS) { + * tcp_quench(tp->t_inpcb, 0); + * return (0); + * } + */ +/* if ((error == EHOSTUNREACH || error == ENETDOWN) + * && TCPS_HAVERCVDSYN(tp->t_state)) { + * tp->t_softerror = error; + * return (0); + * } + */ + return (error); + } + tcpstat.tcps_sndtotal++; + + /* + * Data sent (as far as we can tell). + * If this advertises a larger window than any other segment, + * then remember the size of the advertised window. + * Any pending ACK has now been sent. + */ + if (win > 0 && SEQ_GT(tp->rcv_nxt+win, tp->rcv_adv)) + tp->rcv_adv = tp->rcv_nxt + win; + tp->last_ack_sent = tp->rcv_nxt; + tp->t_flags &= ~(TF_ACKNOW|TF_DELACK); + if (sendalot) + goto again; + + return (0); +} + +void +tcp_setpersist(tp) + struct tcpcb *tp; +{ + int t = ((tp->t_srtt >> 2) + tp->t_rttvar) >> 1; + +/* if (tp->t_timer[TCPT_REXMT]) + * panic("tcp_output REXMT"); + */ + /* + * Start/restart persistence timer. + */ + TCPT_RANGESET(tp->t_timer[TCPT_PERSIST], + t * tcp_backoff[tp->t_rxtshift], + TCPTV_PERSMIN, TCPTV_PERSMAX); + if (tp->t_rxtshift < TCP_MAXRXTSHIFT) + tp->t_rxtshift++; +} diff --git a/src/slirp/tcp_subr.c b/src/slirp/tcp_subr.c new file mode 100644 index 000000000..cb0f0750a --- /dev/null +++ b/src/slirp/tcp_subr.c @@ -0,0 +1,1324 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tcp_subr.c 8.1 (Berkeley) 6/10/93 + * tcp_subr.c,v 1.5 1994/10/08 22:39:58 phk Exp + */ + +/* + * Changes and additions relating to SLiRP + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#define WANT_SYS_IOCTL_H +#include +#include "slirp.h" + +/* patchable/settable parameters for tcp */ +int tcp_mssdflt = TCP_MSS; +int tcp_rttdflt = TCPTV_SRTTDFLT / PR_SLOWHZ; +int tcp_do_rfc1323 = 0; /* Don't do rfc1323 performance enhancements */ +int tcp_rcvspace; /* You may want to change this */ +int tcp_sndspace; /* Keep small if you have an error prone link */ + +/* + * Tcp initialization + */ +void +tcp_init() +{ + tcp_iss = 1; /* wrong */ + tcb.so_next = tcb.so_prev = &tcb; + + /* tcp_rcvspace = our Window we advertise to the remote */ + tcp_rcvspace = TCP_RCVSPACE; + tcp_sndspace = TCP_SNDSPACE; + + /* Make sure tcp_sndspace is at least 2*MSS */ + if (tcp_sndspace < 2*(min(if_mtu, if_mru) - sizeof(struct tcpiphdr))) + tcp_sndspace = 2*(min(if_mtu, if_mru) - sizeof(struct tcpiphdr)); +} + +/* + * Create template to be used to send tcp packets on a connection. + * Call after host entry created, fills + * in a skeletal tcp/ip header, minimizing the amount of work + * necessary when the connection is used. + */ +/* struct tcpiphdr * */ +void +tcp_template(tp) + struct tcpcb *tp; +{ + struct SLIRPsocket *so = tp->t_socket; + struct tcpiphdr *n = &tp->t_template; + + n->ti_next = n->ti_prev = 0; + n->ti_x1 = 0; + n->ti_pr = IPPROTO_TCP; + n->ti_len = htons(sizeof (struct tcpiphdr) - sizeof (struct ip)); + n->ti_src = so->so_faddr; + n->ti_dst = so->so_laddr; + n->ti_sport = so->so_fport; + n->ti_dport = so->so_lport; + + n->ti_seq = 0; + n->ti_ack = 0; + n->ti_x2 = 0; + n->ti_off = 5; + n->ti_flags = 0; + n->ti_win = 0; + n->ti_sum = 0; + n->ti_urp = 0; +} + +/* + * Send a single message to the TCP at address specified by + * the given TCP/IP header. If m == 0, then we make a copy + * of the tcpiphdr at ti and send directly to the addressed host. + * This is used to force keep alive messages out using the TCP + * template for a connection tp->t_template. If flags are given + * then we send a message back to the TCP which originated the + * segment ti, and discard the SLIRPmbuf containing it and any other + * attached SLIRPmbufs. + * + * In any case the ack and sequence number of the transmitted + * segment are as specified by the parameters. + */ +void +tcp_respond(tp, ti, m, ack, seq, flags) + struct tcpcb *tp; + struct tcpiphdr *ti; + struct SLIRPmbuf *m; + tcp_seq ack, seq; + int flags; +{ + register int tlen; + int win = 0; + + DEBUG_CALL("tcp_respond"); + DEBUG_ARG("tp = %lx", (long)tp); + DEBUG_ARG("ti = %lx", (long)ti); + DEBUG_ARG("m = %lx", (long)m); + DEBUG_ARG("ack = %u", ack); + DEBUG_ARG("seq = %u", seq); + DEBUG_ARG("flags = %x", flags); + + if (tp) + win = sbspace(&tp->t_socket->so_rcv); + if (m == 0) { + if ((m = m_get()) == NULL) + return; +#ifdef TCP_COMPAT_42 + tlen = 1; +#else + tlen = 0; +#endif + m->m_data += if_maxlinkhdr; + *mtod(m, struct tcpiphdr *) = *ti; + ti = mtod(m, struct tcpiphdr *); + flags = TH_ACK; + } else { + /* + * ti points into m so the next line is just making + * the SLIRPmbuf point to ti + */ + m->m_data = (SLIRPcaddr_t)ti; + + m->m_len = sizeof (struct tcpiphdr); + tlen = 0; +#define xchg(a,b,type) { type t; t=a; a=b; b=t; } + xchg(ti->ti_dst.s_addr, ti->ti_src.s_addr, u_int32_t); + xchg(ti->ti_dport, ti->ti_sport, u_int16_t); +#undef xchg + } + ti->ti_len = htons((u_short)(sizeof (struct tcphdr) + tlen)); + tlen += sizeof (struct tcpiphdr); + m->m_len = tlen; + + ti->ti_next = ti->ti_prev = 0; + ti->ti_x1 = 0; + ti->ti_seq = htonl(seq); + ti->ti_ack = htonl(ack); + ti->ti_x2 = 0; + ti->ti_off = sizeof (struct tcphdr) >> 2; + ti->ti_flags = flags; + if (tp) + ti->ti_win = htons((u_int16_t) (win >> tp->rcv_scale)); + else + ti->ti_win = htons((u_int16_t)win); + ti->ti_urp = 0; + ti->ti_sum = 0; + ti->ti_sum = cksum(m, tlen); + ((struct ip *)ti)->ip_len = tlen; + + if(flags & TH_RST) + ((struct ip *)ti)->ip_ttl = MAXTTL; + else + ((struct ip *)ti)->ip_ttl = ip_defttl; + + (void) ip_output((struct SLIRPsocket *)0, m); +} + +/* + * Create a new TCP control block, making an + * empty reassembly queue and hooking it to the argument + * protocol control block. + */ +struct tcpcb * +tcp_newtcpcb(so) + struct SLIRPsocket *so; +{ + struct tcpcb *tp; + + tp = (struct tcpcb *)malloc(sizeof(*tp)); + if (tp == NULL) + return ((struct tcpcb *)0); + + memset((char *) tp, 0, sizeof(struct tcpcb)); + tp->seg_next = tp->seg_prev = (tcpiphdrp_32)tp; + tp->t_maxseg = tcp_mssdflt; + + tp->t_flags = tcp_do_rfc1323 ? (TF_REQ_SCALE|TF_REQ_TSTMP) : 0; + tp->t_socket = so; + + /* + * Init srtt to TCPTV_SRTTBASE (0), so we can tell that we have no + * rtt estimate. Set rttvar so that srtt + 2 * rttvar gives + * reasonable initial retransmit time. + */ + tp->t_srtt = TCPTV_SRTTBASE; + tp->t_rttvar = tcp_rttdflt * PR_SLOWHZ << 2; + tp->t_rttmin = TCPTV_MIN; + + TCPT_RANGESET(tp->t_rxtcur, + ((TCPTV_SRTTBASE >> 2) + (TCPTV_SRTTDFLT << 2)) >> 1, + TCPTV_MIN, TCPTV_REXMTMAX); + + tp->snd_cwnd = TCP_MAXWIN << TCP_MAX_WINSHIFT; + tp->snd_ssthresh = TCP_MAXWIN << TCP_MAX_WINSHIFT; + tp->t_state = TCPS_CLOSED; + + so->so_tcpcb = tp; + + return (tp); +} + +/* + * Drop a TCP connection, reporting + * the specified error. If connection is synchronized, + * then send a RST to peer. + */ +struct tcpcb *tcp_drop(struct tcpcb *tp, int err) +{ +/* tcp_drop(tp, errno) + struct tcpcb *tp; + int errno; +{ +*/ + + DEBUG_CALL("tcp_drop"); + DEBUG_ARG("tp = %lx", (long)tp); + DEBUG_ARG("errno = %d", errno); + + if (TCPS_HAVERCVDSYN(tp->t_state)) { + tp->t_state = TCPS_CLOSED; + (void) tcp_output(tp); + tcpstat.tcps_drops++; + } else + tcpstat.tcps_conndrops++; +/* if (errno == ETIMEDOUT && tp->t_softerror) + * errno = tp->t_softerror; + */ +/* so->so_error = errno; */ + return (tcp_close(tp)); +} + +/* + * Close a TCP control block: + * discard all space held by the tcp + * discard internet protocol block + * wake up any sleepers + */ +struct tcpcb * +tcp_close(tp) + struct tcpcb *tp; +{ + struct tcpiphdr *t; + struct SLIRPsocket *so = tp->t_socket; + struct SLIRPmbuf *m; + + DEBUG_CALL("tcp_close"); + DEBUG_ARG("tp = %lx", (long )tp); + + /* free the reassembly queue, if any */ + t = (struct tcpiphdr *) tp->seg_next; + while (t != (struct tcpiphdr *)tp) { + t = (struct tcpiphdr *)t->ti_next; + m = (struct SLIRPmbuf *) REASS_MBUF((struct tcpiphdr *)t->ti_prev); + remque_32((struct tcpiphdr *) t->ti_prev); + m_freem(m); + } + /* It's static */ +/* if (tp->t_template) + * (void) m_free(dtom(tp->t_template)); + */ +/* free(tp, M_PCB); */ + free(tp); + so->so_tcpcb = 0; + soisfdisconnected(so); + /* clobber input socket cache if we're closing the cached connection */ + if (so == tcp_last_so) + tcp_last_so = &tcb; + closesocket(so->s); + sbfree(&so->so_rcv); + sbfree(&so->so_snd); + sofree(so); + tcpstat.tcps_closed++; + return ((struct tcpcb *)0); +} + +void +tcp_drain() +{ + /* XXX */ +} + +/* + * When a source quench is received, close congestion window + * to one segment. We will gradually open it again as we proceed. + */ + +#ifdef notdef + +void +tcp_quench(i, errno) + + int errno; +{ + struct tcpcb *tp = intotcpcb(inp); + + if (tp) + tp->snd_cwnd = tp->t_maxseg; +} + +#endif /* notdef */ + +/* + * TCP protocol interface to socket abstraction. + */ + +/* + * User issued close, and wish to trail through shutdown states: + * if never received SYN, just forget it. If got a SYN from peer, + * but haven't sent FIN, then go to FIN_WAIT_1 state to send peer a FIN. + * If already got a FIN from peer, then almost done; go to LAST_ACK + * state. In all other cases, have already sent FIN to peer (e.g. + * after PRU_SHUTDOWN), and just have to play tedious game waiting + * for peer to send FIN or not respond to keep-alives, etc. + * We can let the user exit from the close as soon as the FIN is acked. + */ +void +tcp_sockclosed(tp) + struct tcpcb *tp; +{ + + DEBUG_CALL("tcp_sockclosed"); + DEBUG_ARG("tp = %lx", (long)tp); + + switch (tp->t_state) { + + case TCPS_CLOSED: + case TCPS_LISTEN: + case TCPS_SYN_SENT: + tp->t_state = TCPS_CLOSED; + tp = tcp_close(tp); + break; + + case TCPS_SYN_RECEIVED: + case TCPS_ESTABLISHED: + tp->t_state = TCPS_FIN_WAIT_1; + break; + + case TCPS_CLOSE_WAIT: + tp->t_state = TCPS_LAST_ACK; + break; + } +/* soisfdisconnecting(tp->t_socket); */ + if (tp && tp->t_state >= TCPS_FIN_WAIT_2) + soisfdisconnected(tp->t_socket); + if (tp) + tcp_output(tp); +} + +/* + * Connect to a host on the Internet + * Called by tcp_input + * Only do a connect, the tcp fields will be set in tcp_input + * return 0 if there's a result of the connect, + * else return -1 means we're still connecting + * The return value is almost always -1 since the socket is + * nonblocking. Connect returns after the SYN is sent, and does + * not wait for ACK+SYN. + */ +int tcp_fconnect(so) + struct SLIRPsocket *so; +{ + int ret=0; + + DEBUG_CALL("tcp_fconnect"); + DEBUG_ARG("so = %lx", (long )so); + + if( (ret=so->s=socket(AF_INET,SOCK_STREAM,0)) >= 0) { + int opt, s=so->s; + struct sockaddr_in addr; + memset(&addr, 0, sizeof(struct sockaddr_in)); + + fd_nonblock(s); + opt = 1; + setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(opt )); + opt = 1; + setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(opt )); + + addr.sin_family = AF_INET; + if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { + /* It's an alias */ + switch(ntohl(so->so_faddr.s_addr) & 0xff) { + case CTL_DNS: + addr.sin_addr = dns_addr; + break; + case CTL_ALIAS: + default: + addr.sin_addr = loopback_addr; + break; + } + } else + addr.sin_addr = so->so_faddr; + addr.sin_port = so->so_fport; + + DEBUG_MISC((dfd, " connect()ing, addr.sin_port=%d, " + "addr.sin_addr.s_addr=%.16s\n", + ntohs(addr.sin_port), inet_ntoa(addr.sin_addr))); + /* We don't care what port we get */ + ret = connect(s,(struct sockaddr *)&addr,sizeof (addr)); + + /* + * If it's not in progress, it failed, so we just return 0, + * without clearing SS_NOFDREF + */ + soisfconnecting(so); + } + + return(ret); +} + +/* + * Accept the socket and connect to the local-host + * + * We have a problem. The correct thing to do would be + * to first connect to the local-host, and only if the + * connection is accepted, then do an accept() here. + * But, a) we need to know who's trying to connect + * to the socket to be able to SYN the local-host, and + * b) we are already connected to the foreign host by + * the time it gets to accept(), so... We simply accept + * here and SYN the local-host. + */ +void +tcp_connect(inso) + struct SLIRPsocket *inso; +{ + struct SLIRPsocket *so; + struct sockaddr_in addr; + socklen_t addrlen = sizeof(struct sockaddr_in); + struct tcpcb *tp; + int s, opt; + + DEBUG_CALL("tcp_connect"); + DEBUG_ARG("inso = %lx", (long)inso); + + /* + * If it's an SS_ACCEPTONCE socket, no need to socreate() + * another socket, just use the accept() socket. + */ + if (inso->so_state & SS_FACCEPTONCE) { + /* FACCEPTONCE already have a tcpcb */ + so = inso; + } else { + if ((so = socreate()) == NULL) { + /* If it failed, get rid of the pending connection */ + closesocket(accept(inso->s,(struct sockaddr *)&addr,&addrlen)); + return; + } + if (tcp_attach(so) < 0) { + free(so); /* NOT sofree */ + return; + } + so->so_laddr = inso->so_laddr; + so->so_lport = inso->so_lport; + } + + (void) tcp_mss(sototcpcb(so), 0); + + if ((s = accept(inso->s,(struct sockaddr *)&addr,&addrlen)) < 0) { + tcp_close(sototcpcb(so)); /* This will sofree() as well */ + return; + } + fd_nonblock(s); + opt = 1; + setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); + opt = 1; + setsockopt(s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); + opt = 1; + setsockopt(s,IPPROTO_TCP,TCP_NODELAY,(char *)&opt,sizeof(int)); + + so->so_fport = addr.sin_port; + so->so_faddr = addr.sin_addr; + /* Translate connections from localhost to the real hostname */ + if (so->so_faddr.s_addr == 0 || so->so_faddr.s_addr == loopback_addr.s_addr) + so->so_faddr = alias_addr; + + /* Close the accept() socket, set right state */ + if (inso->so_state & SS_FACCEPTONCE) { + closesocket(so->s); /* If we only accept once, close the accept() socket */ + so->so_state = SS_NOFDREF; /* Don't select it yet, even though we have an FD */ + /* if it's not FACCEPTONCE, it's already NOFDREF */ + } + so->s = s; + + so->so_iptos = tcp_tos(so); + tp = sototcpcb(so); + + tcp_template(tp); + + /* Compute window scaling to request. */ +/* while (tp->request_r_scale < TCP_MAX_WINSHIFT && + * (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat) + * tp->request_r_scale++; + */ + +/* soisconnecting(so); */ /* NOFDREF used instead */ + tcpstat.tcps_connattempt++; + + tp->t_state = TCPS_SYN_SENT; + tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; + tp->iss = tcp_iss; + tcp_iss += TCP_ISSINCR/2; + tcp_sendseqinit(tp); + tcp_output(tp); +} + +/* + * Attach a TCPCB to a socket. + */ +int +tcp_attach(so) + struct SLIRPsocket *so; +{ + if ((so->so_tcpcb = tcp_newtcpcb(so)) == NULL) + return -1; + + insque(so, &tcb); + + return 0; +} + +/* + * Set the socket's type of service field + */ +struct tos_t tcptos[] = { + {0, 20, IPTOS_THROUGHPUT, 0}, /* ftp data */ + {21, 21, IPTOS_LOWDELAY, EMU_FTP}, /* ftp control */ + {0, 23, IPTOS_LOWDELAY, 0}, /* telnet */ + {0, 80, IPTOS_THROUGHPUT, 0}, /* WWW */ + {0, 513, IPTOS_LOWDELAY, EMU_RLOGIN|EMU_NOCONNECT}, /* rlogin */ + {0, 514, IPTOS_LOWDELAY, EMU_RSH|EMU_NOCONNECT}, /* shell */ + {0, 544, IPTOS_LOWDELAY, EMU_KSH}, /* kshell */ + {0, 543, IPTOS_LOWDELAY, 0}, /* klogin */ + {0, 6667, IPTOS_THROUGHPUT, EMU_IRC}, /* IRC */ + {0, 6668, IPTOS_THROUGHPUT, EMU_IRC}, /* IRC undernet */ + {0, 7070, IPTOS_LOWDELAY, EMU_REALAUDIO }, /* RealAudio control */ + {0, 113, IPTOS_LOWDELAY, EMU_IDENT }, /* identd protocol */ + {0, 0, 0, 0} +}; + +struct emu_t *tcpemu = 0; + +/* + * Return TOS according to the above table + */ +u_int8_t +tcp_tos(so) + struct SLIRPsocket *so; +{ + int i = 0; + struct emu_t *emup; + + while(tcptos[i].tos) { + if ((tcptos[i].fport && (ntohs(so->so_fport) == tcptos[i].fport)) || + (tcptos[i].lport && (ntohs(so->so_lport) == tcptos[i].lport))) { + so->so_emu = tcptos[i].emu; + return tcptos[i].tos; + } + i++; + } + + /* Nope, lets see if there's a user-added one */ + for (emup = tcpemu; emup; emup = emup->next) { + if ((emup->fport && (ntohs(so->so_fport) == emup->fport)) || + (emup->lport && (ntohs(so->so_lport) == emup->lport))) { + so->so_emu = emup->emu; + return emup->tos; + } + } + + return 0; +} + +int do_echo = -1; + +/* + * Emulate programs that try and connect to us + * This includes ftp (the data connection is + * initiated by the server) and IRC (DCC CHAT and + * DCC SEND) for now + * + * NOTE: It's possible to crash SLiRP by sending it + * unstandard strings to emulate... if this is a problem, + * more checks are needed here + * + * XXX Assumes the whole command came in one packet + * + * XXX Some ftp clients will have their TOS set to + * LOWDELAY and so Nagel will kick in. Because of this, + * we'll get the first letter, followed by the rest, so + * we simply scan for ORT instead of PORT... + * DCC doesn't have this problem because there's other stuff + * in the packet before the DCC command. + * + * Return 1 if the SLIRPmbuf m is still valid and should be + * sbappend()ed + * + * NOTE: if you return 0 you MUST m_free() the SLIRPmbuf! + */ +int +tcp_emu(so, m) + struct SLIRPsocket *so; + struct SLIRPmbuf *m; +{ + u_int n1, n2, n3, n4, n5, n6; + char buff[256]; + u_int32_t laddr; + u_int lport; + char *bptr; + + DEBUG_CALL("tcp_emu"); + DEBUG_ARG("so = %lx", (long)so); + DEBUG_ARG("m = %lx", (long)m); + + switch(so->so_emu) { + int x, i; + + case EMU_IDENT: + /* + * Identification protocol as per rfc-1413 + */ + + { + struct SLIRPsocket *tmpso; + struct sockaddr_in addr; + socklen_t addrlen = sizeof(struct sockaddr_in); + struct sbuf *so_rcv = &so->so_rcv; + + memcpy(so_rcv->sb_wptr, m->m_data, m->m_len); + so_rcv->sb_wptr += m->m_len; + so_rcv->sb_rptr += m->m_len; + m->m_data[m->m_len] = 0; /* NULL terminate */ + if (strchr(m->m_data, '\r') || strchr(m->m_data, '\n')) { + if (sscanf(so_rcv->sb_data, "%d%*[ ,]%d", &n1, &n2) == 2) { + HTONS(n1); + HTONS(n2); + /* n2 is the one on our host */ + for (tmpso = tcb.so_next; tmpso != &tcb; tmpso = tmpso->so_next) { + if (tmpso->so_laddr.s_addr == so->so_laddr.s_addr && + tmpso->so_lport == n2 && + tmpso->so_faddr.s_addr == so->so_faddr.s_addr && + tmpso->so_fport == n1) { + if (getsockname(tmpso->s, + (struct sockaddr *)&addr, &addrlen) == 0) + n2 = ntohs(addr.sin_port); + break; + } + } + } + so_rcv->sb_cc = sprintf(so_rcv->sb_data, "%d,%d\r\n", n1, n2); + so_rcv->sb_rptr = so_rcv->sb_data; + so_rcv->sb_wptr = so_rcv->sb_data + so_rcv->sb_cc; + } + m_free(m); + return 0; + } + +#if 0 + case EMU_RLOGIN: + /* + * Rlogin emulation + * First we accumulate all the initial option negotiation, + * then fork_exec() rlogin according to the options + */ + { + int i, i2, n; + char *ptr; + char args[100]; + char term[100]; + struct sbuf *so_snd = &so->so_snd; + struct sbuf *so_rcv = &so->so_rcv; + + /* First check if they have a priveladged port, or too much data has arrived */ + if (ntohs(so->so_lport) > 1023 || ntohs(so->so_lport) < 512 || + (m->m_len + so_rcv->sb_wptr) > (so_rcv->sb_data + so_rcv->sb_datalen)) { + memcpy(so_snd->sb_wptr, "Permission denied\n", 18); + so_snd->sb_wptr += 18; + so_snd->sb_cc += 18; + tcp_sockclosed(sototcpcb(so)); + m_free(m); + return 0; + } + + /* Append the current data */ + memcpy(so_rcv->sb_wptr, m->m_data, m->m_len); + so_rcv->sb_wptr += m->m_len; + so_rcv->sb_rptr += m->m_len; + m_free(m); + + /* + * Check if we have all the initial options, + * and build argument list to rlogin while we're here + */ + n = 0; + ptr = so_rcv->sb_data; + args[0] = 0; + term[0] = 0; + while (ptr < so_rcv->sb_wptr) { + if (*ptr++ == 0) { + n++; + if (n == 2) { + sprintf(args, "rlogin -l %s %s", + ptr, inet_ntoa(so->so_faddr)); + } else if (n == 3) { + i2 = so_rcv->sb_wptr - ptr; + for (i = 0; i < i2; i++) { + if (ptr[i] == '/') { + ptr[i] = 0; +#ifdef HAVE_SETENV + sprintf(term, "%s", ptr); +#else + sprintf(term, "TERM=%s", ptr); +#endif + ptr[i] = '/'; + break; + } + } + } + } + } + + if (n != 4) + return 0; + + /* We have it, set our term variable and fork_exec() */ +#ifdef HAVE_SETENV + setenv("TERM", term, 1); +#else + putenv(term); +#endif + fork_exec(so, args, 2); + term[0] = 0; + so->so_emu = 0; + + /* And finally, send the client a 0 character */ + so_snd->sb_wptr[0] = 0; + so_snd->sb_wptr++; + so_snd->sb_cc++; + + return 0; + } + + case EMU_RSH: + /* + * rsh emulation + * First we accumulate all the initial option negotiation, + * then rsh_exec() rsh according to the options + */ + { + int n; + char *ptr; + char *user; + char *args; + struct sbuf *so_snd = &so->so_snd; + struct sbuf *so_rcv = &so->so_rcv; + + /* First check if they have a priveladged port, or too much data has arrived */ + if (ntohs(so->so_lport) > 1023 || ntohs(so->so_lport) < 512 || + (m->m_len + so_rcv->sb_wptr) > (so_rcv->sb_data + so_rcv->sb_datalen)) { + memcpy(so_snd->sb_wptr, "Permission denied\n", 18); + so_snd->sb_wptr += 18; + so_snd->sb_cc += 18; + tcp_sockclosed(sototcpcb(so)); + m_free(m); + return 0; + } + + /* Append the current data */ + memcpy(so_rcv->sb_wptr, m->m_data, m->m_len); + so_rcv->sb_wptr += m->m_len; + so_rcv->sb_rptr += m->m_len; + m_free(m); + + /* + * Check if we have all the initial options, + * and build argument list to rlogin while we're here + */ + n = 0; + ptr = so_rcv->sb_data; + user=""; + args=""; + if (so->extra==NULL) { + struct SLIRPsocket *ns; + struct tcpcb* tp; + int port=atoi(ptr); + if (port <= 0) return 0; + if (port > 1023 || port < 512) { + memcpy(so_snd->sb_wptr, "Permission denied\n", 18); + so_snd->sb_wptr += 18; + so_snd->sb_cc += 18; + tcp_sockclosed(sototcpcb(so)); + return 0; + } + if ((ns=socreate()) == NULL) + return 0; + if (tcp_attach(ns)<0) { + free(ns); + return 0; + } + + ns->so_laddr=so->so_laddr; + ns->so_lport=htons(port); + + (void) tcp_mss(sototcpcb(ns), 0); + + ns->so_faddr=so->so_faddr; + ns->so_fport=htons(IPPORT_RESERVED-1); /* Use a fake port. */ + + if (ns->so_faddr.s_addr == 0 || + ns->so_faddr.s_addr == loopback_addr.s_addr) + ns->so_faddr = alias_addr; + + ns->so_iptos = tcp_tos(ns); + tp = sototcpcb(ns); + + tcp_template(tp); + + /* Compute window scaling to request. */ + /* while (tp->request_r_scale < TCP_MAX_WINSHIFT && + * (TCP_MAXWIN << tp->request_r_scale) < so->so_rcv.sb_hiwat) + * tp->request_r_scale++; + */ + + /*soisfconnecting(ns);*/ + + tcpstat.tcps_connattempt++; + + tp->t_state = TCPS_SYN_SENT; + tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT; + tp->iss = tcp_iss; + tcp_iss += TCP_ISSINCR/2; + tcp_sendseqinit(tp); + tcp_output(tp); + so->extra=ns; + } + while (ptr < so_rcv->sb_wptr) { + if (*ptr++ == 0) { + n++; + if (n == 2) { + user=ptr; + } else if (n == 3) { + args=ptr; + } + } + } + + if (n != 4) + return 0; + + rsh_exec(so,so->extra, user, inet_ntoa(so->so_faddr), args); + so->so_emu = 0; + so->extra=NULL; + + /* And finally, send the client a 0 character */ + so_snd->sb_wptr[0] = 0; + so_snd->sb_wptr++; + so_snd->sb_cc++; + + return 0; + } + + case EMU_CTL: + { + int num; + struct sbuf *so_snd = &so->so_snd; + struct sbuf *so_rcv = &so->so_rcv; + + /* + * If there is binary data here, we save it in so->so_m + */ + if (!so->so_m) { + int rxlen; + char *rxdata; + rxdata=mtod(m, char *); + for (rxlen=m->m_len; rxlen; rxlen--) { + if (*rxdata++ & 0x80) { + so->so_m = m; + return 0; + } + } + } /* if(so->so_m==NULL) */ + + /* + * Append the line + */ + sbappendsb(so_rcv, m); + + /* To avoid going over the edge of the buffer, we reset it */ + if (so_snd->sb_cc == 0) + so_snd->sb_wptr = so_snd->sb_rptr = so_snd->sb_data; + + /* + * A bit of a hack: + * If the first packet we get here is 1 byte long, then it + * was done in telnet character mode, therefore we must echo + * the characters as they come. Otherwise, we echo nothing, + * because in linemode, the line is already echoed + * XXX two or more control connections won't work + */ + if (do_echo == -1) { + if (m->m_len == 1) do_echo = 1; + else do_echo = 0; + } + if (do_echo) { + sbappendsb(so_snd, m); + m_free(m); + tcp_output(sototcpcb(so)); /* XXX */ + } else + m_free(m); + + num = 0; + while (num < so->so_rcv.sb_cc) { + if (*(so->so_rcv.sb_rptr + num) == '\n' || + *(so->so_rcv.sb_rptr + num) == '\r') { + int n; + + *(so_rcv->sb_rptr + num) = 0; + if (ctl_password && !ctl_password_ok) { + /* Need a password */ + if (sscanf(so_rcv->sb_rptr, "pass %256s", buff) == 1) { + if (strcmp(buff, ctl_password) == 0) { + ctl_password_ok = 1; + n = sprintf(so_snd->sb_wptr, + "Password OK.\r\n"); + goto do_prompt; + } + } + n = sprintf(so_snd->sb_wptr, + "Error: Password required, log on with \"pass PASSWORD\"\r\n"); + goto do_prompt; + } + cfg_quitting = 0; + n = do_config(so_rcv->sb_rptr, so, PRN_SPRINTF); + if (!cfg_quitting) { + /* Register the printed data */ +do_prompt: + so_snd->sb_cc += n; + so_snd->sb_wptr += n; + /* Add prompt */ + n = sprintf(so_snd->sb_wptr, "Slirp> "); + so_snd->sb_cc += n; + so_snd->sb_wptr += n; + } + /* Drop so_rcv data */ + so_rcv->sb_cc = 0; + so_rcv->sb_wptr = so_rcv->sb_rptr = so_rcv->sb_data; + tcp_output(sototcpcb(so)); /* Send the reply */ + } + num++; + } + return 0; + } +#endif + case EMU_FTP: /* ftp */ + *(m->m_data+m->m_len) = 0; /* NULL terminate for strstr */ + if ((bptr = (char *)strstr(m->m_data, "ORT")) != NULL) { + /* + * Need to emulate the PORT command + */ + x = sscanf(bptr, "ORT %d,%d,%d,%d,%d,%d\r\n%256[^\177]", + &n1, &n2, &n3, &n4, &n5, &n6, buff); + if (x < 6) + return 1; + + laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4)); + lport = htons((n5 << 8) | (n6)); + + if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL) + return 1; + + n6 = ntohs(so->so_fport); + + n5 = (n6 >> 8) & 0xff; + n6 &= 0xff; + + laddr = ntohl(so->so_faddr.s_addr); + + n1 = ((laddr >> 24) & 0xff); + n2 = ((laddr >> 16) & 0xff); + n3 = ((laddr >> 8) & 0xff); + n4 = (laddr & 0xff); + + m->m_len = bptr - m->m_data; /* Adjust length */ + m->m_len += sprintf(bptr,"ORT %d,%d,%d,%d,%d,%d\r\n%s", + n1, n2, n3, n4, n5, n6, x==7?buff:""); + return 1; + } else if ((bptr = (char *)strstr(m->m_data, "27 Entering")) != NULL) { + /* + * Need to emulate the PASV response + */ + x = sscanf(bptr, "27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%256[^\177]", + &n1, &n2, &n3, &n4, &n5, &n6, buff); + if (x < 6) + return 1; + + laddr = htonl((n1 << 24) | (n2 << 16) | (n3 << 8) | (n4)); + lport = htons((n5 << 8) | (n6)); + + if ((so = solisten(0, laddr, lport, SS_FACCEPTONCE)) == NULL) + return 1; + + n6 = ntohs(so->so_fport); + + n5 = (n6 >> 8) & 0xff; + n6 &= 0xff; + + laddr = ntohl(so->so_faddr.s_addr); + + n1 = ((laddr >> 24) & 0xff); + n2 = ((laddr >> 16) & 0xff); + n3 = ((laddr >> 8) & 0xff); + n4 = (laddr & 0xff); + + m->m_len = bptr - m->m_data; /* Adjust length */ + m->m_len += sprintf(bptr,"27 Entering Passive Mode (%d,%d,%d,%d,%d,%d)\r\n%s", + n1, n2, n3, n4, n5, n6, x==7?buff:""); + + return 1; + } + + return 1; + + case EMU_KSH: + /* + * The kshell (Kerberos rsh) and shell services both pass + * a local port port number to carry signals to the server + * and stderr to the client. It is passed at the beginning + * of the connection as a NUL-terminated decimal ASCII string. + */ + so->so_emu = 0; + for (lport = 0, i = 0; i < m->m_len-1; ++i) { + if (m->m_data[i] < '0' || m->m_data[i] > '9') + return 1; /* invalid number */ + lport *= 10; + lport += m->m_data[i] - '0'; + } + if (m->m_data[m->m_len-1] == '\0' && lport != 0 && + (so = solisten(0, so->so_laddr.s_addr, htons(lport), SS_FACCEPTONCE)) != NULL) + m->m_len = sprintf(m->m_data, "%d", ntohs(so->so_fport))+1; + return 1; + + case EMU_IRC: + /* + * Need to emulate DCC CHAT, DCC SEND and DCC MOVE + */ + *(m->m_data+m->m_len) = 0; /* NULL terminate the string for strstr */ + if ((bptr = (char *)strstr(m->m_data, "DCC")) == NULL) + return 1; + + /* The %256s is for the broken mIRC */ + if (sscanf(bptr, "DCC CHAT %256s %u %u", buff, &laddr, &lport) == 3) { + if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL) + return 1; + + m->m_len = bptr - m->m_data; /* Adjust length */ + m->m_len += sprintf(bptr, "DCC CHAT chat %lu %u%c\n", + (unsigned long)ntohl(so->so_faddr.s_addr), + ntohs(so->so_fport), 1); + } else if (sscanf(bptr, "DCC SEND %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) { + if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL) + return 1; + + m->m_len = bptr - m->m_data; /* Adjust length */ + m->m_len += sprintf(bptr, "DCC SEND %s %lu %u %u%c\n", + buff, (unsigned long)ntohl(so->so_faddr.s_addr), + ntohs(so->so_fport), n1, 1); + } else if (sscanf(bptr, "DCC MOVE %256s %u %u %u", buff, &laddr, &lport, &n1) == 4) { + if ((so = solisten(0, htonl(laddr), htons(lport), SS_FACCEPTONCE)) == NULL) + return 1; + + m->m_len = bptr - m->m_data; /* Adjust length */ + m->m_len += sprintf(bptr, "DCC MOVE %s %lu %u %u%c\n", + buff, (unsigned long)ntohl(so->so_faddr.s_addr), + ntohs(so->so_fport), n1, 1); + } + return 1; + + case EMU_REALAUDIO: + /* + * RealAudio emulation - JP. We must try to parse the incoming + * data and try to find the two characters that contain the + * port number. Then we redirect an udp port and replace the + * number with the real port we got. + * + * The 1.0 beta versions of the player are not supported + * any more. + * + * A typical packet for player version 1.0 (release version): + * + * 0000:50 4E 41 00 05 + * 0000:00 01 00 02 1B D7 00 00 67 E6 6C DC 63 00 12 50 .....×..gælÜc..P + * 0010:4E 43 4C 49 45 4E 54 20 31 30 31 20 41 4C 50 48 NCLIENT 101 ALPH + * 0020:41 6C 00 00 52 00 17 72 61 66 69 6C 65 73 2F 76 Al..R..rafiles/v + * 0030:6F 61 2F 65 6E 67 6C 69 73 68 5F 2E 72 61 79 42 oa/english_.rayB + * + * Now the port number 0x1BD7 is found at offset 0x04 of the + * Now the port number 0x1BD7 is found at offset 0x04 of the + * second packet. This time we received five bytes first and + * then the rest. You never know how many bytes you get. + * + * A typical packet for player version 2.0 (beta): + * + * 0000:50 4E 41 00 06 00 02 00 00 00 01 00 02 1B C1 00 PNA...........Á. + * 0010:00 67 75 78 F5 63 00 0A 57 69 6E 32 2E 30 2E 30 .guxõc..Win2.0.0 + * 0020:2E 35 6C 00 00 52 00 1C 72 61 66 69 6C 65 73 2F .5l..R..rafiles/ + * 0030:77 65 62 73 69 74 65 2F 32 30 72 65 6C 65 61 73 website/20releas + * 0040:65 2E 72 61 79 53 00 00 06 36 42 e.rayS...6B + * + * Port number 0x1BC1 is found at offset 0x0d. + * + * This is just a horrible switch statement. Variable ra tells + * us where we're going. + */ + + bptr = m->m_data; + while (bptr < m->m_data + m->m_len) { + u_short p; + static int ra = 0; + char ra_tbl[4]; + + ra_tbl[0] = 0x50; + ra_tbl[1] = 0x4e; + ra_tbl[2] = 0x41; + ra_tbl[3] = 0; + + switch (ra) { + case 0: + case 2: + case 3: + if (*bptr++ != ra_tbl[ra]) { + ra = 0; + continue; + } + break; + + case 1: + /* + * We may get 0x50 several times, ignore them + */ + if (*bptr == 0x50) { + ra = 1; + bptr++; + continue; + } else if (*bptr++ != ra_tbl[ra]) { + ra = 0; + continue; + } + break; + + case 4: + /* + * skip version number + */ + bptr++; + break; + + case 5: + /* + * The difference between versions 1.0 and + * 2.0 is here. For future versions of + * the player this may need to be modified. + */ + if (*(bptr + 1) == 0x02) + bptr += 8; + else + bptr += 4; + break; + + case 6: + /* This is the field containing the port + * number that RA-player is listening to. + */ + lport = (((u_char*)bptr)[0] << 8) + + ((u_char *)bptr)[1]; + if (lport < 6970) + lport += 256; /* don't know why */ + if (lport < 6970 || lport > 7170) + return 1; /* failed */ + + /* try to get udp port between 6970 - 7170 */ + for (p = 6970; p < 7071; p++) { + if (udp_listen( htons(p), + so->so_laddr.s_addr, + htons(lport), + SS_FACCEPTONCE)) { + break; + } + } + if (p == 7071) + p = 0; + *(u_char *)bptr++ = (p >> 8) & 0xff; + *(u_char *)bptr++ = p & 0xff; + ra = 0; + return 1; /* port redirected, we're done */ + break; + + default: + ra = 0; + } + ra++; + } + return 1; + + default: + /* Ooops, not emulated, won't call tcp_emu again */ + so->so_emu = 0; + return 1; + } +} + +/* + * Do misc. config of SLiRP while its running. + * Return 0 if this connections is to be closed, 1 otherwise, + * return 2 if this is a command-line connection + */ +int +tcp_ctl(so) + struct SLIRPsocket *so; +{ + struct sbuf *sb = &so->so_snd; + int command; + struct ex_list *ex_ptr; + int do_pty; + // struct SLIRPsocket *tmpso; + + DEBUG_CALL("tcp_ctl"); + DEBUG_ARG("so = %lx", (long )so); + +#if 0 + /* + * Check if they're authorised + */ + if (ctl_addr.s_addr && (ctl_addr.s_addr == -1 || (so->so_laddr.s_addr != ctl_addr.s_addr))) { + sb->sb_cc = sprintf(sb->sb_wptr,"Error: Permission denied.\r\n"); + sb->sb_wptr += sb->sb_cc; + return 0; + } +#endif + command = (ntohl(so->so_faddr.s_addr) & 0xff); + + switch(command) { + default: /* Check for exec's */ + + /* + * Check if it's pty_exec + */ + for (ex_ptr = exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) { + if (ex_ptr->ex_fport == so->so_fport && + command == ex_ptr->ex_addr) { + do_pty = ex_ptr->ex_pty; + goto do_exec; + } + } + + /* + * Nothing bound.. + */ + /* tcp_fconnect(so); */ + + /* FALLTHROUGH */ + case CTL_ALIAS: + sb->sb_cc = sprintf(sb->sb_wptr, + "Error: No application configured.\r\n"); + sb->sb_wptr += sb->sb_cc; + return(0); + + do_exec: + DEBUG_MISC((dfd, " executing %s \n",ex_ptr->ex_exec)); + return(fork_exec(so, ex_ptr->ex_exec, do_pty)); + +#if 0 + case CTL_CMD: + for (tmpso = tcb.so_next; tmpso != &tcb; tmpso = tmpso->so_next) { + if (tmpso->so_emu == EMU_CTL && + !(tmpso->so_tcpcb? + (tmpso->so_tcpcb->t_state & (TCPS_TIME_WAIT|TCPS_LAST_ACK)) + :0)) { + /* Ooops, control connection already active */ + sb->sb_cc = sprintf(sb->sb_wptr,"Sorry, already connected.\r\n"); + sb->sb_wptr += sb->sb_cc; + return 0; + } + } + so->so_emu = EMU_CTL; + ctl_password_ok = 0; + sb->sb_cc = sprintf(sb->sb_wptr, "Slirp command-line ready (type \"help\" for help).\r\nSlirp> "); + sb->sb_wptr += sb->sb_cc; + do_echo=-1; + return(2); +#endif + } +} diff --git a/src/slirp/tcp_timer.c b/src/slirp/tcp_timer.c new file mode 100644 index 000000000..892b222c7 --- /dev/null +++ b/src/slirp/tcp_timer.c @@ -0,0 +1,322 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tcp_timer.c 8.1 (Berkeley) 6/10/93 + * tcp_timer.c,v 1.2 1994/08/02 07:49:10 davidg Exp + */ + +#include "slirp.h" + +int tcp_keepidle = TCPTV_KEEP_IDLE; +int tcp_keepintvl = TCPTV_KEEPINTVL; +int tcp_maxidle; +int so_options = DO_KEEPALIVE; + +struct tcpstat tcpstat; /* tcp statistics */ +u_int32_t tcp_now; /* for RFC 1323 timestamps */ + +/* + * Fast timeout routine for processing delayed acks + */ +void +tcp_fasttimo() +{ + register struct SLIRPsocket *so; + register struct tcpcb *tp; + + DEBUG_CALL("tcp_fasttimo"); + + so = tcb.so_next; + if (so) + for (; so != &tcb; so = so->so_next) + if ((tp = (struct tcpcb *)so->so_tcpcb) && + (tp->t_flags & TF_DELACK)) { + tp->t_flags &= ~TF_DELACK; + tp->t_flags |= TF_ACKNOW; + tcpstat.tcps_delack++; + (void) tcp_output(tp); + } +} + +/* + * Tcp protocol timeout routine called every 500 ms. + * Updates the timers in all active tcb's and + * causes finite state machine actions if timers expire. + */ +void +tcp_slowtimo() +{ + register struct SLIRPsocket *ip, *ipnxt; + register struct tcpcb *tp; + register int i; + + DEBUG_CALL("tcp_slowtimo"); + + tcp_maxidle = TCPTV_KEEPCNT * tcp_keepintvl; + /* + * Search through tcb's and update active timers. + */ + ip = tcb.so_next; + if (ip == 0) + return; + for (; ip != &tcb; ip = ipnxt) { + ipnxt = ip->so_next; + tp = sototcpcb(ip); + if (tp == 0) + continue; + for (i = 0; i < TCPT_NTIMERS; i++) { + if (tp->t_timer[i] && --tp->t_timer[i] == 0) { + tcp_timers(tp,i); + if (ipnxt->so_prev != ip) + goto tpgone; + } + } + tp->t_idle++; + if (tp->t_rtt) + tp->t_rtt++; +tpgone: + ; + } + tcp_iss += TCP_ISSINCR/PR_SLOWHZ; /* increment iss */ +#ifdef TCP_COMPAT_42 + if ((int)tcp_iss < 0) + tcp_iss = 0; /* XXX */ +#endif + tcp_now++; /* for timestamps */ +} + +/* + * Cancel all timers for TCP tp. + */ +void +tcp_canceltimers(tp) + struct tcpcb *tp; +{ + register int i; + + for (i = 0; i < TCPT_NTIMERS; i++) + tp->t_timer[i] = 0; +} + +int tcp_backoff[TCP_MAXRXTSHIFT + 1] = + { 1, 2, 4, 8, 16, 32, 64, 64, 64, 64, 64, 64, 64 }; + +/* + * TCP timer processing. + */ +struct tcpcb * +tcp_timers(tp, timer) + struct tcpcb *tp; + int timer; +{ + int rexmt; + + DEBUG_CALL("tcp_timers"); + + switch (timer) { + + /* + * 2 MSL timeout in shutdown went off. If we're closed but + * still waiting for peer to close and connection has been idle + * too long, or if 2MSL time is up from TIME_WAIT, delete connection + * control block. Otherwise, check again in a bit. + */ + case TCPT_2MSL: + if (tp->t_state != TCPS_TIME_WAIT && + tp->t_idle <= tcp_maxidle) + tp->t_timer[TCPT_2MSL] = tcp_keepintvl; + else + tp = tcp_close(tp); + break; + + /* + * Retransmission timer went off. Message has not + * been acked within retransmit interval. Back off + * to a longer retransmit interval and retransmit one segment. + */ + case TCPT_REXMT: + + /* + * XXXXX If a packet has timed out, then remove all the queued + * packets for that session. + */ + + if (++tp->t_rxtshift > TCP_MAXRXTSHIFT) { + /* + * This is a hack to suit our terminal server here at the uni of canberra + * since they have trouble with zeroes... It usually lets them through + * unharmed, but under some conditions, it'll eat the zeros. If we + * keep retransmitting it, it'll keep eating the zeroes, so we keep + * retransmitting, and eventually the connection dies... + * (this only happens on incoming data) + * + * So, if we were gonna drop the connection from too many retransmits, + * don't... instead halve the t_maxseg, which might break up the NULLs and + * let them through + * + * *sigh* + */ + + tp->t_maxseg >>= 1; + if (tp->t_maxseg < 32) { + /* + * We tried our best, now the connection must die! + */ + tp->t_rxtshift = TCP_MAXRXTSHIFT; + tcpstat.tcps_timeoutdrop++; + tp = tcp_drop(tp, tp->t_softerror); + /* tp->t_softerror : ETIMEDOUT); */ /* XXX */ + return (tp); /* XXX */ + } + + /* + * Set rxtshift to 6, which is still at the maximum + * backoff time + */ + tp->t_rxtshift = 6; + } + tcpstat.tcps_rexmttimeo++; + rexmt = TCP_REXMTVAL(tp) * tcp_backoff[tp->t_rxtshift]; + TCPT_RANGESET(tp->t_rxtcur, rexmt, + (short)tp->t_rttmin, TCPTV_REXMTMAX); /* XXX */ + tp->t_timer[TCPT_REXMT] = tp->t_rxtcur; + /* + * If losing, let the lower level know and try for + * a better route. Also, if we backed off this far, + * our srtt estimate is probably bogus. Clobber it + * so we'll take the next rtt measurement as our srtt; + * move the current srtt into rttvar to keep the current + * retransmit times until then. + */ + if (tp->t_rxtshift > TCP_MAXRXTSHIFT / 4) { +/* in_losing(tp->t_inpcb); */ + tp->t_rttvar += (tp->t_srtt >> TCP_RTT_SHIFT); + tp->t_srtt = 0; + } + tp->snd_nxt = tp->snd_una; + /* + * If timing a segment in this window, stop the timer. + */ + tp->t_rtt = 0; + /* + * Close the congestion window down to one segment + * (we'll open it by one segment for each ack we get). + * Since we probably have a window's worth of unacked + * data accumulated, this "slow start" keeps us from + * dumping all that data as back-to-back packets (which + * might overwhelm an intermediate gateway). + * + * There are two phases to the opening: Initially we + * open by one mss on each ack. This makes the window + * size increase exponentially with time. If the + * window is larger than the path can handle, this + * exponential growth results in dropped packet(s) + * almost immediately. To get more time between + * drops but still "push" the network to take advantage + * of improving conditions, we switch from exponential + * to linear window opening at some threshold size. + * For a threshold, we use half the current window + * size, truncated to a multiple of the mss. + * + * (the minimum cwnd that will give us exponential + * growth is 2 mss. We don't allow the threshold + * to go below this.) + */ + { + u_int win = min(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg; + if (win < 2) + win = 2; + tp->snd_cwnd = tp->t_maxseg; + tp->snd_ssthresh = win * tp->t_maxseg; + tp->t_dupacks = 0; + } + (void) tcp_output(tp); + break; + + /* + * Persistence timer into zero window. + * Force a byte to be output, if possible. + */ + case TCPT_PERSIST: + tcpstat.tcps_persisttimeo++; + tcp_setpersist(tp); + tp->t_force = 1; + (void) tcp_output(tp); + tp->t_force = 0; + break; + + /* + * Keep-alive timer went off; send something + * or drop connection if idle for too long. + */ + case TCPT_KEEP: + tcpstat.tcps_keeptimeo++; + if (tp->t_state < TCPS_ESTABLISHED) + goto dropit; + +/* if (tp->t_socket->so_options & SO_KEEPALIVE && */ + if ((so_options) && tp->t_state <= TCPS_CLOSE_WAIT) { + if (tp->t_idle >= tcp_keepidle + tcp_maxidle) + goto dropit; + /* + * Send a packet designed to force a response + * if the peer is up and reachable: + * either an ACK if the connection is still alive, + * or an RST if the peer has closed the connection + * due to timeout or reboot. + * Using sequence number tp->snd_una-1 + * causes the transmitted zero-length segment + * to lie outside the receive window; + * by the protocol spec, this requires the + * correspondent TCP to respond. + */ + tcpstat.tcps_keepprobe++; +#ifdef TCP_COMPAT_42 + /* + * The keepalive packet must have nonzero length + * to get a 4.2 host to respond. + */ + tcp_respond(tp, &tp->t_template, (struct SLIRPmbuf *)NULL, + tp->rcv_nxt - 1, tp->snd_una - 1, 0); +#else + tcp_respond(tp, &tp->t_template, (struct SLIRPmbuf *)NULL, + tp->rcv_nxt, tp->snd_una - 1, 0); +#endif + tp->t_timer[TCPT_KEEP] = tcp_keepintvl; + } else + tp->t_timer[TCPT_KEEP] = tcp_keepidle; + break; + + dropit: + tcpstat.tcps_keepdrops++; + tp = tcp_drop(tp, 0); /* ETIMEDOUT); */ + break; + } + + return (tp); +} diff --git a/src/slirp/tcp_timer.h b/src/slirp/tcp_timer.h new file mode 100644 index 000000000..0bc438c76 --- /dev/null +++ b/src/slirp/tcp_timer.h @@ -0,0 +1,138 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tcp_timer.h 8.1 (Berkeley) 6/10/93 + * tcp_timer.h,v 1.4 1994/08/21 05:27:38 paul Exp + */ + +#ifndef _TCP_TIMER_H_ +#define _TCP_TIMER_H_ + +/* + * Definitions of the TCP timers. These timers are counted + * down PR_SLOWHZ times a second. + */ +#define TCPT_NTIMERS 4 + +#define TCPT_REXMT 0 /* retransmit */ +#define TCPT_PERSIST 1 /* retransmit persistence */ +#define TCPT_KEEP 2 /* keep alive */ +#define TCPT_2MSL 3 /* 2*msl quiet time timer */ + +/* + * The TCPT_REXMT timer is used to force retransmissions. + * The TCP has the TCPT_REXMT timer set whenever segments + * have been sent for which ACKs are expected but not yet + * received. If an ACK is received which advances tp->snd_una, + * then the retransmit timer is cleared (if there are no more + * outstanding segments) or reset to the base value (if there + * are more ACKs expected). Whenever the retransmit timer goes off, + * we retransmit one unacknowledged segment, and do a backoff + * on the retransmit timer. + * + * The TCPT_PERSIST timer is used to keep window size information + * flowing even if the window goes shut. If all previous transmissions + * have been acknowledged (so that there are no retransmissions in progress), + * and the window is too small to bother sending anything, then we start + * the TCPT_PERSIST timer. When it expires, if the window is nonzero, + * we go to transmit state. Otherwise, at intervals send a single byte + * into the peer's window to force him to update our window information. + * We do this at most as often as TCPT_PERSMIN time intervals, + * but no more frequently than the current estimate of round-trip + * packet time. The TCPT_PERSIST timer is cleared whenever we receive + * a window update from the peer. + * + * The TCPT_KEEP timer is used to keep connections alive. If an + * connection is idle (no segments received) for TCPTV_KEEP_INIT amount of time, + * but not yet established, then we drop the connection. Once the connection + * is established, if the connection is idle for TCPTV_KEEP_IDLE time + * (and keepalives have been enabled on the socket), we begin to probe + * the connection. We force the peer to send us a segment by sending: + * + * This segment is (deliberately) outside the window, and should elicit + * an ack segment in response from the peer. If, despite the TCPT_KEEP + * initiated segments we cannot elicit a response from a peer in TCPT_MAXIDLE + * amount of time probing, then we drop the connection. + */ + +/* + * Time constants. + */ +#define TCPTV_MSL ( 5*PR_SLOWHZ) /* max seg lifetime (hah!) */ + +#define TCPTV_SRTTBASE 0 /* base roundtrip time; + if 0, no idea yet */ +#define TCPTV_SRTTDFLT ( 3*PR_SLOWHZ) /* assumed RTT if no info */ + +#define TCPTV_PERSMIN ( 5*PR_SLOWHZ) /* retransmit persistence */ +#define TCPTV_PERSMAX ( 60*PR_SLOWHZ) /* maximum persist interval */ + +#define TCPTV_KEEP_INIT ( 75*PR_SLOWHZ) /* initial connect keep alive */ +#define TCPTV_KEEP_IDLE (120*60*PR_SLOWHZ) /* dflt time before probing */ +#define TCPTV_KEEPINTVL ( 75*PR_SLOWHZ) /* default probe interval */ +#define TCPTV_KEEPCNT 8 /* max probes before drop */ + +#define TCPTV_MIN ( 1*PR_SLOWHZ) /* minimum allowable value */ +/* #define TCPTV_REXMTMAX ( 64*PR_SLOWHZ) */ /* max allowable REXMT value */ +#define TCPTV_REXMTMAX ( 12*PR_SLOWHZ) /* max allowable REXMT value */ + +#define TCP_LINGERTIME 120 /* linger at most 2 minutes */ + +#define TCP_MAXRXTSHIFT 12 /* maximum retransmits */ + + +#ifdef TCPTIMERS +char *tcptimers[] = + { "REXMT", "PERSIST", "KEEP", "2MSL" }; +#endif + +/* + * Force a time value to be in a certain range. + */ +#define TCPT_RANGESET(tv, value, tvmin, tvmax) { \ + (tv) = (value); \ + if ((tv) < (tvmin)) \ + (tv) = (tvmin); \ + else if ((tv) > (tvmax)) \ + (tv) = (tvmax); \ +} + +extern int tcp_keepidle; /* time before keepalive probes begin */ +extern int tcp_keepintvl; /* time between keepalive probes */ +extern int tcp_maxidle; /* time to drop after starting probes */ +extern int tcp_ttl; /* time to live for TCP segs */ +extern int tcp_backoff[]; + +struct tcpcb; + +void tcp_fasttimo _P((void)); +void tcp_slowtimo _P((void)); +void tcp_canceltimers _P((struct tcpcb *)); +struct tcpcb * tcp_timers _P((register struct tcpcb *, int)); + +#endif diff --git a/src/slirp/tcp_var.h b/src/slirp/tcp_var.h new file mode 100644 index 000000000..e8f6bb73f --- /dev/null +++ b/src/slirp/tcp_var.h @@ -0,0 +1,248 @@ +/* + * Copyright (c) 1982, 1986, 1993, 1994 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tcp_var.h 8.3 (Berkeley) 4/10/94 + * tcp_var.h,v 1.3 1994/08/21 05:27:39 paul Exp + */ + +#ifndef _TCP_VAR_H_ +#define _TCP_VAR_H_ + +#include "tcpip.h" +#include "tcp_timer.h" + +#if SIZEOF_CHAR_P == 4 + typedef struct tcpiphdr *tcpiphdrp_32; +#else + typedef u_int32_t tcpiphdrp_32; +#endif + +/* + * Tcp control block, one per tcp; fields: + */ +struct tcpcb { + tcpiphdrp_32 seg_next; /* sequencing queue */ + tcpiphdrp_32 seg_prev; + short t_state; /* state of this connection */ + short t_timer[TCPT_NTIMERS]; /* tcp timers */ + short t_rxtshift; /* log(2) of rexmt exp. backoff */ + short t_rxtcur; /* current retransmit value */ + short t_dupacks; /* consecutive dup acks recd */ + u_short t_maxseg; /* maximum segment size */ + char t_force; /* 1 if forcing out a byte */ + u_short t_flags; +#define TF_ACKNOW 0x0001 /* ack peer immediately */ +#define TF_DELACK 0x0002 /* ack, but try to delay it */ +#define TF_NODELAY 0x0004 /* don't delay packets to coalesce */ +#define TF_NOOPT 0x0008 /* don't use tcp options */ +#define TF_SENTFIN 0x0010 /* have sent FIN */ +#define TF_REQ_SCALE 0x0020 /* have/will request window scaling */ +#define TF_RCVD_SCALE 0x0040 /* other side has requested scaling */ +#define TF_REQ_TSTMP 0x0080 /* have/will request timestamps */ +#define TF_RCVD_TSTMP 0x0100 /* a timestamp was received in SYN */ +#define TF_SACK_PERMIT 0x0200 /* other side said I could SACK */ + + /* Make it static for now */ +/* struct tcpiphdr *t_template; / * skeletal packet for transmit */ + struct tcpiphdr t_template; + + struct SLIRPsocket *t_socket; /* back pointer to socket */ +/* + * The following fields are used as in the protocol specification. + * See RFC783, Dec. 1981, page 21. + */ +/* send sequence variables */ + tcp_seq snd_una; /* send unacknowledged */ + tcp_seq snd_nxt; /* send next */ + tcp_seq snd_up; /* send urgent pointer */ + tcp_seq snd_wl1; /* window update seg seq number */ + tcp_seq snd_wl2; /* window update seg ack number */ + tcp_seq iss; /* initial send sequence number */ + u_int32_t snd_wnd; /* send window */ +/* receive sequence variables */ + u_int32_t rcv_wnd; /* receive window */ + tcp_seq rcv_nxt; /* receive next */ + tcp_seq rcv_up; /* receive urgent pointer */ + tcp_seq irs; /* initial receive sequence number */ +/* + * Additional variables for this implementation. + */ +/* receive variables */ + tcp_seq rcv_adv; /* advertised window */ +/* retransmit variables */ + tcp_seq snd_max; /* highest sequence number sent; + * used to recognize retransmits + */ +/* congestion control (for slow start, source quench, retransmit after loss) */ + u_int32_t snd_cwnd; /* congestion-controlled window */ + u_int32_t snd_ssthresh; /* snd_cwnd size threshold for + * for slow start exponential to + * linear switch + */ +/* + * transmit timing stuff. See below for scale of srtt and rttvar. + * "Variance" is actually smoothed difference. + */ + short t_idle; /* inactivity time */ + short t_rtt; /* round trip time */ + tcp_seq t_rtseq; /* sequence number being timed */ + short t_srtt; /* smoothed round-trip time */ + short t_rttvar; /* variance in round-trip time */ + u_short t_rttmin; /* minimum rtt allowed */ + u_int32_t max_sndwnd; /* largest window peer has offered */ + +/* out-of-band data */ + char t_oobflags; /* have some */ + char t_iobc; /* input character */ +#define TCPOOB_HAVEDATA 0x01 +#define TCPOOB_HADDATA 0x02 + short t_softerror; /* possible error not yet reported */ + +/* RFC 1323 variables */ + u_char snd_scale; /* window scaling for send window */ + u_char rcv_scale; /* window scaling for recv window */ + u_char request_r_scale; /* pending window scaling */ + u_char requested_s_scale; + u_int32_t ts_recent; /* timestamp echo data */ + u_int32_t ts_recent_age; /* when last updated */ + tcp_seq last_ack_sent; + +}; + +#define sototcpcb(so) ((so)->so_tcpcb) + +/* + * The smoothed round-trip time and estimated variance + * are stored as fixed point numbers scaled by the values below. + * For convenience, these scales are also used in smoothing the average + * (smoothed = (1/scale)sample + ((scale-1)/scale)smoothed). + * With these scales, srtt has 3 bits to the right of the binary point, + * and thus an "ALPHA" of 0.875. rttvar has 2 bits to the right of the + * binary point, and is smoothed with an ALPHA of 0.75. + */ +#define TCP_RTT_SCALE 8 /* multiplier for srtt; 3 bits frac. */ +#define TCP_RTT_SHIFT 3 /* shift for srtt; 3 bits frac. */ +#define TCP_RTTVAR_SCALE 4 /* multiplier for rttvar; 2 bits */ +#define TCP_RTTVAR_SHIFT 2 /* multiplier for rttvar; 2 bits */ + +/* + * The initial retransmission should happen at rtt + 4 * rttvar. + * Because of the way we do the smoothing, srtt and rttvar + * will each average +1/2 tick of bias. When we compute + * the retransmit timer, we want 1/2 tick of rounding and + * 1 extra tick because of +-1/2 tick uncertainty in the + * firing of the timer. The bias will give us exactly the + * 1.5 tick we need. But, because the bias is + * statistical, we have to test that we don't drop below + * the minimum feasible timer (which is 2 ticks). + * This macro assumes that the value of TCP_RTTVAR_SCALE + * is the same as the multiplier for rttvar. + */ +#define TCP_REXMTVAL(tp) \ + (((tp)->t_srtt >> TCP_RTT_SHIFT) + (tp)->t_rttvar) + +/* XXX + * We want to avoid doing m_pullup on incoming packets but that + * means avoiding dtom on the tcp reassembly code. That in turn means + * keeping an mbuf pointer in the reassembly queue (since we might + * have a cluster). As a quick hack, the source & destination + * port numbers (which are no longer needed once we've located the + * tcpcb) are overlayed with an mbuf pointer. + */ +#if SIZEOF_CHAR_P == 4 +typedef struct SLIRPmbuf *mbufp_32; +#else +typedef u_int32_t mbufp_32; +#endif +#define REASS_MBUF(ti) (*(mbufp_32 *)&((ti)->ti_t)) + +/* + * TCP statistics. + * Many of these should be kept per connection, + * but that's inconvenient at the moment. + */ +struct tcpstat { + u_long tcps_connattempt; /* connections initiated */ + u_long tcps_accepts; /* connections accepted */ + u_long tcps_connects; /* connections established */ + u_long tcps_drops; /* connections dropped */ + u_long tcps_conndrops; /* embryonic connections dropped */ + u_long tcps_closed; /* conn. closed (includes drops) */ + u_long tcps_segstimed; /* segs where we tried to get rtt */ + u_long tcps_rttupdated; /* times we succeeded */ + u_long tcps_delack; /* delayed acks sent */ + u_long tcps_timeoutdrop; /* conn. dropped in rxmt timeout */ + u_long tcps_rexmttimeo; /* retransmit timeouts */ + u_long tcps_persisttimeo; /* persist timeouts */ + u_long tcps_keeptimeo; /* keepalive timeouts */ + u_long tcps_keepprobe; /* keepalive probes sent */ + u_long tcps_keepdrops; /* connections dropped in keepalive */ + + u_long tcps_sndtotal; /* total packets sent */ + u_long tcps_sndpack; /* data packets sent */ + u_long tcps_sndbyte; /* data bytes sent */ + u_long tcps_sndrexmitpack; /* data packets retransmitted */ + u_long tcps_sndrexmitbyte; /* data bytes retransmitted */ + u_long tcps_sndacks; /* ack-only packets sent */ + u_long tcps_sndprobe; /* window probes sent */ + u_long tcps_sndurg; /* packets sent with URG only */ + u_long tcps_sndwinup; /* window update-only packets sent */ + u_long tcps_sndctrl; /* control (SYN|FIN|RST) packets sent */ + + u_long tcps_rcvtotal; /* total packets received */ + u_long tcps_rcvpack; /* packets received in sequence */ + u_long tcps_rcvbyte; /* bytes received in sequence */ + u_long tcps_rcvbadsum; /* packets received with ccksum errs */ + u_long tcps_rcvbadoff; /* packets received with bad offset */ +/* u_long tcps_rcvshort; */ /* packets received too short */ + u_long tcps_rcvduppack; /* duplicate-only packets received */ + u_long tcps_rcvdupbyte; /* duplicate-only bytes received */ + u_long tcps_rcvpartduppack; /* packets with some duplicate data */ + u_long tcps_rcvpartdupbyte; /* dup. bytes in part-dup. packets */ + u_long tcps_rcvoopack; /* out-of-order packets received */ + u_long tcps_rcvoobyte; /* out-of-order bytes received */ + u_long tcps_rcvpackafterwin; /* packets with data after window */ + u_long tcps_rcvbyteafterwin; /* bytes rcvd after window */ + u_long tcps_rcvafterclose; /* packets rcvd after "close" */ + u_long tcps_rcvwinprobe; /* rcvd window probe packets */ + u_long tcps_rcvdupack; /* rcvd duplicate acks */ + u_long tcps_rcvacktoomuch; /* rcvd acks for unsent data */ + u_long tcps_rcvackpack; /* rcvd ack packets */ + u_long tcps_rcvackbyte; /* bytes acked by rcvd acks */ + u_long tcps_rcvwinupd; /* rcvd window update packets */ +/* u_long tcps_pawsdrop; */ /* segments dropped due to PAWS */ + u_long tcps_predack; /* times hdr predict ok for acks */ + u_long tcps_preddat; /* times hdr predict ok for data pkts */ + u_long tcps_socachemiss; /* tcp_last_so misses */ + u_long tcps_didnuttin; /* Times tcp_output didn't do anything XXX */ +}; + +extern struct tcpstat tcpstat; /* tcp statistics */ +extern u_int32_t tcp_now; /* for RFC 1323 timestamps */ + +#endif diff --git a/src/slirp/tcpip.h b/src/slirp/tcpip.h new file mode 100644 index 000000000..dff5a3c96 --- /dev/null +++ b/src/slirp/tcpip.h @@ -0,0 +1,70 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)tcpip.h 8.1 (Berkeley) 6/10/93 + * tcpip.h,v 1.3 1994/08/21 05:27:40 paul Exp + */ + +#ifndef _TCPIP_H_ +#define _TCPIP_H_ + +/* + * Tcp+ip header, after ip options removed. + */ +struct tcpiphdr { + struct ipovly ti_i; /* overlaid ip structure */ + struct tcphdr ti_t; /* tcp header */ +}; +#define ti_next ti_i.ih_next +#define ti_prev ti_i.ih_prev +#define ti_x1 ti_i.ih_x1 +#define ti_pr ti_i.ih_pr +#define ti_len ti_i.ih_len +#define ti_src ti_i.ih_src +#define ti_dst ti_i.ih_dst +#define ti_sport ti_t.th_sport +#define ti_dport ti_t.th_dport +#define ti_seq ti_t.th_seq +#define ti_ack ti_t.th_ack +#define ti_x2 ti_t.th_x2 +#define ti_off ti_t.th_off +#define ti_flags ti_t.th_flags +#define ti_win ti_t.th_win +#define ti_sum ti_t.th_sum +#define ti_urp ti_t.th_urp + +/* + * Just a clean way to get to the first byte + * of the packet + */ +struct tcpiphdr_2 { + struct tcpiphdr dummy; + char first_char; +}; + +#endif diff --git a/src/slirp/tftp.c b/src/slirp/tftp.c new file mode 100644 index 000000000..b7b1ffb0a --- /dev/null +++ b/src/slirp/tftp.c @@ -0,0 +1,332 @@ +/* + * tftp.c - a simple, read-only tftp server for qemu + * + * Copyright (c) 2004 Magnus Damm + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "slirp.h" +#include "../ibm.h" + +struct tftp_session { + int in_use; + char filename[TFTP_FILENAME_MAX]; + + struct in_addr client_ip; + u_int16_t client_port; + + int timestamp; +}; + +struct tftp_session tftp_sessions[TFTP_SESSIONS_MAX]; + +const char *tftp_prefix; + +static void tftp_session_update(struct tftp_session *spt) +{ + spt->timestamp = curtime; + spt->in_use = 1; +} + +static void tftp_session_terminate(struct tftp_session *spt) +{ + spt->in_use = 0; +} + +static int tftp_session_allocate(struct tftp_t *tp) +{ + struct tftp_session *spt; + int k; + + for (k = 0; k < TFTP_SESSIONS_MAX; k++) { + spt = &tftp_sessions[k]; + + if (!spt->in_use) + goto found; + + /* sessions time out after 5 inactive seconds */ + if ((int)(curtime - spt->timestamp) > 5000) + goto found; + } + + return -1; + + found: + memset(spt, 0, sizeof(*spt)); + memcpy(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip)); + spt->client_port = tp->udp.uh_sport; + + tftp_session_update(spt); + + return k; +} + +static int tftp_session_find(struct tftp_t *tp) +{ + struct tftp_session *spt; + int k; + + for (k = 0; k < TFTP_SESSIONS_MAX; k++) { + spt = &tftp_sessions[k]; + + if (spt->in_use) { + if (!memcmp(&spt->client_ip, &tp->ip.ip_src, sizeof(spt->client_ip))) { + if (spt->client_port == tp->udp.uh_sport) { + return k; + } + } + } + } + + return -1; +} + +static int tftp_read_data(struct tftp_session *spt, u_int16_t block_nr, + u_int8_t *buf, int len) +{ + int fd; + int bytes_read = 0; + + char file_path[sizeof(pcempath) + 5 + sizeof(spt->filename)]; + strcpy(file_path, pcempath); + strcat(file_path, "tftp/"); + strcat(file_path, spt->filename); + + fd = open(file_path, O_RDONLY | O_BINARY); + + if (fd < 0) { + return -1; + } + + if (len) { + lseek(fd, block_nr * 512, SEEK_SET); + + bytes_read = read(fd, buf, len); + } + + close(fd); + + return bytes_read; +} + +static int tftp_send_error(struct tftp_session *spt, + u_int16_t errorcode, const char *msg, + struct tftp_t *recv_tp) +{ + struct sockaddr_in saddr, daddr; + struct SLIRPmbuf *m; + struct tftp_t *tp; + int nobytes; + + m = m_get(); + + if (!m) { + return -1; + } + + memset(m->m_data, 0, m->m_size); + + m->m_data += if_maxlinkhdr; + tp = (void *)m->m_data; + m->m_data += sizeof(struct udpiphdr); + + tp->tp_op = htons(TFTP_ERROR); + tp->x.tp_error.tp_error_code = htons(errorcode); + strncpy((char *)tp->x.tp_error.tp_msg, msg, sizeof(tp->x.tp_error.tp_msg)); + tp->x.tp_error.tp_msg[sizeof(tp->x.tp_error.tp_msg)-1] = 0; + + saddr.sin_addr = recv_tp->ip.ip_dst; + saddr.sin_port = recv_tp->udp.uh_dport; + + daddr.sin_addr = spt->client_ip; + daddr.sin_port = spt->client_port; + + nobytes = 2; + + m->m_len = sizeof(struct tftp_t) - 514 + 3 + strlen(msg) - + sizeof(struct ip) - sizeof(struct udphdr); + + udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); + + tftp_session_terminate(spt); + + return 0; +} + +static int tftp_send_data(struct tftp_session *spt, + u_int16_t block_nr, + struct tftp_t *recv_tp) +{ + struct sockaddr_in saddr, daddr; + struct SLIRPmbuf *m; + struct tftp_t *tp; + int nobytes; + + if (block_nr < 1) { + return -1; + } + + m = m_get(); + + if (!m) { + return -1; + } + + memset(m->m_data, 0, m->m_size); + + m->m_data += if_maxlinkhdr; + tp = (void *)m->m_data; + m->m_data += sizeof(struct udpiphdr); + + tp->tp_op = htons(TFTP_DATA); + tp->x.tp_data.tp_block_nr = htons(block_nr); + + saddr.sin_addr = recv_tp->ip.ip_dst; + saddr.sin_port = recv_tp->udp.uh_dport; + + daddr.sin_addr = spt->client_ip; + daddr.sin_port = spt->client_port; + + nobytes = tftp_read_data(spt, block_nr - 1, tp->x.tp_data.tp_buf, 512); + + if (nobytes < 0) { + m_free(m); + + /* send "file not found" error back */ + + tftp_send_error(spt, 1, "File not found", tp); + + return -1; + } + + m->m_len = sizeof(struct tftp_t) - (512 - nobytes) - + sizeof(struct ip) - sizeof(struct udphdr); + + udp_output2(NULL, m, &saddr, &daddr, IPTOS_LOWDELAY); + + if (nobytes == 512) { + tftp_session_update(spt); + } + else { + tftp_session_terminate(spt); + } + + return 0; +} + +static void tftp_handle_rrq(struct tftp_t *tp, int pktlen) +{ + struct tftp_session *spt; + int s, k, n; + u_int8_t *src, *dst; + + s = tftp_session_allocate(tp); + + if (s < 0) { + return; + } + + spt = &tftp_sessions[s]; + + src = tp->x.tp_buf; + dst = (u_int8_t *)spt->filename; + n = pktlen - ((uint8_t *)&tp->x.tp_buf[0] - (uint8_t *)tp); + + /* get name */ + + for (k = 0; k < n; k++) { + if (k < TFTP_FILENAME_MAX) { + dst[k] = src[k]; + } + else { + return; + } + + if (src[k] == '\0') { + break; + } + } + + if (k >= n) { + return; + } + + k++; + + /* check mode */ + if ((n - k) < 6) { + return; + } + + if (memcmp(&src[k], "octet\0", 6) != 0) { + tftp_send_error(spt, 4, "Unsupported transfer mode", tp); + return; + } + + pclog("tftp request: %s\n", spt->filename); + + /* do sanity checks on the filename */ + + if (strstr(spt->filename, "../") || strstr(spt->filename, "..\\")) { + tftp_send_error(spt, 2, "Access violation", tp); + return; + } + + /* check if the file exists */ + + if (tftp_read_data(spt, 0, (u_int8_t *)spt->filename, 0) < 0) { + tftp_send_error(spt, 1, "File not found", tp); + return; + } + + tftp_send_data(spt, 1, tp); +} + +static void tftp_handle_ack(struct tftp_t *tp, int pktlen) +{ + int s; + + s = tftp_session_find(tp); + + if (s < 0) { + return; + } + + if (tftp_send_data(&tftp_sessions[s], + ntohs(tp->x.tp_data.tp_block_nr) + 1, + tp) < 0) { + return; + } +} + +void tftp_input(struct SLIRPmbuf *m) +{ + struct tftp_t *tp = (struct tftp_t *)m->m_data; + + switch(ntohs(tp->tp_op)) { + case TFTP_RRQ: + tftp_handle_rrq(tp, m->m_len); + break; + + case TFTP_ACK: + tftp_handle_ack(tp, m->m_len); + break; + } +} diff --git a/src/slirp/tftp.h b/src/slirp/tftp.h new file mode 100644 index 000000000..ba4174115 --- /dev/null +++ b/src/slirp/tftp.h @@ -0,0 +1,40 @@ +/* tftp defines */ + +#define TFTP_SESSIONS_MAX 3 + +#define TFTP_SERVER 69 + +#define TFTP_RRQ 1 +#define TFTP_WRQ 2 +#define TFTP_DATA 3 +#define TFTP_ACK 4 +#define TFTP_ERROR 5 + +#define TFTP_FILENAME_MAX 512 + +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(1) +#endif + +struct tftp_t { + struct ip ip; + struct udphdr udp; + u_int16_t tp_op; + union { + struct { + u_int16_t tp_block_nr; + u_int8_t tp_buf[512]; + } tp_data; + struct { + u_int16_t tp_error_code; + u_int8_t tp_msg[512]; + } tp_error; + u_int8_t tp_buf[512 + 2]; + } x; +} PACKED__; + +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(PACK_END) +#endif + +void tftp_input(struct SLIRPmbuf *m); diff --git a/src/slirp/udp.c b/src/slirp/udp.c new file mode 100644 index 000000000..318ac6400 --- /dev/null +++ b/src/slirp/udp.c @@ -0,0 +1,676 @@ +/* + * Copyright (c) 1982, 1986, 1988, 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)udp_usrreq.c 8.4 (Berkeley) 1/21/94 + * udp_usrreq.c,v 1.4 1994/10/02 17:48:45 phk Exp + */ + +/* + * Changes and additions relating to SLiRP + * Copyright (c) 1995 Danny Gasparovski. + * + * Please read the file COPYRIGHT for the + * terms and conditions of the copyright. + */ + +#include +#include "slirp.h" +#include "ip_icmp.h" + +struct udpstat udpstat; + +struct SLIRPsocket udb; + +/* + * UDP protocol implementation. + * Per RFC 768, August, 1980. + */ +#ifndef COMPAT_42 +int udpcksum = 1; +#else +int udpcksum = 0; /* XXX */ +#endif + +struct SLIRPsocket *udp_last_so = &udb; + +void +udp_init() +{ + udb.so_next = udb.so_prev = &udb; +} +/* m->m_data points at ip packet header + * m->m_len length ip packet + * ip->ip_len length data (IPDU) + */ +void +udp_input(m, iphlen) + struct SLIRPmbuf *m; + int iphlen; +{ + struct ip *ip; + struct udphdr *uh; +/* struct SLIRPmbuf *opts = 0;*/ + int len; + struct ip save_ip; + struct SLIRPsocket *so; + + DEBUG_CALL("udp_input"); + DEBUG_ARG("m = %lx", (long)m); + DEBUG_ARG("iphlen = %d", iphlen); + + udpstat.udps_ipackets++; + + /* + * Strip IP options, if any; should skip this, + * make available to user, and use on returned packets, + * but we don't yet have a way to check the checksum + * with options still present. + */ + if(iphlen > sizeof(struct ip)) { + ip_stripoptions(m, (struct SLIRPmbuf *)0); + iphlen = sizeof(struct ip); + } + + /* + * Get IP and UDP header together in first SLIRPmbuf. + */ + ip = mtod(m, struct ip *); + uh = (struct udphdr *)((SLIRPcaddr_t)ip + iphlen); + + /* + * Make SLIRPmbuf data length reflect UDP length. + * If not enough data to reflect UDP length, drop. + */ + len = ntohs((u_int16_t)uh->uh_ulen); + + if (ip->ip_len != len) { + if (len > ip->ip_len) { + udpstat.udps_badlen++; + goto bad; + } + m_adj(m, len - ip->ip_len); + ip->ip_len = len; + } + + /* + * Save a copy of the IP header in case we want restore it + * for sending an ICMP error message in response. + */ + save_ip = *ip; + save_ip.ip_len+= iphlen; /* tcp_input subtracts this */ + + /* + * Checksum extended UDP header and data. + */ + if (udpcksum && uh->uh_sum) { + ((struct ipovly *)ip)->ih_next = 0; + ((struct ipovly *)ip)->ih_prev = 0; + ((struct ipovly *)ip)->ih_x1 = 0; + ((struct ipovly *)ip)->ih_len = uh->uh_ulen; + /* keep uh_sum for ICMP reply + * uh->uh_sum = cksum(m, len + sizeof (struct ip)); + * if (uh->uh_sum) { + */ + if(cksum(m, len + sizeof(struct ip))) { + udpstat.udps_badsum++; + goto bad; + } + } + + /* + * handle DHCP/BOOTP + */ + if (ntohs(uh->uh_dport) == BOOTP_SERVER) { + bootp_input(m); + goto bad; + } + + /* + * handle TFTP + */ + if (ntohs(uh->uh_dport) == TFTP_SERVER) { + tftp_input(m); + goto bad; + } + + /* + * Locate pcb for datagram. + */ + so = udp_last_so; + if (so->so_lport != uh->uh_sport || + so->so_laddr.s_addr != ip->ip_src.s_addr) { + struct SLIRPsocket *tmp; + + for (tmp = udb.so_next; tmp != &udb; tmp = tmp->so_next) { + if (tmp->so_lport == uh->uh_sport && + tmp->so_laddr.s_addr == ip->ip_src.s_addr) { + tmp->so_faddr.s_addr = ip->ip_dst.s_addr; + tmp->so_fport = uh->uh_dport; + so = tmp; + break; + } + } + if (tmp == &udb) { + so = NULL; + } else { + udpstat.udpps_pcbcachemiss++; + udp_last_so = so; + } + } + + if (so == NULL) { + /* + * If there's no socket for this packet, + * create one + */ + if ((so = socreate()) == NULL) goto bad; + if(udp_attach(so) == -1) { + DEBUG_MISC((dfd," udp_attach errno = %d-%s\n", + errno,strerror(errno))); + sofree(so); + goto bad; + } + + /* + * Setup fields + */ + /* udp_last_so = so; */ + so->so_laddr = ip->ip_src; + so->so_lport = uh->uh_sport; + + if ((so->so_iptos = udp_tos(so)) == 0) + so->so_iptos = ip->ip_tos; + + /* + * XXXXX Here, check if it's in udpexec_list, + * and if it is, do the fork_exec() etc. + */ + } + + so->so_faddr = ip->ip_dst; /* XXX */ + so->so_fport = uh->uh_dport; /* XXX */ + + iphlen += sizeof(struct udphdr); + m->m_len -= iphlen; + m->m_data += iphlen; + + /* + * Now we sendto() the packet. + */ + if (so->so_emu) + udp_emu(so, m); + + if(sosendto(so,m) == -1) { + m->m_len += iphlen; + m->m_data -= iphlen; + *ip=save_ip; + DEBUG_MISC((dfd,"udp tx errno = %d-%s\n",errno,strerror(errno))); + icmp_error(m, ICMP_UNREACH,ICMP_UNREACH_NET, 0,strerror(errno)); + } + + m_free(so->so_m); /* used for ICMP if error on sorecvfrom */ + + /* restore the orig SLIRPmbuf packet */ + m->m_len += iphlen; + m->m_data -= iphlen; + *ip=save_ip; + so->so_m=m; /* ICMP backup */ + + return; +bad: + m_freem(m); + /* if (opts) m_freem(opts); */ + return; +} + +int udp_output2(struct SLIRPsocket *so, struct SLIRPmbuf *m, + struct sockaddr_in *saddr, struct sockaddr_in *daddr, + int iptos) +{ + struct udpiphdr *ui; + int error = 0; + + DEBUG_CALL("udp_output"); + DEBUG_ARG("so = %lx", (long)so); + DEBUG_ARG("m = %lx", (long)m); + DEBUG_ARG("saddr = %lx", (long)saddr->sin_addr.s_addr); + DEBUG_ARG("daddr = %lx", (long)daddr->sin_addr.s_addr); + + /* + * Adjust for header + */ + m->m_data -= sizeof(struct udpiphdr); + m->m_len += sizeof(struct udpiphdr); + + /* + * Fill in SLIRPmbuf with extended UDP header + * and addresses and length put into network format. + */ + ui = mtod(m, struct udpiphdr *); + ui->ui_next = ui->ui_prev = 0; + ui->ui_x1 = 0; + ui->ui_pr = IPPROTO_UDP; + ui->ui_len = htons(m->m_len - sizeof(struct ip)); /* + sizeof (struct udphdr)); */ + /* XXXXX Check for from-one-location sockets, or from-any-location sockets */ + ui->ui_src = saddr->sin_addr; + ui->ui_dst = daddr->sin_addr; + ui->ui_sport = saddr->sin_port; + ui->ui_dport = daddr->sin_port; + ui->ui_ulen = ui->ui_len; + + /* + * Stuff checksum and output datagram. + */ + ui->ui_sum = 0; + if (udpcksum) { + if ((ui->ui_sum = cksum(m, /* sizeof (struct udpiphdr) + */ m->m_len)) == 0) + ui->ui_sum = 0xffff; + } + ((struct ip *)ui)->ip_len = m->m_len; + + ((struct ip *)ui)->ip_ttl = ip_defttl; + ((struct ip *)ui)->ip_tos = iptos; + + udpstat.udps_opackets++; + + error = ip_output(so, m); + + return (error); +} + +int udp_output(struct SLIRPsocket *so, struct SLIRPmbuf *m, + struct sockaddr_in *addr) + +{ + struct sockaddr_in saddr, daddr; + + saddr = *addr; + if ((so->so_faddr.s_addr & htonl(0xffffff00)) == special_addr.s_addr) { + saddr.sin_addr.s_addr = so->so_faddr.s_addr; + if ((so->so_faddr.s_addr & htonl(0x000000ff)) == htonl(0xff)) + saddr.sin_addr.s_addr = alias_addr.s_addr; + } + daddr.sin_addr = so->so_laddr; + daddr.sin_port = so->so_lport; + + return udp_output2(so, m, &saddr, &daddr, so->so_iptos); +} + +int +udp_attach(so) + struct SLIRPsocket *so; +{ + struct sockaddr_in addr; + + if((so->s = socket(AF_INET,SOCK_DGRAM,0)) != -1) { + /* + * Here, we bind() the socket. Although not really needed + * (sendto() on an unbound socket will bind it), it's done + * here so that emulation of ytalk etc. don't have to do it + */ + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_port = 0; + addr.sin_addr.s_addr = INADDR_ANY; + if(bind(so->s, (struct sockaddr *)&addr, sizeof(addr))<0) { + int lasterrno=errno; + closesocket(so->s); + so->s=-1; +#ifdef _WIN32 + WSASetLastError(lasterrno); +#else + errno=lasterrno; +#endif + } else { + /* success, insert in queue */ + so->so_expire = curtime + SO_EXPIRE; + insque(so,&udb); + } + } + return(so->s); +} + +void +udp_detach(so) + struct SLIRPsocket *so; +{ + closesocket(so->s); + /* if (so->so_m) m_free(so->so_m); done by sofree */ + + sofree(so); +} + +struct tos_t udptos[] = { + {0, 53, IPTOS_LOWDELAY, 0}, /* DNS */ + {517, 517, IPTOS_LOWDELAY, EMU_TALK}, /* talk */ + {518, 518, IPTOS_LOWDELAY, EMU_NTALK}, /* ntalk */ + {0, 7648, IPTOS_LOWDELAY, EMU_CUSEEME}, /* Cu-Seeme */ + {0, 0, 0, 0} +}; + +u_int8_t +udp_tos(so) + struct SLIRPsocket *so; +{ + int i = 0; + + while(udptos[i].tos) { + if ((udptos[i].fport && ntohs(so->so_fport) == udptos[i].fport) || + (udptos[i].lport && ntohs(so->so_lport) == udptos[i].lport)) { + so->so_emu = udptos[i].emu; + return udptos[i].tos; + } + i++; + } + + return 0; +} + +#ifdef EMULATE_TALK +#include "talkd.h" +#endif + +/* + * Here, talk/ytalk/ntalk requests must be emulated + */ +void +udp_emu(so, m) + struct SLIRPsocket *so; + struct SLIRPmbuf *m; +{ + struct sockaddr_in addr; + socklen_t addrlen = sizeof(addr); +#ifdef EMULATE_TALK + CTL_MSG_OLD *omsg; + CTL_MSG *nmsg; + char buff[sizeof(CTL_MSG)]; + u_char type; + +struct talk_request { + struct talk_request *next; + struct SLIRPsocket *udp_so; + struct SLIRPsocket *tcp_so; +} *req; + + static struct talk_request *req_tbl = 0; + +#endif + +struct cu_header { + uint16_t d_family; // destination family + uint16_t d_port; // destination port + uint32_t d_addr; // destination address + uint16_t s_family; // source family + uint16_t s_port; // source port + uint32_t so_addr; // source address + uint32_t seqn; // sequence number + uint16_t message; // message + uint16_t data_type; // data type + uint16_t pkt_len; // packet length +} *cu_head; + + switch(so->so_emu) { + +#ifdef EMULATE_TALK + case EMU_TALK: + case EMU_NTALK: + /* + * Talk emulation. We always change the ctl_addr to get + * some answers from the daemon. When an ANNOUNCE comes, + * we send LEAVE_INVITE to the local daemons. Also when a + * DELETE comes, we send copies to the local daemons. + */ + if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0) + return; + +#define IS_OLD (so->so_emu == EMU_TALK) + +#define COPY_MSG(dest, src) { dest->type = src->type; \ + dest->id_num = src->id_num; \ + dest->pid = src->pid; \ + dest->addr = src->addr; \ + dest->ctl_addr = src->ctl_addr; \ + memcpy(&dest->l_name, &src->l_name, NAME_SIZE_OLD); \ + memcpy(&dest->r_name, &src->r_name, NAME_SIZE_OLD); \ + memcpy(&dest->r_tty, &src->r_tty, TTY_SIZE); } + +#define OTOSIN(ptr, field) ((struct sockaddr_in *)&ptr->field) +/* old_sockaddr to sockaddr_in */ + + + if (IS_OLD) { /* old talk */ + omsg = mtod(m, CTL_MSG_OLD*); + nmsg = (CTL_MSG *) buff; + type = omsg->type; + OTOSIN(omsg, ctl_addr)->sin_port = addr.sin_port; + OTOSIN(omsg, ctl_addr)->sin_addr = our_addr; + strncpy(omsg->l_name, getlogin(), NAME_SIZE_OLD); + } else { /* new talk */ + omsg = (CTL_MSG_OLD *) buff; + nmsg = mtod(m, CTL_MSG *); + type = nmsg->type; + OTOSIN(nmsg, ctl_addr)->sin_port = addr.sin_port; + OTOSIN(nmsg, ctl_addr)->sin_addr = our_addr; + strncpy(nmsg->l_name, getlogin(), NAME_SIZE_OLD); + } + + if (type == LOOK_UP) + return; /* for LOOK_UP this is enough */ + + if (IS_OLD) { /* make a copy of the message */ + COPY_MSG(nmsg, omsg); + nmsg->vers = 1; + nmsg->answer = 0; + } else + COPY_MSG(omsg, nmsg); + + /* + * If if is an ANNOUNCE message, we go through the + * request table to see if a tcp port has already + * been redirected for this socket. If not, we solisten() + * a new socket and add this entry to the table. + * The port number of the tcp socket and our IP + * are put to the addr field of the message structures. + * Then a LEAVE_INVITE is sent to both local daemon + * ports, 517 and 518. This is why we have two copies + * of the message, one in old talk and one in new talk + * format. + */ + + if (type == ANNOUNCE) { + int s; + u_short temp_port; + + for(req = req_tbl; req; req = req->next) + if (so == req->udp_so) + break; /* found it */ + + if (!req) { /* no entry for so, create new */ + req = (struct talk_request *) + malloc(sizeof(struct talk_request)); + req->udp_so = so; + req->tcp_so = solisten(0, + OTOSIN(omsg, addr)->sin_addr.s_addr, + OTOSIN(omsg, addr)->sin_port, + SS_FACCEPTONCE); + req->next = req_tbl; + req_tbl = req; + } + + /* replace port number in addr field */ + addrlen = sizeof(addr); + getsockname(req->tcp_so->s, + (struct sockaddr *) &addr, + &addrlen); + OTOSIN(omsg, addr)->sin_port = addr.sin_port; + OTOSIN(omsg, addr)->sin_addr = our_addr; + OTOSIN(nmsg, addr)->sin_port = addr.sin_port; + OTOSIN(nmsg, addr)->sin_addr = our_addr; + + /* send LEAVE_INVITEs */ + temp_port = OTOSIN(omsg, ctl_addr)->sin_port; + OTOSIN(omsg, ctl_addr)->sin_port = 0; + OTOSIN(nmsg, ctl_addr)->sin_port = 0; + omsg->type = nmsg->type = LEAVE_INVITE; + + s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + addr.sin_addr = our_addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(517); + sendto(s, (char *)omsg, sizeof(*omsg), 0, + (struct sockaddr *)&addr, sizeof(addr)); + addr.sin_port = htons(518); + sendto(s, (char *)nmsg, sizeof(*nmsg), 0, + (struct sockaddr *) &addr, sizeof(addr)); + closesocket(s) ; + + omsg->type = nmsg->type = ANNOUNCE; + OTOSIN(omsg, ctl_addr)->sin_port = temp_port; + OTOSIN(nmsg, ctl_addr)->sin_port = temp_port; + } + + /* + * If it is a DELETE message, we send a copy to the + * local daemons. Then we delete the entry corresponding + * to our socket from the request table. + */ + + if (type == DELETE) { + struct talk_request *temp_req, *req_next; + int s; + u_short temp_port; + + temp_port = OTOSIN(omsg, ctl_addr)->sin_port; + OTOSIN(omsg, ctl_addr)->sin_port = 0; + OTOSIN(nmsg, ctl_addr)->sin_port = 0; + + s = socket(AF_INET, SOCK_DGRAM, IPPROTO_IP); + addr.sin_addr = our_addr; + addr.sin_family = AF_INET; + addr.sin_port = htons(517); + sendto(s, (char *)omsg, sizeof(*omsg), 0, + (struct sockaddr *)&addr, sizeof(addr)); + addr.sin_port = htons(518); + sendto(s, (char *)nmsg, sizeof(*nmsg), 0, + (struct sockaddr *)&addr, sizeof(addr)); + closesocket(s); + + OTOSIN(omsg, ctl_addr)->sin_port = temp_port; + OTOSIN(nmsg, ctl_addr)->sin_port = temp_port; + + /* delete table entry */ + if (so == req_tbl->udp_so) { + temp_req = req_tbl; + req_tbl = req_tbl->next; + free(temp_req); + } else { + temp_req = req_tbl; + for(req = req_tbl->next; req; req = req_next) { + req_next = req->next; + if (so == req->udp_so) { + temp_req->next = req_next; + free(req); + break; + } else { + temp_req = req; + } + } + } + } + + return; +#endif + + case EMU_CUSEEME: + + /* + * Cu-SeeMe emulation. + * Hopefully the packet is more that 16 bytes long. We don't + * do any other tests, just replace the address and port + * fields. + */ + if (m->m_len >= sizeof (*cu_head)) { + if (getsockname(so->s, (struct sockaddr *)&addr, &addrlen) < 0) + return; + cu_head = mtod(m, struct cu_header *); + cu_head->s_port = addr.sin_port; + cu_head->so_addr = our_addr.s_addr; + } + + return; + } +} + +struct SLIRPsocket * +udp_listen(port, laddr, lport, flags) + u_int port; + u_int32_t laddr; + u_int lport; + int flags; +{ + struct sockaddr_in addr; + struct SLIRPsocket *so; + socklen_t addrlen = sizeof(struct sockaddr_in); + int opt = 1; + + if ((so = socreate()) == NULL) { + free(so); + return NULL; + } + so->s = socket(AF_INET,SOCK_DGRAM,0); + so->so_expire = curtime + SO_EXPIRE; + insque(so,&udb); + + memset(&addr, 0, sizeof(struct sockaddr_in)); + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = INADDR_ANY; + addr.sin_port = port; + + if (bind(so->s,(struct sockaddr *)&addr, addrlen) < 0) { + udp_detach(so); + return NULL; + } + setsockopt(so->s,SOL_SOCKET,SO_REUSEADDR,(char *)&opt,sizeof(int)); +/* setsockopt(so->s,SOL_SOCKET,SO_OOBINLINE,(char *)&opt,sizeof(int)); */ + + getsockname(so->s,(struct sockaddr *)&addr,&addrlen); + so->so_fport = addr.sin_port; + if (addr.sin_addr.s_addr == 0 || addr.sin_addr.s_addr == loopback_addr.s_addr) + so->so_faddr = alias_addr; + else + so->so_faddr = addr.sin_addr; + + so->so_lport = lport; + so->so_laddr.s_addr = laddr; + if (flags != SS_FACCEPTONCE) + so->so_expire = 0; + + so->so_state = SS_ISFCONNECTED; + + return so; +} diff --git a/src/slirp/udp.h b/src/slirp/udp.h new file mode 100644 index 000000000..2f6b1e483 --- /dev/null +++ b/src/slirp/udp.h @@ -0,0 +1,114 @@ +/* + * Copyright (c) 1982, 1986, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * @(#)udp.h 8.1 (Berkeley) 6/10/93 + * udp.h,v 1.3 1994/08/21 05:27:41 paul Exp + */ + +#ifndef _UDP_H_ +#define _UDP_H_ + +#define UDP_TTL 0x60 +#define UDP_UDPDATALEN 16192 + +extern struct SLIRPsocket *udp_last_so; + +/* + * Udp protocol header. + * Per RFC 768, September, 1981. + */ +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(1) +#endif + +struct udphdr { + u_int16_t uh_sport; /* source port */ + u_int16_t uh_dport; /* destination port */ + int16_t uh_ulen; /* udp length */ + u_int16_t uh_sum; /* udp checksum */ +} PACKED__; + +#ifdef PRAGMA_PACK_SUPPORTED +#pragma pack(PACK_END) +#endif + +/* + * UDP kernel structures and variables. + */ +struct udpiphdr { + struct ipovly ui_i; /* overlaid ip structure */ + struct udphdr ui_u; /* udp header */ +}; +#define ui_next ui_i.ih_next +#define ui_prev ui_i.ih_prev +#define ui_x1 ui_i.ih_x1 +#define ui_pr ui_i.ih_pr +#define ui_len ui_i.ih_len +#define ui_src ui_i.ih_src +#define ui_dst ui_i.ih_dst +#define ui_sport ui_u.uh_sport +#define ui_dport ui_u.uh_dport +#define ui_ulen ui_u.uh_ulen +#define ui_sum ui_u.uh_sum + +struct udpstat { + /* input statistics: */ + u_long udps_ipackets; /* total input packets */ + u_long udps_hdrops; /* packet shorter than header */ + u_long udps_badsum; /* checksum error */ + u_long udps_badlen; /* data length larger than packet */ + u_long udps_noport; /* no socket on port */ + u_long udps_noportbcast; /* of above, arrived as broadcast */ + u_long udps_fullsock; /* not delivered, input socket full */ + u_long udpps_pcbcachemiss; /* input packets missing pcb cache */ + /* output statistics: */ + u_long udps_opackets; /* total output packets */ +}; + +/* + * Names for UDP sysctl objects + */ +#define UDPCTL_CHECKSUM 1 /* checksum UDP packets */ +#define UDPCTL_MAXID 2 + +extern struct udpstat udpstat; +extern struct SLIRPsocket udb; +struct SLIRPmbuf; + +void udp_init _P((void)); +void udp_input _P((register struct SLIRPmbuf *, int)); +int udp_output _P((struct SLIRPsocket *, struct SLIRPmbuf *, struct sockaddr_in *)); +int udp_attach _P((struct SLIRPsocket *)); +void udp_detach _P((struct SLIRPsocket *)); +u_int8_t udp_tos _P((struct SLIRPsocket *)); +void udp_emu _P((struct SLIRPsocket *, struct SLIRPmbuf *)); +struct SLIRPsocket * udp_listen _P((u_int, u_int32_t, u_int, int)); +int udp_output2(struct SLIRPsocket *so, struct SLIRPmbuf *m, + struct sockaddr_in *saddr, struct sockaddr_in *daddr, + int iptos); +#endif diff --git a/src/sound.c b/src/sound.c new file mode 100644 index 000000000..1fedb4c79 --- /dev/null +++ b/src/sound.c @@ -0,0 +1,230 @@ +#include +#include +#include "ibm.h" +#include "device.h" + +#include "filters.h" + +#include "sound_opl.h" + +#include "sound.h" +#include "sound_adlib.h" +#include "sound_adlibgold.h" +#include "sound_pas16.h" +#include "sound_sb.h" +#include "sound_sb_dsp.h" +#include "sound_wss.h" + +#include "timer.h" +#include "thread.h" + +int sound_card_current = 0; +static int sound_card_last = 0; + +typedef struct +{ + char name[32]; + device_t *device; +} SOUND_CARD; + +static SOUND_CARD sound_cards[] = +{ + {"None", NULL}, + {"Adlib", &adlib_device}, + {"Sound Blaster 1.0", &sb_1_device}, + {"Sound Blaster 1.5", &sb_15_device}, + {"Sound Blaster 2.0", &sb_2_device}, + {"Sound Blaster Pro v1", &sb_pro_v1_device}, + {"Sound Blaster Pro v2", &sb_pro_v2_device}, + {"Sound Blaster 16", &sb_16_device}, + {"Sound Blaster AWE32", &sb_awe32_device}, + {"Adlib Gold", &adgold_device}, + {"Windows Sound System", &wss_device}, + {"Pro Audio Spectrum 16", &pas16_device}, + {"", NULL} +}; + +int sound_card_available(int card) +{ + if (sound_cards[card].device) + return device_available(sound_cards[card].device); + + return 1; +} + +char *sound_card_getname(int card) +{ + return sound_cards[card].name; +} + +device_t *sound_card_getdevice(int card) +{ + return sound_cards[card].device; +} + +int sound_card_has_config(int card) +{ + if (!sound_cards[card].device) + return 0; + return sound_cards[card].device->config ? 1 : 0; +} + +void sound_card_init() +{ + if (sound_cards[sound_card_current].device) + device_add(sound_cards[sound_card_current].device); + sound_card_last = sound_card_current; +} + +static struct +{ + void (*get_buffer)(int32_t *buffer, int len, void *p); + void *priv; +} sound_handlers[8]; + +static int sound_handlers_num; + +static int sound_poll_time = 0, sound_get_buffer_time = 0, sound_poll_latch; +int sound_pos_global = 0; + +int soundon = 1; + +static int16_t cd_buffer[CD_BUFLEN * 2]; +static thread_t *sound_cd_thread_h; +static event_t *sound_cd_event; +static unsigned int cd_vol_l, cd_vol_r; + +void sound_set_cd_volume(unsigned int vol_l, unsigned int vol_r) +{ + cd_vol_l = vol_l; + cd_vol_r = vol_r; +} + +static void sound_cd_thread(void *param) +{ + while (1) + { + int c; + + thread_wait_event(sound_cd_event, -1); + ioctl_audio_callback(cd_buffer, CD_BUFLEN*2); + if (soundon) + { + int32_t atapi_vol_l = atapi_get_cd_volume(0); + int32_t atapi_vol_r = atapi_get_cd_volume(1); + int channel_select[2]; + + channel_select[0] = atapi_get_cd_channel(0); + channel_select[1] = atapi_get_cd_channel(1); + + for (c = 0; c < CD_BUFLEN*2; c += 2) + { + int32_t cd_buffer_temp[2] = {0, 0}; + + /*First, adjust input from drive according to ATAPI volume.*/ + cd_buffer[c] = ((int32_t)cd_buffer[c] * atapi_vol_l) / 255; + cd_buffer[c+1] = ((int32_t)cd_buffer[c+1] * atapi_vol_r) / 255; + + /*Apply ATAPI channel select*/ + if (channel_select[0] & 1) + cd_buffer_temp[0] += cd_buffer[c]; + if (channel_select[0] & 2) + cd_buffer_temp[1] += cd_buffer[c]; + if (channel_select[1] & 1) + cd_buffer_temp[0] += cd_buffer[c+1]; + if (channel_select[1] & 2) + cd_buffer_temp[1] += cd_buffer[c+1]; + + /*Apply sound card CD volume*/ + cd_buffer_temp[0] = (cd_buffer_temp[0] * (int)cd_vol_l) / 65535; + cd_buffer_temp[1] = (cd_buffer_temp[1] * (int)cd_vol_r) / 65535; + + if (cd_buffer_temp[0] > 32767) + cd_buffer_temp[0] = 32767; + if (cd_buffer_temp[0] < -32768) + cd_buffer_temp[0] = -32768; + if (cd_buffer_temp[1] > 32767) + cd_buffer_temp[1] = 32767; + if (cd_buffer_temp[1] < -32768) + cd_buffer_temp[1] = -32768; + + cd_buffer[c] = cd_buffer_temp[0]; + cd_buffer[c+1] = cd_buffer_temp[1]; + } + + givealbuffer_cd(cd_buffer); + } + } +} + +static int32_t *outbuffer; + +void sound_init() +{ + initalmain(0,NULL); + inital(); + + outbuffer = malloc(SOUNDBUFLEN * 2 * sizeof(int32_t)); + + sound_cd_event = thread_create_event(); + sound_cd_thread_h = thread_create(sound_cd_thread, NULL); +} + +void sound_add_handler(void (*get_buffer)(int32_t *buffer, int len, void *p), void *p) +{ + sound_handlers[sound_handlers_num].get_buffer = get_buffer; + sound_handlers[sound_handlers_num].priv = p; + sound_handlers_num++; +} + +void sound_poll(void *priv) +{ + sound_poll_time += sound_poll_latch; + + sound_pos_global++; + if (sound_pos_global == SOUNDBUFLEN) + { + int c; +/* int16_t buf16[SOUNDBUFLEN * 2 ];*/ + + memset(outbuffer, 0, SOUNDBUFLEN * 2 * sizeof(int32_t)); + + for (c = 0; c < sound_handlers_num; c++) + sound_handlers[c].get_buffer(outbuffer, SOUNDBUFLEN, sound_handlers[c].priv); + + +/* for (c=0;c 32767) + buf16[c] = 32767; + else + buf16[c] = outbuffer[c]; + } + + if (!soundf) soundf=fopen("sound.pcm","wb"); + fwrite(buf16,(SOUNDBUFLEN)*2*2,1,soundf);*/ + + if (soundon) givealbuffer(outbuffer); + + thread_set_event(sound_cd_event); + + sound_pos_global = 0; + } +} + +void sound_speed_changed() +{ + sound_poll_latch = (int)((double)TIMER_USEC * (1000000.0 / 48000.0)); +} + +void sound_reset() +{ + timer_add(sound_poll, &sound_poll_time, TIMER_ALWAYS_ENABLED, NULL); + + sound_handlers_num = 0; + + sound_set_cd_volume(65535, 65535); + ioctl_audio_stop(); +} diff --git a/src/sound.h b/src/sound.h new file mode 100644 index 000000000..352d0cf41 --- /dev/null +++ b/src/sound.h @@ -0,0 +1,20 @@ +#include "timer.h" + +void sound_add_handler(void (*get_buffer)(int32_t *buffer, int len, void *p), void *p); + +extern int sbtype; + +extern int sound_card_current; + +int sound_card_available(int card); +char *sound_card_getname(int card); +struct device_t *sound_card_getdevice(int card); +int sound_card_has_config(int card); +void sound_card_init(); +void sound_set_cd_volume(unsigned int vol_l, unsigned int vol_r); + +#define CD_FREQ 44100 +#define CD_BUFLEN (CD_FREQ / 10) + +extern int sound_pos_global; +void sound_speed_changed(); diff --git a/src/sound_ad1848.c b/src/sound_ad1848.c new file mode 100644 index 000000000..9dd339bce --- /dev/null +++ b/src/sound_ad1848.c @@ -0,0 +1,219 @@ +/*PCem v0.8 by Tom Walker + + AD1848 CODEC emulation (Windows Sound System compatible)*/ + +#include "ibm.h" +#include "sound.h" +#include "sound_ad1848.h" + +static int ad1848_vols[64]; + +void ad1848_setirq(ad1848_t *ad1848, int irq) +{ + ad1848->irq = irq; +} + +void ad1848_setdma(ad1848_t *ad1848, int dma) +{ + ad1848->dma = dma; +} + +uint8_t ad1848_read(uint16_t addr, void *p) +{ + ad1848_t *ad1848 = (ad1848_t *)p; + uint8_t temp = 0xff; +// pclog("ad1848_read - addr %04X %04X(%08X):%08X ", addr, CS, cs, pc); + switch (addr & 3) + { + case 0: /*Index*/ + temp = ad1848->index | ad1848->trd | ad1848->mce; + break; + case 1: + temp = ad1848->regs[ad1848->index]; + break; + case 2: + temp = ad1848->status; + break; + } +// pclog("return %02X\n", temp); + return temp; +} + +void ad1848_write(uint16_t addr, uint8_t val, void *p) +{ + ad1848_t *ad1848 = (ad1848_t *)p; + double freq; +// pclog("ad1848_write - addr %04X val %02X %04X(%08X):%08X\n", addr, val, CS, cs, pc); + switch (addr & 3) + { + case 0: /*Index*/ + ad1848->index = val & 0xf; + ad1848->trd = val & 0x20; + ad1848->mce = val & 0x40; + break; + case 1: + switch (ad1848->index) + { + case 8: + freq = (val & 1) ? 16934400 : 24576000; + switch ((val >> 1) & 7) + { + case 0: freq /= 3072; break; + case 1: freq /= 1536; break; + case 2: freq /= 896; break; + case 3: freq /= 768; break; + case 4: freq /= 448; break; + case 5: freq /= 384; break; + case 6: freq /= 512; break; + case 7: freq /= 2560; break; + } + ad1848->freq = freq; + ad1848->timer_latch = (int)((double)TIMER_USEC * (1000000.0 / (double)ad1848->freq)); + break; + + case 9: + ad1848->enable = ((val & 0x41) == 0x01); + if (!ad1848->enable) + ad1848->out_l = ad1848->out_r = 0; + break; + + case 12: + return; + + case 14: + ad1848->count = ad1848->regs[15] | (val << 8); + break; + } + ad1848->regs[ad1848->index] = val; + break; + case 2: + ad1848->status &= 0xfe; + break; + } +} + +void ad1848_speed_changed(ad1848_t *ad1848) +{ + ad1848->timer_latch = (int)((double)TIMER_USEC * (1000000.0 / (double)ad1848->freq)); +} + +void ad1848_update(ad1848_t *ad1848) +{ + for (; ad1848->pos < sound_pos_global; ad1848->pos++) + { + ad1848->buffer[ad1848->pos*2] = ad1848->out_l; + ad1848->buffer[ad1848->pos*2 + 1] = ad1848->out_r; + } +} + +static void ad1848_poll(void *p) +{ + ad1848_t *ad1848 = (ad1848_t *)p; + + if (ad1848->timer_latch) + ad1848->timer_count += ad1848->timer_latch; + else + ad1848->timer_count = TIMER_USEC; + + ad1848_update(ad1848); + + if (ad1848->enable) + { + int32_t temp; + + switch (ad1848->regs[8] & 0x70) + { + case 0x00: /*Mono, 8-bit PCM*/ + ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; + break; + case 0x10: /*Stereo, 8-bit PCM*/ + ad1848->out_l = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; + ad1848->out_r = (dma_channel_read(ad1848->dma) ^ 0x80) * 256; + break; + + case 0x40: /*Mono, 16-bit PCM*/ + temp = dma_channel_read(ad1848->dma); + ad1848->out_l = ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp; + break; + case 0x50: /*Stereo, 16-bit PCM*/ + temp = dma_channel_read(ad1848->dma); + ad1848->out_l = (dma_channel_read(ad1848->dma) << 8) | temp; + temp = dma_channel_read(ad1848->dma); + ad1848->out_r = (dma_channel_read(ad1848->dma) << 8) | temp; + break; + } + + if (ad1848->regs[6] & 0x80) + ad1848->out_l = 0; + else + ad1848->out_l = (ad1848->out_l * ad1848_vols[ad1848->regs[6] & 0x3f]) >> 16; + + if (ad1848->regs[7] & 0x80) + ad1848->out_r = 0; + else + ad1848->out_r = (ad1848->out_r * ad1848_vols[ad1848->regs[7] & 0x3f]) >> 16; + + if (ad1848->count < 0) + { + ad1848->count = ad1848->regs[15] | (ad1848->regs[14] << 8); + if (!(ad1848->status & 0x01)) + { + ad1848->status |= 0x01; + if (ad1848->regs[0xa] & 2) + picint(1 << ad1848->irq); + } + } + + ad1848->count--; +// pclog("ad1848_poll : enable %X %X %X %X %X %X\n", ad1848->pcm_buffer[0][ad1848->pos], ad1848->pcm_buffer[1][ad1848->pos], ad1848->out_l[0], ad1848->out_r[0], ad1848->out_l[1], ad1848->out_r[1]); + } + else + { + ad1848->out_l = ad1848->out_r = 0; +// pclog("ad1848_poll : not enable\n"); + } +} + +void ad1848_init(ad1848_t *ad1848) +{ + int c; + double attenuation; + + ad1848->enable = 0; + + ad1848->status = 0xcc; + ad1848->index = ad1848->trd = 0; + ad1848->mce = 0x40; + + ad1848->regs[0] = ad1848->regs[1] = 0; + ad1848->regs[2] = ad1848->regs[3] = 0x80; + ad1848->regs[4] = ad1848->regs[5] = 0x80; + ad1848->regs[6] = ad1848->regs[7] = 0x80; + ad1848->regs[8] = 0; + ad1848->regs[9] = 0x08; + ad1848->regs[10] = ad1848->regs[11] = 0; + ad1848->regs[12] = 0xa; + ad1848->regs[13] = 0; + ad1848->regs[14] = ad1848->regs[15] = 0; + + ad1848->out_l = 0; + ad1848->out_r = 0; + + for (c = 0; c < 64; c++) + { + attenuation = 0.0; + if (c & 0x01) attenuation -= 1.5; + if (c & 0x02) attenuation -= 3.0; + if (c & 0x04) attenuation -= 6.0; + if (c & 0x08) attenuation -= 12.0; + if (c & 0x10) attenuation -= 24.0; + if (c & 0x20) attenuation -= 48.0; + + attenuation = pow(10, attenuation / 10); + + ad1848_vols[c] = (int)(attenuation * 65536); +// pclog("ad1848_vols %i = %f %i\n", c, attenuation, ad1848_vols[c]); + } + + timer_add(ad1848_poll, &ad1848->timer_count, &ad1848->enable, ad1848); +} diff --git a/src/sound_ad1848.h b/src/sound_ad1848.h new file mode 100644 index 000000000..b97e1e499 --- /dev/null +++ b/src/sound_ad1848.h @@ -0,0 +1,35 @@ +#include "timer.h" + +typedef struct ad1848_t +{ + int index; + uint8_t regs[16]; + uint8_t status; + + int trd; + int mce; + + int count; + + int16_t out_l, out_r; + + int enable; + + int irq, dma; + + int freq; + + int timer_count, timer_latch; + + int16_t buffer[SOUNDBUFLEN * 2]; + int pos; +} ad1848_t; + +void ad1848_setirq(ad1848_t *ad1848, int irq); +void ad1848_setdma(ad1848_t *ad1848, int dma); + +uint8_t ad1848_read(uint16_t addr, void *p); +void ad1848_write(uint16_t addr, uint8_t val, void *p); + +void ad1848_update(ad1848_t *ad1848); +void ad1848_speed_changed(ad1848_t *ad1848); diff --git a/src/sound_adlib.c b/src/sound_adlib.c new file mode 100644 index 000000000..f4e24bb44 --- /dev/null +++ b/src/sound_adlib.c @@ -0,0 +1,56 @@ +#include +#include "ibm.h" +#include "device.h" +#include "sound.h" + +#include "sound_adlib.h" +#include "sound_opl.h" + +typedef struct adlib_t +{ + opl_t opl; +} adlib_t; + +static void adlib_get_buffer(int32_t *buffer, int len, void *p) +{ + adlib_t *adlib = (adlib_t *)p; + int c; + + opl2_update2(&adlib->opl); + + for (c = 0; c < len * 2; c++) + buffer[c] += (int32_t)adlib->opl.buffer[c]; + + adlib->opl.pos = 0; +} + +void *adlib_init() +{ + adlib_t *adlib = malloc(sizeof(adlib_t)); + memset(adlib, 0, sizeof(adlib_t)); + + pclog("adlib_init\n"); + opl2_init(&adlib->opl); + io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &adlib->opl); + sound_add_handler(adlib_get_buffer, adlib); + return adlib; +} + +void adlib_close(void *p) +{ + adlib_t *adlib = (adlib_t *)p; + + free(adlib); +} + +device_t adlib_device = +{ + "AdLib", + 0, + adlib_init, + adlib_close, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/sound_adlib.h b/src/sound_adlib.h new file mode 100644 index 000000000..c8db01482 --- /dev/null +++ b/src/sound_adlib.h @@ -0,0 +1 @@ +extern device_t adlib_device; diff --git a/src/sound_adlibgold.c b/src/sound_adlibgold.c new file mode 100644 index 000000000..a0f0956a9 --- /dev/null +++ b/src/sound_adlibgold.c @@ -0,0 +1,863 @@ +#include +#include +#include "ibm.h" +#include "device.h" + +#include "sound_opl.h" +#include "sound_ym7128.h" +#include "dma.h" +#include "io.h" +#include "pic.h" +#include "pit.h" +#include "sound.h" +#include "timer.h" + +#include "filters.h" + +typedef struct adgold_t +{ + int adgold_irq_status; + + uint8_t adgold_eeprom[0x19]; + + uint8_t adgold_status; + int adgold_38x_state, adgold_38x_addr; + uint8_t adgold_38x_regs[0x19]; + + int adgold_mma_addr; + uint8_t adgold_mma_regs[2][0xe]; + + int adgold_mma_enable[2]; + uint8_t adgold_mma_fifo[2][256]; + int adgold_mma_fifo_start[2], adgold_mma_fifo_end[2]; + uint8_t adgold_mma_status; + + int16_t adgold_mma_out[2]; + int adgold_mma_intpos[2]; + + int adgold_mma_timer_count; + + struct + { + int timer0_latch, timer0_count; + int timerbase_latch, timerbase_count; + int timer1_latch, timer1_count; + int timer2_latch, timer2_count, timer2_read; + + int voice_count[2], voice_latch[2]; + } adgold_mma; + + opl_t opl; + ym7128_t ym7128; + + int fm_vol_l, fm_vol_r; + int samp_vol_l, samp_vol_r; + int vol_l, vol_r; + int treble, bass; + + int16_t opl_buffer[SOUNDBUFLEN * 2]; + int16_t mma_buffer[2][SOUNDBUFLEN]; + + int pos; + + int surround_enabled; +} adgold_t; + +static int attenuation[0x40]; +static int bass_attenuation[0x10] = +{ + (int)(1.995 * 16384), /*12 dB - filter output is at +6 dB so we use 6 dB here*/ + (int)(1.995 * 16384), + (int)(1.995 * 16384), + (int)(1.413 * 16384), /*9 dB*/ + (int)(1 * 16384), /*6 dB*/ + (int)(0.708 * 16384), /*3 dB*/ + (int)(0 * 16384), /*0 dB*/ + (int)(0.708 * 16384), /*3 dB*/ + (int)(1 * 16384), /*6 dB*/ + (int)(1.413 * 16384), /*9 dB*/ + (int)(1.995 * 16384), /*12 dB*/ + (int)(2.819 * 16384), /*15 dB*/ + (int)(2.819 * 16384), + (int)(2.819 * 16384), + (int)(2.819 * 16384), + (int)(2.819 * 16384) +}; + +static int bass_cut[6] = +{ + (int)(0.126 * 16384), /*-12 dB*/ + (int)(0.126 * 16384), /*-12 dB*/ + (int)(0.126 * 16384), /*-12 dB*/ + (int)(0.178 * 16384), /*-9 dB*/ + (int)(0.251 * 16384), /*-6 dB*/ + (int)(0.354 * 16384) /*-3 dB - filter output is at +6 dB*/ +}; + +static int treble_attenuation[0x10] = +{ + (int)(1.995 * 16384), /*12 dB - filter output is at +6 dB so we use 6 dB here*/ + (int)(1.995 * 16384), + (int)(1.995 * 16384), + (int)(1.413 * 16384), /*9 dB*/ + (int)(1 * 16384), /*6 dB*/ + (int)(0.708 * 16384), /*3 dB*/ + (int)(0 * 16384), /*0 dB*/ + (int)(0.708 * 16384), /*3 dB*/ + (int)(1 * 16384), /*6 dB*/ + (int)(1.413 * 16384), /*9 dB*/ + (int)(1.995 * 16384), /*12 dB*/ + (int)(1.995 * 16384), + (int)(1.995 * 16384), + (int)(1.995 * 16384), + (int)(1.995 * 16384), + (int)(1.995 * 16384) +}; + +static int treble_cut[6] = +{ + (int)(0.126 * 16384), /*-12 dB*/ + (int)(0.126 * 16384), /*-12 dB*/ + (int)(0.126 * 16384), /*-12 dB*/ + (int)(0.178 * 16384), /*-9 dB*/ + (int)(0.251 * 16384), /*-6 dB*/ + (int)(0.354 * 16384) /*-3 dB - filter output is at +6 dB*/ +}; + +void adgold_timer_poll(); +void adgold_update(adgold_t *adgold); + +void adgold_update_irq_status(adgold_t *adgold) +{ + uint8_t temp = 0xf; + + if (!(adgold->adgold_mma_regs[0][8] & 0x10) && (adgold->adgold_mma_status & 0x10)) /*Timer 0*/ + temp &= ~2; + if (!(adgold->adgold_mma_regs[0][8] & 0x20) && (adgold->adgold_mma_status & 0x20)) /*Timer 1*/ + temp &= ~2; + if (!(adgold->adgold_mma_regs[0][8] & 0x40) && (adgold->adgold_mma_status & 0x40)) /*Timer 2*/ + temp &= ~2; + + if ((adgold->adgold_mma_status & 0x01) && !(adgold->adgold_mma_regs[0][0xc] & 2)) + temp &= ~2; + if ((adgold->adgold_mma_status & 0x02) && !(adgold->adgold_mma_regs[1][0xc] & 2)) + temp &= ~2; + adgold->adgold_status = temp; + + if ((adgold->adgold_status ^ 0xf) && !adgold->adgold_irq_status) + { +// pclog("adgold irq %02X\n", adgold->adgold_status); + picint(0x80); + } + + adgold->adgold_irq_status = adgold->adgold_status ^ 0xf; +} + +void adgold_getsamp_dma(adgold_t *adgold, int channel) +{ + int temp; + + if ((adgold->adgold_mma_regs[channel][0xc] & 0x60) && (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) >= 127)) + return; + + temp = dma_channel_read(1); +// pclog("adgold DMA1 return %02X %i L\n", temp, channel); + if (temp == DMA_NODATA) return; + adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_end[channel]] = temp; + adgold->adgold_mma_fifo_end[channel] = (adgold->adgold_mma_fifo_end[channel] + 1) & 255; + if (adgold->adgold_mma_regs[channel][0xc] & 0x60) + { + temp = dma_channel_read(1); +// pclog("adgold DMA1 return %02X %i H\n", temp, channel); + adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_end[channel]] = temp; + adgold->adgold_mma_fifo_end[channel] = (adgold->adgold_mma_fifo_end[channel] + 1) & 255; + } + if (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) >= adgold->adgold_mma_intpos[channel]) + { + adgold->adgold_mma_status &= ~(0x01 << channel); + adgold_update_irq_status(adgold); + } +} + +void adgold_write(uint16_t addr, uint8_t val, void *p) +{ + adgold_t *adgold = (adgold_t *)p; +// if (addr > 0x389) pclog("adgold_write : addr %04X val %02X %04X:%04X\n", addr, val, CS, pc); + switch (addr & 7) + { + case 0: case 1: + opl3_write(addr, val, &adgold->opl); + break; + + case 2: + if (val == 0xff) + { + adgold->adgold_38x_state = 1; + return; + } + if (val == 0xfe) + { + adgold->adgold_38x_state = 0; + return; + } + if (adgold->adgold_38x_state) /*Write to control chip*/ + adgold->adgold_38x_addr = val; + else + opl3_write(addr, val, &adgold->opl); + break; + case 3: + if (adgold->adgold_38x_state) + { + if (adgold->adgold_38x_addr >= 0x19) break; + switch (adgold->adgold_38x_addr) + { + case 0x00: /*Control/ID*/ + if (val & 1) + memcpy(adgold->adgold_38x_regs, adgold->adgold_eeprom, 0x19); + if (val & 2) + memcpy(adgold->adgold_eeprom, adgold->adgold_38x_regs, 0x19); + break; + + case 0x04: /*Final output volume left*/ + adgold->adgold_38x_regs[0x04] = val; + adgold->vol_l = attenuation[val & 0x3f]; + break; + case 0x05: /*Final output volume right*/ + adgold->adgold_38x_regs[0x05] = val; + adgold->vol_r = attenuation[val & 0x3f]; + break; + case 0x06: /*Bass*/ + adgold->adgold_38x_regs[0x06] = val; + adgold->bass = val & 0xf; + break; + case 0x07: /*Treble*/ + adgold->adgold_38x_regs[0x07] = val; + adgold->treble = val & 0xf; + break; + + case 0x09: /*FM volume left*/ + adgold->adgold_38x_regs[0x09] = val; + adgold->fm_vol_l = (int)(int8_t)(val - 128); + break; + case 0x0a: /*FM volume right*/ + adgold->adgold_38x_regs[0x0a] = val; + adgold->fm_vol_r = (int)(int8_t)(val - 128); + break; + case 0x0b: /*Sample volume left*/ + adgold->adgold_38x_regs[0x0b] = val; + adgold->samp_vol_l = (int)(int8_t)(val - 128); + break; + case 0x0c: /*Sample volume right*/ + adgold->adgold_38x_regs[0x0c] = val; + adgold->samp_vol_r = (int)(int8_t)(val - 128); + break; + + case 0x18: /*Surround*/ + adgold->adgold_38x_regs[0x18] = val; + ym7128_write(&adgold->ym7128, val); + break; + + default: + adgold->adgold_38x_regs[adgold->adgold_38x_addr] = val; + break; + } + } + else + opl3_write(addr, val, &adgold->opl); + break; + case 4: case 6: + adgold->adgold_mma_addr = val; + break; + case 5: + if (adgold->adgold_mma_addr >= 0xf) break; + switch (adgold->adgold_mma_addr) + { + case 0x2: + adgold->adgold_mma.timer0_latch = (adgold->adgold_mma.timer0_latch & 0xff00) | val; + break; + case 0x3: + adgold->adgold_mma.timer0_latch = (adgold->adgold_mma.timer0_latch & 0xff) | (val << 8); + break; + case 0x4: + adgold->adgold_mma.timerbase_latch = (adgold->adgold_mma.timerbase_latch & 0xf00) | val; + break; + case 0x5: + adgold->adgold_mma.timerbase_latch = (adgold->adgold_mma.timerbase_latch & 0xff) | ((val & 0xf) << 8); + adgold->adgold_mma.timer1_latch = val >> 4; + break; + case 0x6: + adgold->adgold_mma.timer2_latch = (adgold->adgold_mma.timer2_latch & 0xff00) | val; + break; + case 0x7: + adgold->adgold_mma.timer2_latch = (adgold->adgold_mma.timer2_latch & 0xff) | (val << 8); + break; + + case 0x8: + if ((val & 1) && !(adgold->adgold_mma_regs[0][8] & 1)) /*Reload timer 0*/ + adgold->adgold_mma.timer0_count = adgold->adgold_mma.timer0_latch; + + if ((val & 2) && !(adgold->adgold_mma_regs[0][8] & 2)) /*Reload timer 1*/ + adgold->adgold_mma.timer1_count = adgold->adgold_mma.timer1_latch; + + if ((val & 4) && !(adgold->adgold_mma_regs[0][8] & 4)) /*Reload timer 2*/ + adgold->adgold_mma.timer2_count = adgold->adgold_mma.timer2_latch; + + if ((val & 8) && !(adgold->adgold_mma_regs[0][8] & 8)) /*Reload base timer*/ + adgold->adgold_mma.timerbase_count = adgold->adgold_mma.timerbase_latch; + break; + + case 0x9: + switch (val & 0x18) + { + case 0x00: adgold->adgold_mma.voice_latch[0] = 12; break; /*44100 Hz*/ + case 0x08: adgold->adgold_mma.voice_latch[0] = 24; break; /*22050 Hz*/ + case 0x10: adgold->adgold_mma.voice_latch[0] = 48; break; /*11025 Hz*/ + case 0x18: adgold->adgold_mma.voice_latch[0] = 72; break; /* 7350 Hz*/ + } + if (val & 0x80) + { + adgold->adgold_mma_enable[0] = 0; + adgold->adgold_mma_fifo_end[0] = adgold->adgold_mma_fifo_start[0] = 0; + adgold->adgold_mma_status &= ~0x01; + adgold_update_irq_status(adgold); + } + if ((val & 0x01)) /*Start playback*/ + { + if (!(adgold->adgold_mma_regs[0][0x9] & 1)) + adgold->adgold_mma.voice_count[0] = adgold->adgold_mma.voice_latch[0]; + +// pclog("adgold start! FIFO fill %i %i %i %02X\n", (adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255, adgold->adgold_mma_fifo_end[0], adgold->adgold_mma_fifo_start[0], adgold->adgold_mma_regs[0][0xc]); + if (adgold->adgold_mma_regs[0][0xc] & 1) + { + if (adgold->adgold_mma_regs[0][0xc] & 0x80) + { +// pclog("adgold start interleaved %i %i + adgold->adgold_mma_enable[1] = 1; + adgold->adgold_mma.voice_count[1] = adgold->adgold_mma.voice_latch[1]; + + while (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) < 128) + { + adgold_getsamp_dma(adgold, 0); + adgold_getsamp_dma(adgold, 1); + } + if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) >= adgold->adgold_mma_intpos[0]) + { + adgold->adgold_mma_status &= ~0x01; + adgold_update_irq_status(adgold); + } + if (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) >= adgold->adgold_mma_intpos[1]) + { + adgold->adgold_mma_status &= ~0x02; + adgold_update_irq_status(adgold); + } + } + else + { + while (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) < 128) + { + adgold_getsamp_dma(adgold, 0); + } + if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) >= adgold->adgold_mma_intpos[0]) + { + adgold->adgold_mma_status &= ~0x01; + adgold_update_irq_status(adgold); + } + } + } +// pclog("adgold end\n"); + } + adgold->adgold_mma_enable[0] = val & 0x01; + break; + + case 0xb: + if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) < 128) + { + adgold->adgold_mma_fifo[0][adgold->adgold_mma_fifo_end[0]] = val; + adgold->adgold_mma_fifo_end[0] = (adgold->adgold_mma_fifo_end[0] + 1) & 255; + if (((adgold->adgold_mma_fifo_end[0] - adgold->adgold_mma_fifo_start[0]) & 255) >= adgold->adgold_mma_intpos[0]) + { + adgold->adgold_mma_status &= ~0x01; + adgold_update_irq_status(adgold); + } + } + break; + + case 0xc: + adgold->adgold_mma_intpos[0] = (7 - ((val >> 2) & 7)) * 8; + break; + } + adgold->adgold_mma_regs[0][adgold->adgold_mma_addr] = val; + break; + case 7: + if (adgold->adgold_mma_addr >= 0xf) break; + switch (adgold->adgold_mma_addr) + { + case 0x9: + adgold_update(adgold); + switch (val & 0x18) + { + case 0x00: adgold->adgold_mma.voice_latch[1] = 12; break; /*44100 Hz*/ + case 0x08: adgold->adgold_mma.voice_latch[1] = 24; break; /*22050 Hz*/ + case 0x10: adgold->adgold_mma.voice_latch[1] = 48; break; /*11025 Hz*/ + case 0x18: adgold->adgold_mma.voice_latch[1] = 72; break; /* 7350 Hz*/ + } + if (val & 0x80) + { + adgold->adgold_mma_enable[1] = 0; + adgold->adgold_mma_fifo_end[1] = adgold->adgold_mma_fifo_start[1] = 0; + adgold->adgold_mma_status &= ~0x02; + adgold_update_irq_status(adgold); + } + if ((val & 0x01)) /*Start playback*/ + { + if (!(adgold->adgold_mma_regs[1][0x9] & 1)) + adgold->adgold_mma.voice_count[1] = adgold->adgold_mma.voice_latch[1]; + +// pclog("adgold start! FIFO fill %i %i %i %02X\n", (adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255, adgold->adgold_mma_fifo_end[1], adgold->adgold_mma_fifo_start[1], adgold->adgold_mma_regs[1][0xc]); + if (adgold->adgold_mma_regs[1][0xc] & 1) + { + while (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) < 128) + { + adgold_getsamp_dma(adgold, 1); + } + } +// pclog("adgold end\n"); + } + adgold->adgold_mma_enable[1] = val & 0x01; + break; + + case 0xb: + if (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) < 128) + { + adgold->adgold_mma_fifo[1][adgold->adgold_mma_fifo_end[1]] = val; + adgold->adgold_mma_fifo_end[1] = (adgold->adgold_mma_fifo_end[1] + 1) & 255; + if (((adgold->adgold_mma_fifo_end[1] - adgold->adgold_mma_fifo_start[1]) & 255) >= adgold->adgold_mma_intpos[1]) + { + adgold->adgold_mma_status &= ~0x02; + adgold_update_irq_status(adgold); + } + } + break; + + case 0xc: + adgold->adgold_mma_intpos[1] = (7 - ((val >> 2) & 7)) * 8; + break; + } + adgold->adgold_mma_regs[1][adgold->adgold_mma_addr] = val; + break; + } +} + +uint8_t adgold_read(uint16_t addr, void *p) +{ + adgold_t *adgold = (adgold_t *)p; + uint8_t temp; + + switch (addr & 7) + { + case 0: case 1: + temp = opl3_read(addr, &adgold->opl); + break; + + case 2: + if (adgold->adgold_38x_state) /*Read from control chip*/ + temp = adgold->adgold_status; + else + temp = opl3_read(addr, &adgold->opl); + break; + + case 3: + if (adgold->adgold_38x_state) + { + if (adgold->adgold_38x_addr >= 0x19) temp = 0xff; + switch (adgold->adgold_38x_addr) + { + case 0x00: /*Control/ID*/ + if (adgold->surround_enabled) + temp = 0x50; /*16-bit ISA, surround module, no telephone/CDROM*/ + else + temp = 0x70; /*16-bit ISA, no telephone/surround/CD-ROM*/ + break; + + default: + temp = adgold->adgold_38x_regs[adgold->adgold_38x_addr]; + } + } + else + temp = opl3_read(addr, &adgold->opl); + break; + + case 4: case 6: + temp = adgold->adgold_mma_status; + adgold->adgold_mma_status = 0; /*JUKEGOLD expects timer status flags to auto-clear*/ + adgold_update_irq_status(adgold); + break; + case 5: + if (adgold->adgold_mma_addr >= 0xf) temp = 0xff; + switch (adgold->adgold_mma_addr) + { + case 6: /*Timer 2 low*/ + adgold->adgold_mma.timer2_read = adgold->adgold_mma.timer2_count; + temp = adgold->adgold_mma.timer2_read & 0xff; + break; + case 7: /*Timer 2 high*/ + temp = adgold->adgold_mma.timer2_read >> 8; + break; + + default: + temp = adgold->adgold_mma_regs[0][adgold->adgold_mma_addr]; + break; + } + break; + case 7: + if (adgold->adgold_mma_addr >= 0xf) temp = 0xff; + temp = adgold->adgold_mma_regs[1][adgold->adgold_mma_addr]; + break; + } +// if (addr > 0x389) pclog("adgold_read : addr %04X %02X\n", addr, temp); + return temp; +} + +void adgold_update(adgold_t *adgold) +{ + for (; adgold->pos < sound_pos_global; adgold->pos++) + { + adgold->mma_buffer[0][adgold->pos] = adgold->mma_buffer[1][adgold->pos] = 0; + + if (adgold->adgold_mma_regs[0][9] & 0x20) + adgold->mma_buffer[0][adgold->pos] += adgold->adgold_mma_out[0] / 2; + if (adgold->adgold_mma_regs[0][9] & 0x40) + adgold->mma_buffer[1][adgold->pos] += adgold->adgold_mma_out[0] / 2; + + if (adgold->adgold_mma_regs[1][9] & 0x20) + adgold->mma_buffer[0][adgold->pos] += adgold->adgold_mma_out[1] / 2; + if (adgold->adgold_mma_regs[1][9] & 0x40) + adgold->mma_buffer[1][adgold->pos] += adgold->adgold_mma_out[1] / 2; + } +} + +void adgold_mma_poll(adgold_t *adgold, int channel) +{ + int16_t dat; + + adgold_update(adgold); + + if (adgold->adgold_mma_fifo_start[channel] != adgold->adgold_mma_fifo_end[channel]) + { + switch (adgold->adgold_mma_regs[channel][0xc] & 0x60) + { + case 0x00: /*8-bit*/ + dat = adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_start[channel]] * 256; + adgold->adgold_mma_out[channel] = dat; + adgold->adgold_mma_fifo_start[channel] = (adgold->adgold_mma_fifo_start[channel] + 1) & 255; + break; + + case 0x40: /*12-bit sensible format*/ + if (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) < 2) + return; + + dat = adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_start[channel]] & 0xf0; + adgold->adgold_mma_fifo_start[channel] = (adgold->adgold_mma_fifo_start[channel] + 1) & 255; + dat |= (adgold->adgold_mma_fifo[channel][adgold->adgold_mma_fifo_start[channel]] << 8); + adgold->adgold_mma_fifo_start[channel] = (adgold->adgold_mma_fifo_start[channel] + 1) & 255; + adgold->adgold_mma_out[channel] = dat; + break; + } + + if (adgold->adgold_mma_regs[channel][0xc] & 1) + { + adgold_getsamp_dma(adgold, channel); + } + if (((adgold->adgold_mma_fifo_end[channel] - adgold->adgold_mma_fifo_start[channel]) & 255) < adgold->adgold_mma_intpos[channel] && !(adgold->adgold_mma_status & 0x01)) + { +// pclog("adgold_mma_poll - IRQ! %i\n", channel); + adgold->adgold_mma_status |= 1 << channel; + adgold_update_irq_status(adgold); + } + } + if (adgold->adgold_mma_fifo_start[channel] == adgold->adgold_mma_fifo_end[channel]) + { + adgold->adgold_mma_enable[channel] = 0; + } +} + +void adgold_timer_poll(void *p) +{ + adgold_t *adgold = (adgold_t *)p; + + while (adgold->adgold_mma_timer_count <= 0) + { + adgold->adgold_mma_timer_count += (int)((double)TIMER_USEC * 1.88964); + if (adgold->adgold_mma_regs[0][8] & 0x01) /*Timer 0*/ + { + adgold->adgold_mma.timer0_count--; + if (!adgold->adgold_mma.timer0_count) + { + adgold->adgold_mma.timer0_count = adgold->adgold_mma.timer0_latch; +// pclog("Timer 0 interrupt\n"); + adgold->adgold_mma_status |= 0x10; + adgold_update_irq_status(adgold); + } + } + if (adgold->adgold_mma_regs[0][8] & 0x08) /*Base timer*/ + { + adgold->adgold_mma.timerbase_count--; + if (!adgold->adgold_mma.timerbase_count) + { + adgold->adgold_mma.timerbase_count = adgold->adgold_mma.timerbase_latch; + if (adgold->adgold_mma_regs[0][8] & 0x02) /*Timer 1*/ + { + adgold->adgold_mma.timer1_count--; + if (!adgold->adgold_mma.timer1_count) + { + adgold->adgold_mma.timer1_count = adgold->adgold_mma.timer1_latch; +// pclog("Timer 1 interrupt\n"); + adgold->adgold_mma_status |= 0x20; + adgold_update_irq_status(adgold); + } + } + if (adgold->adgold_mma_regs[0][8] & 0x04) /*Timer 2*/ + { + adgold->adgold_mma.timer2_count--; + if (!adgold->adgold_mma.timer2_count) + { + adgold->adgold_mma.timer2_count = adgold->adgold_mma.timer2_latch; +// pclog("Timer 2 interrupt\n"); + adgold->adgold_mma_status |= 0x40; + adgold_update_irq_status(adgold); + } + } + } + } + + if (adgold->adgold_mma_enable[0]) + { + adgold->adgold_mma.voice_count[0]--; + if (!adgold->adgold_mma.voice_count[0]) + { + adgold->adgold_mma.voice_count[0] = adgold->adgold_mma.voice_latch[0]; + adgold_mma_poll(adgold, 0); + } + } + if (adgold->adgold_mma_enable[1]) + { + adgold->adgold_mma.voice_count[1]--; + if (!adgold->adgold_mma.voice_count[1]) + { + adgold->adgold_mma.voice_count[1] = adgold->adgold_mma.voice_latch[1]; + adgold_mma_poll(adgold, 1); + } + } + } +} + +static void adgold_get_buffer(int32_t *buffer, int len, void *p) +{ + adgold_t *adgold = (adgold_t *)p; + int16_t adgold_buffer[len*2]; + + int c; + + opl3_update2(&adgold->opl); + adgold_update(adgold); + + for (c = 0; c < len * 2; c += 2) + { + adgold_buffer[c] = ((adgold->opl.buffer[c] * adgold->fm_vol_l) >> 7) / 2; + adgold_buffer[c] += ((adgold->mma_buffer[0][c >> 1] * adgold->samp_vol_l) >> 7) / 4; + adgold_buffer[c+1] = ((adgold->opl.buffer[c+1] * adgold->fm_vol_r) >> 7) / 2; + adgold_buffer[c+1] += ((adgold->mma_buffer[1][c >> 1] * adgold->samp_vol_r) >> 7) / 4; + } + + if (adgold->surround_enabled) + ym7128_apply(&adgold->ym7128, adgold_buffer, len); + + switch (adgold->adgold_38x_regs[0x8] & 6) + { + case 0: + for (c = 0; c < len * 2; c++) + adgold_buffer[c] = 0; + break; + case 2: /*Left channel only*/ + for (c = 0; c < len * 2; c += 2) + adgold_buffer[c+1] = adgold_buffer[c]; + break; + case 4: /*Right channel only*/ + for (c = 0; c < len * 2; c += 2) + adgold_buffer[c] = adgold_buffer[c+1]; + break; + case 6: /*Left and right channels*/ + break; + } + + switch (adgold->adgold_38x_regs[0x8] & 0x18) + { + case 0x00: /*Forced mono*/ + for (c = 0; c < len * 2; c += 2) + adgold_buffer[c] = adgold_buffer[c+1] = ((int32_t)adgold_buffer[c] + (int32_t)adgold_buffer[c+1]) / 2; + break; + case 0x08: /*Linear stereo*/ + break; + case 0x10: /*Pseudo stereo*/ + /*Filter left channel, leave right channel unchanged*/ + /*Filter cutoff is largely a guess*/ + for (c = 0; c < len * 2; c += 2) + adgold_buffer[c] += adgold_pseudo_stereo_iir(adgold_buffer[c]); + break; + case 0x18: /*Spatial stereo*/ + /*Quite probably wrong, I only have the diagram in the TDA8425 datasheet + and a very vague understanding of how op-amps work to go on*/ + for (c = 0; c < len * 2; c += 2) + { + int16_t l = adgold_buffer[c]; + int16_t r = adgold_buffer[c+1]; + + adgold_buffer[c] += (r / 3) + ((l * 2) / 3); + adgold_buffer[c+1] += (l / 3) + ((r * 2) / 3); + } + break; + } + + for (c = 0; c < len * 2; c += 2) + { + int32_t temp, lowpass, highpass; + + /*Output is deliberately halved to avoid clipping*/ + temp = ((int32_t)adgold_buffer[c] * adgold->vol_l) >> 17; + lowpass = adgold_lowpass_iir(0, temp); + highpass = adgold_highpass_iir(0, temp); + if (adgold->bass > 6) + temp += (lowpass * bass_attenuation[adgold->bass]) >> 14; + else if (adgold->bass < 6) + temp = highpass + ((temp * bass_cut[adgold->bass]) >> 14); + if (adgold->treble > 6) + temp += (highpass * treble_attenuation[adgold->treble]) >> 14; + else if (adgold->treble < 6) + temp = lowpass + ((temp * treble_cut[adgold->treble]) >> 14); + if (temp < -32768) + temp = -32768; + if (temp > 32767) + temp = 32767; + buffer[c] += temp; + + temp = ((int32_t)adgold_buffer[c+1] * adgold->vol_r) >> 17; + lowpass = adgold_lowpass_iir(1, temp); + highpass = adgold_highpass_iir(1, temp); + if (adgold->bass > 6) + temp += (lowpass * bass_attenuation[adgold->bass]) >> 14; + else if (adgold->bass < 6) + temp = highpass + ((temp * bass_cut[adgold->bass]) >> 14); + if (adgold->treble > 6) + temp += (highpass * treble_attenuation[adgold->treble]) >> 14; + else if (adgold->treble < 6) + temp = lowpass + ((temp * treble_cut[adgold->treble]) >> 14); + if (temp < -32768) + temp = -32768; + if (temp > 32767) + temp = 32767; + buffer[c+1] += temp; + } + + adgold->opl.pos = 0; + adgold->pos = 0; +} + + +void *adgold_init() +{ + FILE *f; + int c; + double out; + adgold_t *adgold = malloc(sizeof(adgold_t)); + memset(adgold, 0, sizeof(adgold_t)); + + adgold->surround_enabled = device_get_config_int("surround"); + + opl3_init(&adgold->opl); + if (adgold->surround_enabled) + ym7128_init(&adgold->ym7128); + + out = 65536.0; /*Main volume control ranges from +6 dB to -64 dB in 2 dB steps, then remaining settings are -80 dB (effectively 0)*/ + for (c = 0x3f; c >= 0x1c; c--) + { + attenuation[c] = (int)out; + out /= 1.25963; /*2 dB steps*/ + } + for (; c >= 0; c--) + attenuation[c] = 0; + + f = romfopen("nvr/adgold.bin", "rb"); + if (f) + { + fread(adgold->adgold_eeprom, 0x18, 1, f); + fclose(f); + } + + adgold->adgold_status = 0xf; + adgold->adgold_38x_addr = 0; + adgold->adgold_eeprom[0x13] = 3 | (1 << 4); /*IRQ 7, DMA 1*/ + adgold->adgold_eeprom[0x14] = 3 << 4; /*DMA 3*/ + adgold->adgold_eeprom[0x15] = 0x388 / 8; /*Present at 388-38f*/ + memcpy(adgold->adgold_38x_regs, adgold->adgold_eeprom, 0x19); + adgold->vol_l = attenuation[adgold->adgold_eeprom[0x04] & 0x3f]; + adgold->vol_r = attenuation[adgold->adgold_eeprom[0x05] & 0x3f]; + adgold->bass = adgold->adgold_eeprom[0x06] & 0xf; + adgold->treble = adgold->adgold_eeprom[0x07] & 0xf; + adgold->fm_vol_l = (int)(int8_t)(adgold->adgold_eeprom[0x09] - 128); + adgold->fm_vol_r = (int)(int8_t)(adgold->adgold_eeprom[0x0a] - 128); + adgold->samp_vol_l = (int)(int8_t)(adgold->adgold_eeprom[0x0b] - 128); + adgold->samp_vol_r = (int)(int8_t)(adgold->adgold_eeprom[0x0c] - 128); + + adgold->adgold_mma_enable[0] = 0; + adgold->adgold_mma_fifo_start[0] = adgold->adgold_mma_fifo_end[0] = 0; + + /*388/389 are handled by adlib_init*/ + io_sethandler(0x0388, 0x0008, adgold_read, NULL, NULL, adgold_write, NULL, NULL, adgold); + + timer_add(adgold_timer_poll, &adgold->adgold_mma_timer_count, TIMER_ALWAYS_ENABLED, adgold); + + sound_add_handler(adgold_get_buffer, adgold); + + return adgold; +} + +void adgold_close(void *p) +{ + FILE *f; + adgold_t *adgold = (adgold_t *)p; + + f = romfopen("nvr/adgold.bin", "wb"); + if (f) + { + fwrite(adgold->adgold_eeprom, 0x18, 1, f); + fclose(f); + } + + free(adgold); +} + +static device_config_t adgold_config[] = +{ + { + .name = "surround", + .description = "Surround module", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .type = -1 + } +}; + +device_t adgold_device = +{ + "AdLib Gold", + 0, + adgold_init, + adgold_close, + NULL, + NULL, + NULL, + NULL, + adgold_config +}; diff --git a/src/sound_adlibgold.h b/src/sound_adlibgold.h new file mode 100644 index 000000000..b952aaf03 --- /dev/null +++ b/src/sound_adlibgold.h @@ -0,0 +1 @@ +extern device_t adgold_device; diff --git a/src/sound_cms.c b/src/sound_cms.c new file mode 100644 index 000000000..f38f46f9c --- /dev/null +++ b/src/sound_cms.c @@ -0,0 +1,183 @@ +#include +#include +#include "ibm.h" + +#include "device.h" +#include "io.h" +#include "sound.h" +#include "sound_cms.h" + +typedef struct cms_t +{ + int addrs[2]; + uint8_t regs[2][32]; + uint16_t latch[2][6]; + int freq[2][6]; + float count[2][6]; + int vol[2][6][2]; + int stat[2][6]; + uint16_t noise[2][2]; + uint16_t noisefreq[2][2]; + int noisecount[2][2]; + int noisetype[2][2]; + + int16_t buffer[SOUNDBUFLEN * 2]; + + int pos; +} cms_t; + +void cms_update(cms_t *cms) +{ + for (; cms->pos < sound_pos_global; cms->pos++) + { + int c, d; + int16_t out_l = 0, out_r = 0; + + for (c = 0; c < 4; c++) + { + switch (cms->noisetype[c >> 1][c & 1]) + { + case 0: cms->noisefreq[c >> 1][c & 1] = 31250; break; + case 1: cms->noisefreq[c >> 1][c & 1] = 15625; break; + case 2: cms->noisefreq[c >> 1][c & 1] = 7812; break; + case 3: cms->noisefreq[c >> 1][c & 1] = cms->freq[c >> 1][(c & 1) * 3]; break; + } + } + for (c = 0; c < 2; c ++) + { + if (cms->regs[c][0x1C] & 1) + { + for (d = 0; d < 6; d++) + { + if (cms->regs[c][0x14] & (1 << d)) + { + if (cms->stat[c][d]) out_l += (cms->vol[c][d][0] * 90); + if (cms->stat[c][d]) out_r += (cms->vol[c][d][1] * 90); + cms->count[c][d] += cms->freq[c][d]; + if (cms->count[c][d] >= 24000) + { + cms->count[c][d] -= 24000; + cms->stat[c][d] ^= 1; + } + } + else if (cms->regs[c][0x15] & (1 << d)) + { + if (cms->noise[c][d / 3] & 1) out_l += (cms->vol[c][d][0] * 90); + if (cms->noise[c][d / 3] & 1) out_r += (cms->vol[c][d][0] * 90); + } + } + for (d = 0; d < 2; d++) + { + cms->noisecount[c][d] += cms->noisefreq[c][d]; + while (cms->noisecount[c][d] >= 24000) + { + cms->noisecount[c][d] -= 24000; + cms->noise[c][d] <<= 1; + if (!(((cms->noise[c][d] & 0x4000) >> 8) ^ (cms->noise[c][d] & 0x40))) + cms->noise[c][d] |= 1; + } + } + } + } + cms->buffer[(cms->pos << 1)] = out_l; + cms->buffer[(cms->pos << 1) + 1] = out_r; + } +} + +void cms_get_buffer(int32_t *buffer, int len, void *p) +{ + cms_t *cms = (cms_t *)p; + + int c; + + cms_update(cms); + + for (c = 0; c < len * 2; c++) + buffer[c] += cms->buffer[c]; + + cms->pos = 0; +} + +void cms_write(uint16_t addr, uint8_t val, void *p) +{ + cms_t *cms = (cms_t *)p; + int voice; + int chip = (addr & 2) >> 1; + + pclog("cms_write : addr %04X val %02X\n", addr, val); + + if (addr & 1) + cms->addrs[chip] = val & 31; + else + { + cms_update(cms); + cms->regs[chip][cms->addrs[chip] & 31] = val; + switch (cms->addrs[chip] & 31) + { + case 0x00: case 0x01: case 0x02: /*Volume*/ + case 0x03: case 0x04: case 0x05: + voice = cms->addrs[chip] & 7; + cms->vol[chip][voice][0] = val & 0xf; + cms->vol[chip][voice][1] = val >> 4; + break; + case 0x08: case 0x09: case 0x0A: /*Frequency*/ + case 0x0B: case 0x0C: case 0x0D: + voice = cms->addrs[chip] & 7; + cms->latch[chip][voice] = (cms->latch[chip][voice] & 0x700) | val; + cms->freq[chip][voice] = (15625 << (cms->latch[chip][voice] >> 8)) / (511 - (cms->latch[chip][voice] & 255)); + break; + case 0x10: case 0x11: case 0x12: /*Octave*/ + voice = (cms->addrs[chip] & 3) << 1; + cms->latch[chip][voice] = (cms->latch[chip][voice] & 0xFF) | ((val & 7) << 8); + cms->latch[chip][voice + 1] = (cms->latch[chip][voice + 1] & 0xFF) | ((val & 0x70) << 4); + cms->freq[chip][voice] = (15625 << (cms->latch[chip][voice] >> 8)) / (511 - (cms->latch[chip][voice] & 255)); + cms->freq[chip][voice + 1] = (15625 << (cms->latch[chip][voice + 1] >> 8)) / (511 - (cms->latch[chip][voice + 1] & 255)); + break; + case 0x16: /*Noise*/ + cms->noisetype[chip][0] = val & 3; + cms->noisetype[chip][1] = (val >> 4) & 3; + break; + } + } +} + +uint8_t cms_read(uint16_t addr, void *p) +{ + cms_t *cms = (cms_t *)p; + int chip = (addr & 2) >> 1; + + if (addr & 1) + return cms->addrs[chip]; + + return cms->regs[chip][cms->addrs[chip] & 31]; +} + +void *cms_init() +{ + cms_t *cms = malloc(sizeof(cms_t)); + memset(cms, 0, sizeof(cms_t)); + + pclog("cms_init\n"); + io_sethandler(0x0220, 0x0004, cms_read, NULL, NULL, cms_write, NULL, NULL, cms); + sound_add_handler(cms_get_buffer, cms); + return cms; +} + +void cms_close(void *p) +{ + cms_t *cms = (cms_t *)p; + + free(cms); +} + +device_t cms_device = +{ + "Creative Music System / Game Blaster", + 0, + cms_init, + cms_close, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/sound_cms.h b/src/sound_cms.h new file mode 100644 index 000000000..d5795cc0f --- /dev/null +++ b/src/sound_cms.h @@ -0,0 +1 @@ +extern device_t cms_device; diff --git a/src/sound_dbopl.cc b/src/sound_dbopl.cc new file mode 100644 index 000000000..111618dcb --- /dev/null +++ b/src/sound_dbopl.cc @@ -0,0 +1,141 @@ +#include "dosbox/dbopl.h" +#include "sound_dbopl.h" + +static struct +{ + DBOPL::Chip chip; + int addr; + int timer[2]; + uint8_t timer_ctrl; + uint8_t status_mask; + uint8_t status; + int is_opl3; + + void (*timer_callback)(void *param, int timer, int64_t period); + void *timer_param; +} opl[2]; + +enum +{ + STATUS_TIMER_1 = 0x40, + STATUS_TIMER_2 = 0x20, + STATUS_TIMER_ALL = 0x80 +}; + +enum +{ + CTRL_IRQ_RESET = 0x80, + CTRL_TIMER1_MASK = 0x40, + CTRL_TIMER2_MASK = 0x20, + CTRL_TIMER2_CTRL = 0x02, + CTRL_TIMER1_CTRL = 0x01 +}; + +void opl_init(void (*timer_callback)(void *param, int timer, int64_t period), void *timer_param, int nr, int is_opl3) +{ + DBOPL::InitTables(); + opl[nr].chip.Setup(48000, is_opl3); + opl[nr].timer_callback = timer_callback; + opl[nr].timer_param = timer_param; + opl[nr].is_opl3 = is_opl3; +} + +void opl_status_update(int nr) +{ + if (opl[nr].status & (STATUS_TIMER_1 | STATUS_TIMER_2) & opl[nr].status_mask) + opl[nr].status |= STATUS_TIMER_ALL; + else + opl[nr].status &= ~STATUS_TIMER_ALL; +} + +void opl_timer_over(int nr, int timer) +{ + if (!timer) + { + opl[nr].status |= STATUS_TIMER_1; + opl[nr].timer_callback(opl[nr].timer_param, 0, opl[nr].timer[0] * 4); + } + else + { + opl[nr].status |= STATUS_TIMER_2; + opl[nr].timer_callback(opl[nr].timer_param, 1, opl[nr].timer[1] * 16); + } + + opl_status_update(nr); +} + +void opl_write(int nr, uint16_t addr, uint8_t val) +{ + if (!(addr & 1)) + opl[nr].addr = (int)opl[nr].chip.WriteAddr(addr, val) & (opl[nr].is_opl3 ? 0x1ff : 0xff); + else + { + opl[nr].chip.WriteReg(opl[nr].addr, val); + + switch (opl[nr].addr) + { + case 0x02: /*Timer 1*/ + opl[nr].timer[0] = 256 - val; + break; + case 0x03: /*Timer 2*/ + opl[nr].timer[1] = 256 - val; + break; + case 0x04: /*Timer control*/ + if (val & CTRL_IRQ_RESET) /*IRQ reset*/ + { + opl[nr].status &= ~(STATUS_TIMER_1 | STATUS_TIMER_2); + opl_status_update(nr); + return; + } + if ((val ^ opl[nr].timer_ctrl) & CTRL_TIMER1_CTRL) + { + if (val & CTRL_TIMER1_CTRL) + opl[nr].timer_callback(opl[nr].timer_param, 0, opl[nr].timer[0] * 4); + else + opl[nr].timer_callback(opl[nr].timer_param, 0, 0); + } + if ((val ^ opl[nr].timer_ctrl) & CTRL_TIMER2_CTRL) + { + if (val & CTRL_TIMER2_CTRL) + opl[nr].timer_callback(opl[nr].timer_param, 1, opl[nr].timer[1] * 16); + else + opl[nr].timer_callback(opl[nr].timer_param, 1, 0); + } + opl[nr].status_mask = (~val & (CTRL_TIMER1_MASK | CTRL_TIMER2_MASK)) | 0x80; + opl[nr].timer_ctrl = val; + break; + } + } + +} + +uint8_t opl_read(int nr, uint16_t addr) +{ + if (!(addr & 1)) + { + return (opl[nr].status & opl[nr].status_mask) | (opl[nr].is_opl3 ? 0 : 0x06); + } + return opl[nr].is_opl3 ? 0 : 0xff; +} + +void opl2_update(int nr, int16_t *buffer, int samples) +{ + int c; + Bit32s buffer_32[samples]; + + opl[nr].chip.GenerateBlock2(samples, buffer_32); + + for (c = 0; c < samples; c++) + buffer[c*2] = (int16_t)buffer_32[c]; +} + +void opl3_update(int nr, int16_t *buffer, int samples) +{ + int c; + Bit32s buffer_32[samples*2]; + + opl[nr].chip.GenerateBlock3(samples, buffer_32); + + for (c = 0; c < samples*2; c++) + buffer[c] = (int16_t)buffer_32[c]; +} diff --git a/src/sound_dbopl.h b/src/sound_dbopl.h new file mode 100644 index 000000000..450c5dca3 --- /dev/null +++ b/src/sound_dbopl.h @@ -0,0 +1,12 @@ +#ifdef __cplusplus +extern "C" { +#endif + void opl_init(void (*timer_callback)(void *param, int timer, int64_t period), void *timer_param, int nr, int is_opl3); + void opl_write(int nr, uint16_t addr, uint8_t val); + uint8_t opl_read(int nr, uint16_t addr); + void opl_timer_over(int nr, int timer); + void opl2_update(int nr, int16_t *buffer, int samples); + void opl3_update(int nr, int16_t *buffer, int samples); +#ifdef __cplusplus +} +#endif diff --git a/src/sound_emu8k.c b/src/sound_emu8k.c new file mode 100644 index 000000000..6274b8839 --- /dev/null +++ b/src/sound_emu8k.c @@ -0,0 +1,754 @@ +/*12log2(r) * 4096 + + freq = 2^((in - 0xe000) / 4096)*/ +/*LFO - lowest (0.042 Hz) = 2^20 steps = 1048576 + highest (10.72 Hz) = 2^12 steps = 4096*/ +#include +#include +#include "ibm.h" +#include "device.h" +#include "sound.h" +#include "sound_emu8k.h" +#include "timer.h" + +enum +{ + ENV_STOPPED = 0, + ENV_ATTACK = 1, + ENV_DECAY = 2, + ENV_SUSTAIN = 3, + ENV_RELEASE = 4 +}; + +static int64_t freqtable[65536]; +static int attentable[256]; +static int envtable[4096]; +static int lfotable[4096]; + +static int32_t filt_w0[256]; +/*static float filt_w0[256];*/ + +#define READ16(addr, var) switch ((addr) & 2) \ + { \ + case 0: ret = (var) & 0xffff; break; \ + case 2: ret = ((var) >> 16) & 0xffff; break; \ + } + +#define WRITE16(addr, var, val) switch ((addr) & 2) \ + { \ + case 0: var = (var & 0xffff0000) | (val); break; \ + case 2: var = (var & 0x0000ffff) | ((val) << 16); break; \ + } + +static inline int16_t EMU8K_READ(emu8k_t *emu8k, uint32_t addr) +{ + addr &= 0xffffff; + if (addr < 0x80000) + return emu8k->rom[addr]; + if (addr < 0x200000 || addr >= emu8k->ram_end_addr) + return 0; + if (!emu8k->ram) + return 0; + return emu8k->ram[addr - 0x200000]; +} + +static inline int16_t EMU8K_READ_INTERP(emu8k_t *emu8k, uint32_t addr) +{ + int16_t dat1 = EMU8K_READ(emu8k, addr >> 8); + int16_t dat2 = EMU8K_READ(emu8k, (addr >> 8) + 1); + return ((dat1 * (0xff - (addr & 0xff))) + (dat2 * (addr & 0xff))) >> 8; +} + +static inline void EMU8K_WRITE(emu8k_t *emu8k, uint32_t addr, uint16_t val) +{ + addr &= 0xffffff; + if (emu8k->ram && addr >= 0x200000 && addr < emu8k->ram_end_addr) + emu8k->ram[addr - 0x200000] = val; +} +static int ff = 0; +static int voice_count = 0; + +uint16_t emu8k_inw(uint32_t addr, void *p) +{ + emu8k_t *emu8k = (emu8k_t *)p; + uint16_t ret; +/* pclog("emu8k_inw %04X reg=%i voice=%i\n", addr, emu8k->cur_reg, emu8k->cur_voice);*/ + + addr -= 0x220; + switch (addr & 0xc02) + { + case 0x400: case 0x402: /*Data0*/ + switch (emu8k->cur_reg) + { + case 0: + READ16(addr, emu8k->voice[emu8k->cur_voice].cpf); + return ret; + + case 1: + READ16(addr, emu8k->voice[emu8k->cur_voice].ptrx); + return ret; + + case 2: + READ16(addr, emu8k->voice[emu8k->cur_voice].cvcf); + return ret; + + case 3: + READ16(addr, emu8k->voice[emu8k->cur_voice].vtft); + return ret; + + case 4: case 5: /*???*/ + return 0xffff; + + case 6: + READ16(addr, emu8k->voice[emu8k->cur_voice].psst); + return ret; + + case 7: + READ16(addr, emu8k->voice[emu8k->cur_voice].cpf); + return ret; + } + break; + + case 0x800: /*Data1*/ + switch (emu8k->cur_reg) + { + case 0: + { + uint32_t val = (emu8k->voice[emu8k->cur_voice].ccca & 0xff000000) | (emu8k->voice[emu8k->cur_voice].addr >> 8); + READ16(addr, emu8k->voice[emu8k->cur_voice].ccca); + return ret; + } + + case 1: + switch (emu8k->cur_voice) + { + case 20: + READ16(addr, emu8k->smalr); + return ret; + case 21: + READ16(addr, emu8k->smarr); + return ret; + case 22: + READ16(addr, emu8k->smalw); + return ret; + case 23: + READ16(addr, emu8k->smarw); + return ret; + + case 26: + { + uint16_t val = emu8k->smld_buffer; + emu8k->smld_buffer = EMU8K_READ(emu8k, emu8k->smalr); +/* pclog("emu8k_SMLR in %04X (%04X) %08X\n", val, emu8k->smld_buffer, emu8k->smalr);*/ + emu8k->smalr++; + return val; + } + /*The EMU8000 PGM describes the return values of these registers as 'a VLSI error'*/ + case 29: /*Configuration Word 1*/ + return (emu8k->hwcf1 & 0xfe) | (emu8k->hwcf3 & 0x01); + case 30: /*Configuration Word 2*/ + return ((emu8k->hwcf2 >> 4) & 0x0e) | (emu8k->hwcf1 & 0x01) | ((emu8k->hwcf3 & 0x02) ? 0x10 : 0) | ((emu8k->hwcf3 & 0x04) ? 0x40 : 0) | ((emu8k->hwcf3 & 0x08) ? 0x20 : 0) | ((emu8k->hwcf3 & 0x10) ? 0x80 : 0); + case 31: /*Configuration Word 3*/ + return emu8k->hwcf2 & 0x1f; + } + break; + + case 2: /*INIT1*/ + case 3: /*INIT3*/ + return 0xffff; /*Can we read anything useful from here?*/ + + case 5: + return emu8k->voice[emu8k->cur_voice].dcysusv; + + case 7: + return emu8k->voice[emu8k->cur_voice].dcysus; + } + break; + + case 0x802: /*Data2*/ + switch (emu8k->cur_reg) + { + case 0: + { + uint32_t val = (emu8k->voice[emu8k->cur_voice].ccca & 0xff000000) | (emu8k->voice[emu8k->cur_voice].addr >> 8); + READ16(addr, emu8k->voice[emu8k->cur_voice].ccca); + return ret; + } + + case 1: + switch (emu8k->cur_voice) + { + case 20: + READ16(addr, emu8k->smalr | ff); + ff ^= 0x80000000; + return ret; + case 21: + READ16(addr, emu8k->smarr | ff); + ff ^= 0x80000000; + return ret; + case 22: + READ16(addr, emu8k->smalw); + return ret; + case 23: + READ16(addr, emu8k->smarw); + return ret; + + case 26: + { + uint16_t val = emu8k->smrd_buffer; + emu8k->smrd_buffer = EMU8K_READ(emu8k, emu8k->smarr); +/* pclog("emu8k_SMRR in %04X (%04X) %08X\n", val, emu8k->smrd_buffer, emu8k->smarr);*/ + emu8k->smarr++; + return val; + } + + case 27: /*Sample Counter*/ + return emu8k->wc; + } + break; + + case 2: /*INIT2*/ + case 3: /*INIT4*/ + return 0xffff; /*Can we read anything useful from here?*/ + + case 4: + return emu8k->voice[emu8k->cur_voice].atkhldv; + } + break; + + case 0xc00: /*Data3*/ + switch (emu8k->cur_reg) + { + case 0: + return emu8k->voice[emu8k->cur_voice].ip; + + case 1: + return emu8k->voice[emu8k->cur_voice].ifatn; + + case 2: + return emu8k->voice[emu8k->cur_voice].pefe; + + case 3: + return emu8k->voice[emu8k->cur_voice].fmmod; + + case 4: + return emu8k->voice[emu8k->cur_voice].tremfrq; + + case 5: + return emu8k->voice[emu8k->cur_voice].fm2frq2; + + case 6: + return 0xffff; + + case 7: /*ID?*/ + return 0x1c | ((emu8k->id & 0x0002) ? 0xff02 : 0); + } + break; + case 0xc02: /*Status - I think!*/ + voice_count = (voice_count + 1) & 0x1f; +/* emu8k->c02_read ^= 0x1000; + pclog("Read status %04X\n", 0x803f | (voice_count << 8));*/ + return 0x803f | (voice_count << 8); + } +/* fatal("Bad EMU8K inw from %08X\n", addr);*/ + return 0xffff; +} + +void emu8k_outw(uint32_t addr, uint16_t val, void *p) +{ + emu8k_t *emu8k = (emu8k_t *)p; + + emu8k_update(emu8k); +/* pclog("emu8k_outw : addr=%08X reg=%i voice=%i val=%04X\n", addr, emu8k->cur_reg, emu8k->cur_voice, val);*/ +//emu8k_outw : addr=00000A22 reg=3 voice=21 val=0265 + addr -= 0x220; + switch (addr & 0xc02) + { + case 0x400: case 0x402: /*Data0*/ + switch (emu8k->cur_reg) + { + case 0: + WRITE16(addr, emu8k->voice[emu8k->cur_voice].cpf, val); + return; + + case 1: + WRITE16(addr, emu8k->voice[emu8k->cur_voice].ptrx, val); + return; + + case 2: + WRITE16(addr, emu8k->voice[emu8k->cur_voice].cvcf, val); + return; + + case 3: + WRITE16(addr, emu8k->voice[emu8k->cur_voice].vtft, val); + return; + + case 6: + WRITE16(addr, emu8k->voice[emu8k->cur_voice].psst, val); + emu8k->voice[emu8k->cur_voice].loop_start = (uint64_t)(emu8k->voice[emu8k->cur_voice].psst & 0xffffff) << 32; + if (addr & 2) + { + emu8k->voice[emu8k->cur_voice].vol_l = val >> 8; + emu8k->voice[emu8k->cur_voice].vol_r = 255 - (val >> 8); + } +/* pclog("emu8k_outl : write PSST %08X l %i r %i\n", emu8k->voice[emu8k->cur_voice].psst, emu8k->voice[emu8k->cur_voice].vol_l, emu8k->voice[emu8k->cur_voice].vol_r);*/ + return; + + case 7: + WRITE16(addr, emu8k->voice[emu8k->cur_voice].cpf, val); + emu8k->voice[emu8k->cur_voice].loop_end = (uint64_t)(emu8k->voice[emu8k->cur_voice].cpf & 0xffffff) << 32; +/* pclog("emu8k_outl : write CPF %08X\n", emu8k->voice[emu8k->cur_voice].cpf);*/ + return; + } + break; + + case 0x800: /*Data1*/ + switch (emu8k->cur_reg) + { + case 0: + WRITE16(addr, emu8k->voice[emu8k->cur_voice].ccca, val); + emu8k->voice[emu8k->cur_voice].addr = (uint64_t)(emu8k->voice[emu8k->cur_voice].ccca & 0xffffff) << 32; +/* pclog("emu8k_outl : write CCCA %08X\n", emu8k->voice[emu8k->cur_voice].ccca);*/ + return; + + case 1: + switch (emu8k->cur_voice) + { + case 20: + WRITE16(addr, emu8k->smalr, val); + return; + case 21: + WRITE16(addr, emu8k->smarr, val); + return; + case 22: + WRITE16(addr, emu8k->smalw, val); + return; + case 23: + WRITE16(addr, emu8k->smarw, val); + return; + + case 26: + EMU8K_WRITE(emu8k, emu8k->smalw, val); +/* pclog("emu8k_SMLW %04X %08X\n", val, emu8k->smalw);*/ +/* if (val = 0xffff && emu8k->smalw == 0x200000) + output = 3;*/ + emu8k->smalw++; + break; + + case 29: /*Configuration Word 1*/ + emu8k->hwcf1 = val; + return; + case 30: /*Configuration Word 2*/ + emu8k->hwcf2 = val; + return; + case 31: /*Configuration Word 3*/ + emu8k->hwcf3 = val; + return; + } + break; + + case 5: +/* pclog("emu8k_outw : write DCYSUSV %04X\n", val);*/ + emu8k->voice[emu8k->cur_voice].dcysusv = val; + emu8k->voice[emu8k->cur_voice].env_sustain = (((val >> 8) & 0x7f) << 5) << 9; + if (val & 0x8000) /*Release*/ + { + emu8k->voice[emu8k->cur_voice].env_state = ENV_RELEASE; + emu8k->voice[emu8k->cur_voice].env_release = val & 0x7f; + } + else /*Decay*/ + emu8k->voice[emu8k->cur_voice].env_decay = val & 0x7f; + if (val & 0x80) + emu8k->voice[emu8k->cur_voice].env_state = ENV_STOPPED; + return; + + case 7: +/* pclog("emu8k_outw : write DCYSUS %04X\n", val);*/ + emu8k->voice[emu8k->cur_voice].dcysus = val; + emu8k->voice[emu8k->cur_voice].menv_sustain = (((val >> 8) & 0x7f) << 5) << 9; + if (val & 0x8000) /*Release*/ + { + emu8k->voice[emu8k->cur_voice].menv_state = ENV_RELEASE; + emu8k->voice[emu8k->cur_voice].menv_release = val & 0x7f; + } + else /*Decay*/ + emu8k->voice[emu8k->cur_voice].menv_decay = val & 0x7f; + if (val & 0x80) + emu8k->voice[emu8k->cur_voice].menv_state = ENV_STOPPED; + return; + } + break; + + case 0x802: /*Data2*/ + switch (emu8k->cur_reg) + { + case 0: + { + float q; + + WRITE16(addr, emu8k->voice[emu8k->cur_voice].ccca, val); + emu8k->voice[emu8k->cur_voice].addr = (uint64_t)(emu8k->voice[emu8k->cur_voice].ccca & 0xffffff) << 32; + + q = (float)(emu8k->voice[emu8k->cur_voice].ccca >> 28) / 15.0f; + q /= 10.0f; /*Horrible and wrong hack*/ + emu8k->voice[emu8k->cur_voice].q = (int32_t)((1.0f / (0.707f + q)) * 256.0f); + +/* pclog("emu8k_outl : write CCCA %08X Q %f invQ %X\n", emu8k->voice[emu8k->cur_voice].ccca, q, emu8k->voice[emu8k->cur_voice].q);*/ + } + return; + + case 1: + switch (emu8k->cur_voice) + { + case 20: + WRITE16(addr, emu8k->smalr, val); + return; + case 21: + WRITE16(addr, emu8k->smarr, val); + return; + case 22: + WRITE16(addr, emu8k->smalw, val); + return; + case 23: + WRITE16(addr, emu8k->smarw, val); + return; + + case 26: + EMU8K_WRITE(emu8k, emu8k->smarw, val); +/* pclog("emu8k_SMRW %04X %08X\n", val, emu8k->smarw);*/ + emu8k->smarw++; + break; + } + break; + + case 4: +/* pclog("emu8k_outw : write ATKHLDV %04X\n", val);*/ + emu8k->voice[emu8k->cur_voice].atkhldv = val; + emu8k->voice[emu8k->cur_voice].env_attack = (val & 0x7f) << 6; + if (!(val & 0x8000)) /*Trigger attack*/ + emu8k->voice[emu8k->cur_voice].env_state = ENV_ATTACK; + return; + + case 6: +/* pclog("emu8k_outw : write ATKHLD %04X\n", val);*/ + emu8k->voice[emu8k->cur_voice].atkhld = val; + emu8k->voice[emu8k->cur_voice].menv_attack = (val & 0x7f) << 6; + if (!(val & 0x8000)) /*Trigger attack*/ + emu8k->voice[emu8k->cur_voice].menv_state = ENV_ATTACK; + return; + } + break; + + case 0xc00: /*Data3*/ + switch (emu8k->cur_reg) + { + case 0: + emu8k->voice[emu8k->cur_voice].ip = val; + emu8k->voice[emu8k->cur_voice].pitch = val; + return; + + case 1: + emu8k->voice[emu8k->cur_voice].ifatn = val; + emu8k->voice[emu8k->cur_voice].attenuation = attentable[val & 0xff]; + emu8k->voice[emu8k->cur_voice].cutoff = (val >> 8); +/* pclog("Attenuation now %02X %i\n", val & 0xff, emu8k->voice[emu8k->cur_voice].attenuation);*/ + return; + + case 2: + emu8k->voice[emu8k->cur_voice].pefe = val; + emu8k->voice[emu8k->cur_voice].fe_height = (int8_t)(val & 0xff); + return; + + case 3: + emu8k->voice[emu8k->cur_voice].fmmod = val; + emu8k->voice[emu8k->cur_voice].lfo1_fmmod = (val >> 8); + return; + + case 4: + emu8k->voice[emu8k->cur_voice].tremfrq = val; + emu8k->voice[emu8k->cur_voice].lfo1_trem = (val >> 8); + return; + + case 5: + emu8k->voice[emu8k->cur_voice].fm2frq2 = val; + emu8k->voice[emu8k->cur_voice].lfo2_fmmod = (val >> 8); + return; + + case 7: /*ID?*/ + emu8k->id = val; + return; + } + break; + + case 0xc02: /*Pointer*/ + emu8k->cur_voice = (val & 31); + emu8k->cur_reg = ((val >> 5) & 7); + return; + } +} + +uint8_t emu8k_inb(uint32_t addr, void *p) +{ + if (addr & 1) + return emu8k_inw(addr & ~1, p) >> 1; + return emu8k_inw(addr, p) & 0xff; +} + +void emu8k_outb(uint32_t addr, uint8_t val, void *p) +{ + if (addr & 1) + emu8k_outw(addr & ~1, val << 8, p); + else + emu8k_outw(addr, val, p); +} + +void emu8k_update(emu8k_t *emu8k) +{ + int new_pos = (sound_pos_global * 44100) / 48000; + if (emu8k->pos < new_pos) + { + int32_t *buf; + int pos; + int c; + int32_t out_l = 0, out_r = 0; + + buf = &emu8k->buffer[emu8k->pos*2]; + + for (pos = emu8k->pos; pos < new_pos; pos++) + emu8k->buffer[pos*2] = emu8k->buffer[pos*2 + 1] = 0; + + for (c = 0; c < 32; c++) + { + buf = &emu8k->buffer[emu8k->pos*2]; + + for (pos = emu8k->pos; pos < new_pos; pos++) + { + int32_t voice_l, voice_r; + int32_t dat; + int lfo1_vibrato, lfo2_vibrato; + int tremolo; + + tremolo = ((lfotable[(emu8k->voice[c].lfo1_count >> 8) & 4095] * emu8k->voice[c].lfo1_trem) * 4) >> 12; + + if (freqtable[emu8k->voice[c].pitch] >> 32) + dat = EMU8K_READ(emu8k, emu8k->voice[c].addr >> 32); + else + dat = EMU8K_READ_INTERP(emu8k, emu8k->voice[c].addr >> 24); + + dat = (dat * emu8k->voice[c].attenuation) >> 16; + + dat = (dat * envtable[emu8k->voice[c].env_vol >> 9]) >> 16; + + if ((emu8k->voice[c].ccca >> 28) || (emu8k->voice[c].cutoff != 0xff)) + { + int cutoff = emu8k->voice[c].cutoff + ((emu8k->voice[c].menv_vol * emu8k->voice[c].fe_height) >> 20); + if (cutoff < 0) + cutoff = 0; + if (cutoff > 255) + cutoff = 255; + + emu8k->voice[c].vhp = ((-emu8k->voice[c].vbp * emu8k->voice[c].q) >> 8) - emu8k->voice[c].vlp - dat; + emu8k->voice[c].vlp += (emu8k->voice[c].vbp * filt_w0[cutoff]) >> 8; + emu8k->voice[c].vbp += (emu8k->voice[c].vhp * filt_w0[cutoff]) >> 8; + if (emu8k->voice[c].vlp < -32767) + dat = -32767; + else if (emu8k->voice[c].vlp > 32767) + dat = 32767; + else + dat = (int16_t)emu8k->voice[c].vlp; + } + + voice_l = (dat * emu8k->voice[c].vol_l) >> 7; + voice_r = (dat * emu8k->voice[c].vol_r) >> 7; + + (*buf++) += voice_l * 8192; + (*buf++) += voice_r * 8192; + + switch (emu8k->voice[c].env_state) + { + case ENV_ATTACK: + emu8k->voice[c].env_vol += emu8k->voice[c].env_attack; + emu8k->voice[c].vtft |= 0xffff0000; + if (emu8k->voice[c].env_vol >= (1 << 21)) + { + emu8k->voice[c].env_vol = 1 << 21; + emu8k->voice[c].env_state = ENV_DECAY; + } + break; + + case ENV_DECAY: + emu8k->voice[c].env_vol -= emu8k->voice[c].env_decay; + emu8k->voice[c].vtft = (emu8k->voice[c].vtft & ~0xffff0000) | ((emu8k->voice[c].env_sustain >> 5) << 16); + if (emu8k->voice[c].env_vol <= emu8k->voice[c].env_sustain) + { + emu8k->voice[c].env_vol = emu8k->voice[c].env_sustain; + emu8k->voice[c].env_state = ENV_SUSTAIN; + } + break; + + case ENV_RELEASE: + emu8k->voice[c].env_vol -= emu8k->voice[c].env_release; + emu8k->voice[c].vtft &= ~0xffff0000; + if (emu8k->voice[c].env_vol <= 0) + { + emu8k->voice[c].env_vol = 0; + emu8k->voice[c].env_state = ENV_STOPPED; + } + break; + } + + if (emu8k->voice[c].env_vol >= (1 << 21)) + emu8k->voice[c].cvcf &= ~0xffff0000; + else + emu8k->voice[c].cvcf = (emu8k->voice[c].cvcf & ~0xffff0000) | ((emu8k->voice[c].env_vol >> 5) << 16); + + switch (emu8k->voice[c].menv_state) + { + case ENV_ATTACK: + emu8k->voice[c].menv_vol += emu8k->voice[c].menv_attack; + if (emu8k->voice[c].menv_vol >= (1 << 21)) + { + emu8k->voice[c].menv_vol = 1 << 21; + emu8k->voice[c].menv_state = ENV_DECAY; + } + break; + + case ENV_DECAY: + emu8k->voice[c].menv_vol -= emu8k->voice[c].menv_decay; + if (emu8k->voice[c].menv_vol <= emu8k->voice[c].menv_sustain) + { + emu8k->voice[c].menv_vol = emu8k->voice[c].menv_sustain; + emu8k->voice[c].menv_state = ENV_SUSTAIN; + } + break; + + case ENV_RELEASE: + emu8k->voice[c].menv_vol -= emu8k->voice[c].menv_release; + if (emu8k->voice[c].menv_vol <= 0) + { + emu8k->voice[c].menv_vol = 0; + emu8k->voice[c].menv_state = ENV_STOPPED; + } + break; + } + + lfo1_vibrato = (lfotable[(emu8k->voice[c].lfo1_count >> 8) & 4095] * emu8k->voice[c].lfo1_fmmod) >> 9; + lfo2_vibrato = (lfotable[(emu8k->voice[c].lfo2_count >> 8) & 4095] * emu8k->voice[c].lfo2_fmmod) >> 9; + + emu8k->voice[c].addr += freqtable[(emu8k->voice[c].pitch + lfo1_vibrato + lfo2_vibrato) & 0xffff]; + if (emu8k->voice[c].addr >= emu8k->voice[c].loop_end) + emu8k->voice[c].addr -= (emu8k->voice[c].loop_end - emu8k->voice[c].loop_start); + + emu8k->voice[c].lfo1_count += (emu8k->voice[c].tremfrq & 0xff); + emu8k->voice[c].lfo2_count += (emu8k->voice[c].fm2frq2 & 0xff); + } + } + + buf = &emu8k->buffer[emu8k->pos*2]; + + for (pos = emu8k->pos; pos < new_pos; pos++) + { + buf[0] >>= 15; + buf[1] >>= 15; + + if (buf[0] < -32768) + buf[0] = -32768; + else if (buf[0] > 32767) + buf[0] = 32767; + + if (buf[1] < -32768) + buf[1] = -32768; + else if (buf[1] > 32767) + buf[1] = 32767; + + buf += 2; + } + + emu8k->wc += (new_pos - emu8k->pos); + + emu8k->pos = new_pos; + } +} + +void emu8k_init(emu8k_t *emu8k, int onboard_ram) +{ + FILE *f; + int c; + double out; + + f = romfopen("roms/awe32.raw", "rb"); + if (!f) + fatal("ROMS/AWE32.RAW not found\n"); + + if (onboard_ram) + { + emu8k->ram = malloc(onboard_ram * 1024); + emu8k->ram_end_addr = 0x200000 + ((onboard_ram * 1024) / 2); + } + + emu8k->rom = malloc(1024 * 1024); + + fread(emu8k->rom, 1024 * 1024, 1, f); + fclose(f); + + /*AWE-DUMP creates ROM images offset by 2 bytes, so if we detect this + then correct it*/ + if (emu8k->rom[3] == 0x314d && emu8k->rom[4] == 0x474d) + { + memcpy(&emu8k->rom[0], &emu8k->rom[1], (1024 * 1024) - 2); + emu8k->rom[0x7ffff] = 0; + } + io_sethandler(0x0620, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); + io_sethandler(0x0a20, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); + io_sethandler(0x0e20, 0x0004, emu8k_inb, emu8k_inw, NULL, emu8k_outb, emu8k_outw, NULL, emu8k); + + /*Create frequency table*/ + for (c = 0; c < 0x10000; c++) + { + freqtable[c] = (uint64_t)(exp2((double)(c - 0xe000) / 4096.0) * 65536.0 * 65536.0); + } + + out = 65536.0; + + for (c = 0; c < 256; c++) + { + attentable[c] = (int)out; + out /= sqrt(1.09018); /*0.375 dB steps*/ + } + + out = 65536; + + for (c = 0; c < 4096; c++) + { + envtable[4095 - c] = (int)out; + out /= 1.002709201; /*0.0235 dB Steps*/ + } + + for (c = 0; c < 4096; c++) + { + int d = (c + 1024) & 4095; + if (d >= 2048) + lfotable[c] = 4096 - ((2048 - d) * 4); + else + lfotable[c] = (d * 4) - 4096; + } + + out = 125.0; + for (c = 0; c < 256; c++) + { +/* filt_w0[c] = (int32_t)((2.0 * 3.142 * (out / 44100.0)) * 0.707 * 256.0);*/ +/* filt_w0[c] = 2.0 * 3.142 * (out / 44100.0);*/ + filt_w0[c] = (int32_t)(2.0 * 3.142 * (out / 44100.0) * 256.0); + out *= 1.016378315; + } + + emu8k->hwcf1 = 0x59; + emu8k->hwcf2 = 0x20; + emu8k->hwcf3 = 0x04; +} + +void emu8k_close(emu8k_t *emu8k) +{ + free(emu8k->rom); + free(emu8k->ram); +} diff --git a/src/sound_emu8k.h b/src/sound_emu8k.h new file mode 100644 index 000000000..79478ad56 --- /dev/null +++ b/src/sound_emu8k.h @@ -0,0 +1,90 @@ +typedef struct emu8k_t +{ + struct + { + uint32_t cpf; + uint32_t ptrx; + uint32_t cvcf; + uint32_t vtft; + uint32_t psst; + uint32_t csl; + + uint32_t ccca; + + uint16_t init1, init2, init3, init4; + + uint16_t envvol; + uint16_t dcysusv; + uint16_t envval; + uint16_t dcysus; + uint16_t atkhldv; + uint16_t lfo1val, lfo2val; + uint16_t atkhld; + uint16_t ip; + uint16_t ifatn; + uint16_t pefe; + uint16_t fmmod; + uint16_t tremfrq; + uint16_t fm2frq2; + + int voice_on; + + uint64_t addr; + uint64_t loop_start, loop_end; + + uint16_t pitch; + int attenuation; + int env_state, env_vol; + int env_attack, env_decay, env_sustain, env_release; + + int menv_state, menv_vol; + int menv_attack, menv_decay, menv_sustain, menv_release; + + int lfo1_count, lfo2_count; + int8_t lfo1_fmmod, lfo2_fmmod; + int8_t lfo1_trem; + int vol_l, vol_r; + + int8_t fe_height; + + int64_t vlp, vbp, vhp; + int32_t q; + + int filter_offset; + +/* float vlp, vbp, vhp; + float q;*/ + + int cutoff; + } voice[32]; + + uint32_t hwcf1, hwcf2, hwcf3; + uint32_t hwcf4, hwcf5, hwcf6; + + uint32_t smalr, smarr, smalw, smarw; + uint16_t smld_buffer, smrd_buffer; + + uint16_t wc; + + uint16_t c02_read; + + uint16_t id; + + int16_t *ram, *rom; + + uint32_t ram_end_addr; + + int cur_reg, cur_voice; + + int timer_count; + + int16_t out_l, out_r; + + int pos; + int32_t buffer[SOUNDBUFLEN * 2]; +} emu8k_t; + +void emu8k_init(emu8k_t *emu8k, int onboard_ram); +void emu8k_close(emu8k_t *emu8k); + +void emu8k_update(emu8k_t *emu8k); diff --git a/src/sound_gus.c b/src/sound_gus.c new file mode 100644 index 000000000..6ff19a254 --- /dev/null +++ b/src/sound_gus.c @@ -0,0 +1,1138 @@ +#include +#include +#include +#include "ibm.h" + +#include "device.h" +#include "dma.h" +#include "io.h" +#include "pic.h" +#include "sound.h" +#include "sound_gus.h" +#include "timer.h" + +typedef struct gus_t +{ + int reset; + + int global; + uint32_t addr,dmaaddr; + int voice; + uint32_t start[32],end[32],cur[32]; + uint32_t startx[32],endx[32],curx[32]; + int rstart[32],rend[32]; + int rcur[32]; + uint16_t freq[32]; + uint16_t rfreq[32]; + uint8_t ctrl[32]; + uint8_t rctrl[32]; + int curvol[32]; + int pan_l[32], pan_r[32]; + int t1on,t2on; + uint8_t tctrl; + uint16_t t1,t2,t1l,t2l; + uint8_t irqstatus,irqstatus2; + uint8_t adcommand; + int waveirqs[32],rampirqs[32]; + int voices; + uint8_t dmactrl; + + int32_t out_l, out_r; + + int16_t buffer[2][SOUNDBUFLEN]; + int pos; + + int samp_timer, samp_latch; + + uint8_t *ram; + + int irqnext; + + int timer_1, timer_2; + + int irq, dma, irq_midi; + int latch_enable; + + uint8_t sb_2xa, sb_2xc, sb_2xe; + uint8_t sb_ctrl; + int sb_nmi; + + uint8_t reg_ctrl; + + uint8_t ad_status, ad_data; + uint8_t ad_timer_ctrl; + + uint8_t midi_ctrl, midi_status; + uint8_t midi_data; + int midi_loopback; + + uint8_t gp1, gp2; + uint16_t gp1_addr, gp2_addr; + + uint8_t usrr; +} gus_t; + +static int gus_irqs[8] = {-1, 2, 5, 3, 7, 11, 12, 15}; +static int gus_irqs_midi[8] = {-1, 2, 5, 3, 7, 11, 12, 15}; +static int gus_dmas[8] = {-1, 1, 3, 5, 6, 7, -1, -1}; + +int gusfreqs[]= +{ + 44100,41160,38587,36317,34300,32494,30870,29400,28063,26843,25725,24696, + 23746,22866,22050,21289,20580,19916,19293 +}; + +double vol16bit[4096]; + +void pollgusirqs(gus_t *gus) +{ + int c; + + gus->irqstatus&=~0x60; + for (c=0;c<32;c++) + { + if (gus->waveirqs[c]) + { +// gus->waveirqs[c]=0; + gus->irqstatus2=0x60|c; + if (gus->rampirqs[c]) gus->irqstatus2 |= 0x80; + gus->irqstatus|=0x20; +// printf("Voice IRQ %i %02X %i\n",c,gus->irqstatus2,ins); + if (gus->irq != -1) + picint(1 << gus->irq); + return; + } + if (gus->rampirqs[c]) + { +// gus->rampirqs[c]=0; + gus->irqstatus2=0xA0|c; + gus->irqstatus|=0x40; +// printf("Ramp IRQ %i %02X %i\n",c,gus->irqstatus2,ins); + if (gus->irq != -1) + picint(1 << gus->irq); + return; + } + } + gus->irqstatus2=0xE0; +// gus->irqstatus&=~0x20; + if (!gus->irqstatus && gus->irq != -1) picintc(1 << gus->irq); +} + +enum +{ + MIDI_INT_RECEIVE = 0x01, + MIDI_INT_TRANSMIT = 0x02, + MIDI_INT_MASTER = 0x80 +}; + +enum +{ + MIDI_CTRL_TRANSMIT_MASK = 0x60, + MIDI_CTRL_TRANSMIT = 0x20, + MIDI_CTRL_RECEIVE = 0x80 +}; + +enum +{ + GUS_INT_MIDI_TRANSMIT = 0x01, + GUS_INT_MIDI_RECEIVE = 0x02 +}; + +enum +{ + GUS_TIMER_CTRL_AUTO = 0x01 +}; + +void gus_midi_update_int_status(gus_t *gus) +{ + gus->midi_status &= ~MIDI_INT_MASTER; + if ((gus->midi_ctrl & MIDI_CTRL_TRANSMIT_MASK) == MIDI_CTRL_TRANSMIT && (gus->midi_status & MIDI_INT_TRANSMIT)) + { + gus->midi_status |= MIDI_INT_MASTER; + gus->irqstatus |= GUS_INT_MIDI_TRANSMIT; + } + else + gus->irqstatus &= ~GUS_INT_MIDI_TRANSMIT; + + if ((gus->midi_ctrl & MIDI_CTRL_RECEIVE) && (gus->midi_status & MIDI_INT_RECEIVE)) + { + gus->midi_status |= MIDI_INT_MASTER; + gus->irqstatus |= GUS_INT_MIDI_RECEIVE; + } + else + gus->irqstatus &= ~GUS_INT_MIDI_RECEIVE; + + if ((gus->midi_status & MIDI_INT_MASTER) && (gus->irq_midi != -1)) + { +// pclog("Take MIDI IRQ\n"); + picint(1 << gus->irq_midi); + } +} + +void writegus(uint16_t addr, uint8_t val, void *p) +{ + gus_t *gus = (gus_t *)p; + int c, d; + int old; +// pclog("Write GUS %04X %02X %04X:%04X\n",addr,val,CS,pc); + if (gus->latch_enable && addr != 0x24b) + gus->latch_enable = 0; + switch (addr) + { + case 0x340: /*MIDI control*/ + old = gus->midi_ctrl; + gus->midi_ctrl = val; + + if ((val & 3) == 3) + gus->midi_status = 0; + else if ((old & 3) == 3) + { + gus->midi_status |= MIDI_INT_TRANSMIT; +// pclog("MIDI_INT_TRANSMIT\n"); + } + gus_midi_update_int_status(gus); + break; + + case 0x341: /*MIDI data*/ + if (gus->midi_loopback) + { + gus->midi_status |= MIDI_INT_RECEIVE; + gus->midi_data = val; + } + else + gus->midi_status |= MIDI_INT_TRANSMIT; + break; + + case 0x342: /*Voice select*/ + gus->voice=val&31; + break; + case 0x343: /*Global select*/ + gus->global=val; + break; + case 0x344: /*Global low*/ +// if (gus->global!=0x43 && gus->global!=0x44) printf("Writing register %02X %02X %02X %i\n",gus->global,gus->voice,val, ins); + switch (gus->global) + { + case 0: /*Voice control*/ +// if (val&1 && !(gus->ctrl[gus->voice]&1)) printf("Voice on %i\n",gus->voice); + gus->ctrl[gus->voice]=val; + break; + case 1: /*Frequency control*/ + gus->freq[gus->voice]=(gus->freq[gus->voice]&0xFF00)|val; + break; + case 2: /*Start addr high*/ + gus->startx[gus->voice]=(gus->startx[gus->voice]&0xF807F)|(val<<7); + gus->start[gus->voice]=(gus->start[gus->voice]&0x1F00FFFF)|(val<<16); +// printf("Write %i start %08X %08X\n",gus->voice,gus->start[gus->voice],gus->startx[gus->voice]); + break; + case 3: /*Start addr low*/ + gus->start[gus->voice]=(gus->start[gus->voice]&0x1FFFFF00)|val; +// printf("Write %i start %08X %08X\n",gus->voice,gus->start[gus->voice],gus->startx[gus->voice]); + break; + case 4: /*End addr high*/ + gus->endx[gus->voice]=(gus->endx[gus->voice]&0xF807F)|(val<<7); + gus->end[gus->voice]=(gus->end[gus->voice]&0x1F00FFFF)|(val<<16); +// printf("Write %i end %08X %08X\n",gus->voice,gus->end[gus->voice],gus->endx[gus->voice]); + break; + case 5: /*End addr low*/ + gus->end[gus->voice]=(gus->end[gus->voice]&0x1FFFFF00)|val; +// printf("Write %i end %08X %08X\n",gus->voice,gus->end[gus->voice],gus->endx[gus->voice]); + break; + + case 0x6: /*Ramp frequency*/ + gus->rfreq[gus->voice] = (int)( (double)((val & 63)*512)/(double)(1 << (3*(val >> 6)))); +// printf("RFREQ %02X %i %i %f\n",val,gus->voice,gus->rfreq[gus->voice],(double)(val & 63)/(double)(1 << (3*(val >> 6)))); + break; + + case 0x9: /*Current volume*/ + gus->curvol[gus->voice] = gus->rcur[gus->voice] = (gus->rcur[gus->voice] & ~(0xff << 6)) | (val << 6); +// printf("Vol %i is %04X\n",gus->voice,gus->curvol[gus->voice]); + break; + + case 0xA: /*Current addr high*/ + gus->cur[gus->voice]=(gus->cur[gus->voice]&0x1F00FFFF)|(val<<16); +gus->curx[gus->voice]=(gus->curx[gus->voice]&0xF807F00)|((val<<7)<<8); +// gus->cur[gus->voice]=(gus->cur[gus->voice]&0x0F807F00)|((val<<7)<<8); +// printf("Write %i cur %08X\n",gus->voice,gus->cur[gus->voice],gus->curx[gus->voice]); + break; + case 0xB: /*Current addr low*/ + gus->cur[gus->voice]=(gus->cur[gus->voice]&0x1FFFFF00)|val; +// printf("Write %i cur %08X\n",gus->voice,gus->cur[gus->voice],gus->curx[gus->voice]); + break; + + case 0x42: /*DMA address low*/ + gus->dmaaddr=(gus->dmaaddr&0xFF000)|(val<<4); + break; + + case 0x43: /*Address low*/ + gus->addr=(gus->addr&0xFFF00)|val; + break; + case 0x45: /*Timer control*/ +// printf("Timer control %02X\n",val); + gus->tctrl=val; + break; + } + break; + case 0x345: /*Global high*/ +// if (gus->global!=0x43 && gus->global!=0x44) printf("HWriting register %02X %02X %02X %04X:%04X %i %X\n",gus->global,gus->voice,val,CS,pc, ins, gus->rcur[1] >> 10); + switch (gus->global) + { + case 0: /*Voice control*/ + if (!(val&1) && gus->ctrl[gus->voice]&1) + { +// printf("Voice on %i - start %05X end %05X freq %04X\n",gus->voice,gus->start[gus->voice],gus->end[gus->voice],gus->freq[gus->voice]); +// if (val&0x40) gus->cur[gus->voice]=gus->end[gus->voice]<<8; +// else gus->cur[gus->voice]=gus->start[gus->voice]<<8; + } + + gus->ctrl[gus->voice] = val & 0x7f; + + old = gus->waveirqs[gus->voice]; + gus->waveirqs[gus->voice] = ((val & 0xa0) == 0xa0) ? 1 : 0; + if (gus->waveirqs[gus->voice] != old) + pollgusirqs(gus); + break; + case 1: /*Frequency control*/ + gus->freq[gus->voice]=(gus->freq[gus->voice]&0xFF)|(val<<8); + break; + case 2: /*Start addr high*/ + gus->startx[gus->voice]=(gus->startx[gus->voice]&0x07FFF)|(val<<15); + gus->start[gus->voice]=(gus->start[gus->voice]&0x00FFFFFF)|((val&0x1F)<<24); +// printf("Write %i start %08X %08X %02X\n",gus->voice,gus->start[gus->voice],gus->startx[gus->voice],val); + break; + case 3: /*Start addr low*/ + gus->startx[gus->voice]=(gus->startx[gus->voice]&0xFFF80)|(val&0x7F); + gus->start[gus->voice]=(gus->start[gus->voice]&0x1FFF00FF)|(val<<8); +// printf("Write %i start %08X %08X\n",gus->voice,gus->start[gus->voice],gus->startx[gus->voice]); + break; + case 4: /*End addr high*/ + gus->endx[gus->voice]=(gus->endx[gus->voice]&0x07FFF)|(val<<15); + gus->end[gus->voice]=(gus->end[gus->voice]&0x00FFFFFF)|((val&0x1F)<<24); +// printf("Write %i end %08X %08X %02X\n",gus->voice,gus->end[gus->voice],gus->endx[gus->voice],val); + break; + case 5: /*End addr low*/ + gus->endx[gus->voice]=(gus->endx[gus->voice]&0xFFF80)|(val&0x7F); + gus->end[gus->voice]=(gus->end[gus->voice]&0x1FFF00FF)|(val<<8); +// printf("Write %i end %08X %08X\n",gus->voice,gus->end[gus->voice],gus->endx[gus->voice]); + break; + + case 0x6: /*Ramp frequency*/ + gus->rfreq[gus->voice] = (int)( (double)((val & 63) * (1 << 10))/(double)(1 << (3 * (val >> 6)))); +// pclog("Ramp freq %02X %i %i %f %i\n", val, gus->voice, gus->rfreq[gus->voice], (double)(val & 63)/(double)(1 << (3*(val >> 6))), ins); + break; + case 0x7: /*Ramp start*/ + gus->rstart[gus->voice] = val << 14; +// pclog("Ramp start %04X\n", gus->rstart[gus->voice] >> 10); + break; + case 0x8: /*Ramp end*/ + gus->rend[gus->voice] = val << 14; +// pclog("Ramp end %04X\n", gus->rend[gus->voice] >> 10); + break; + case 0x9: /*Current volume*/ + gus->curvol[gus->voice] = gus->rcur[gus->voice] = (gus->rcur[gus->voice] & ~(0xff << 14)) | (val << 14); +// printf("Vol %i is %04X\n",gus->voice,gus->curvol[gus->voice]); + break; + + case 0xA: /*Current addr high*/ + gus->cur[gus->voice]=(gus->cur[gus->voice]&0x00FFFFFF)|((val&0x1F)<<24); + gus->curx[gus->voice]=(gus->curx[gus->voice]&0x07FFF00)|((val<<15)<<8); +// printf("Write %i cur %08X %08X %02X\n",gus->voice,gus->cur[gus->voice],gus->curx[gus->voice],val); +// gus->cur[gus->voice]=(gus->cur[gus->voice]&0x007FFF00)|((val<<15)<<8); + break; + case 0xB: /*Current addr low*/ + gus->cur[gus->voice]=(gus->cur[gus->voice]&0x1FFF00FF)|(val<<8); +gus->curx[gus->voice]=(gus->curx[gus->voice]&0xFFF8000)|((val&0x7F)<<8); +// gus->cur[gus->voice]=(gus->cur[gus->voice]&0x0FFF8000)|((val&0x7F)<<8); +// printf("Write %i cur %08X %08X\n",gus->voice,gus->cur[gus->voice],gus->curx[gus->voice]); + break; + case 0xC: /*Pan*/ + gus->pan_l[gus->voice] = 15 - (val & 0xf); + gus->pan_r[gus->voice] = (val & 0xf); + break; + case 0xD: /*Ramp control*/ + old = gus->rampirqs[gus->voice]; + gus->rctrl[gus->voice] = val & 0x7F; + gus->rampirqs[gus->voice] = ((val & 0xa0) == 0xa0) ? 1 : 0; + if (gus->rampirqs[gus->voice] != old) + pollgusirqs(gus); +// printf("Ramp control %02i %02X %02X %i\n",gus->voice,val,gus->rampirqs[gus->voice],ins); + break; + + case 0xE: + gus->voices=(val&63)+1; + if (gus->voices>32) gus->voices=32; + if (gus->voices<14) gus->voices=14; + gus->global=val; +// printf("GUS voices %i\n",val&31); + if (gus->voices < 14) + gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / 44100.0)); + else + gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / gusfreqs[gus->voices - 14])); + break; + + case 0x41: /*DMA*/ + if (val&1 && gus->dma != -1) + { +// printf("DMA start! %05X %02X\n",gus->dmaaddr,val); + if (val & 2) + { + c=0; + while (c<65536) + { + int dma_result; + d = gus->ram[gus->dmaaddr]; + if (val & 0x80) d ^= 0x80; + dma_result = dma_channel_write(gus->dma, d); + if (dma_result == DMA_NODATA) + break; + gus->dmaaddr++; + gus->dmaaddr&=0xFFFFF; + c++; + if (dma_result & DMA_OVER) + break; + } +// printf("GUS->MEM Transferred %i bytes\n",c); + gus->dmactrl=val&~0x40; + if (val&0x20) gus->irqnext=1; + } + else + { + c=0; + while (c<65536) + { + d = dma_channel_read(gus->dma); + if (d == DMA_NODATA) + break; + if (val&0x80) d^=0x80; + gus->ram[gus->dmaaddr]=d; + gus->dmaaddr++; + gus->dmaaddr&=0xFFFFF; + c++; + if (d & DMA_OVER) + break; + } +// printf("MEM->GUS Transferred %i bytes\n",c); + gus->dmactrl=val&~0x40; + if (val&0x20) gus->irqnext=1; + } +// exit(-1); + } + break; + + case 0x42: /*DMA address low*/ + gus->dmaaddr=(gus->dmaaddr&0xFF0)|(val<<12); + break; + + case 0x43: /*Address low*/ + gus->addr=(gus->addr&0xF00FF)|(val<<8); + break; + case 0x44: /*Address high*/ + gus->addr=(gus->addr&0xFFFF)|((val<<16)&0xF0000); + break; + case 0x45: /*Timer control*/ + if (!(val&4)) gus->irqstatus&=~4; + if (!(val&8)) gus->irqstatus&=~8; + if (!(val & 0x20)) + { + gus->ad_status &= ~0x18; + nmi = 0; + } + if (!(val & 0x02)) + { + gus->ad_status &= ~0x01; + nmi = 0; + } +// printf("Timer control %02X\n",val); +/* if ((val&4) && !(gus->tctrl&4)) + { + gus->t1=gus->t1l; + gus->t1on=1; + }*/ + gus->tctrl=val; + gus->sb_ctrl = val; + break; + case 0x46: /*Timer 1*/ + gus->t1 = gus->t1l = val; + gus->t1on = 1; +// printf("GUS timer 1 %i\n",val); + break; + case 0x47: /*Timer 2*/ + gus->t2 = gus->t2l = val; + gus->t2on = 1; +// printf("GUS timer 2 %i\n",val); + break; + + case 0x4c: /*Reset*/ + gus->reset = val; + break; + } + break; + case 0x347: /*DRAM access*/ + gus->ram[gus->addr]=val; +// pclog("GUS RAM write %05X %02X\n",gus->addr,val); + gus->addr&=0xFFFFF; + break; + case 0x248: case 0x388: + gus->adcommand = val; +// pclog("Setting ad command %02X %02X %p\n", val, gus->adcommand, &gus->adcommand); + break; + + case 0x389: + if ((gus->tctrl & GUS_TIMER_CTRL_AUTO) || gus->adcommand != 4) + { + gus->ad_data = val; + gus->ad_status |= 0x01; + if (gus->sb_ctrl & 0x02) + { + if (gus->sb_nmi) + nmi = 1; + else if (gus->irq != -1) + picint(1 << gus->irq); + } + } + else if (!(gus->tctrl & GUS_TIMER_CTRL_AUTO) && gus->adcommand == 4) + { + if (val & 0x80) + { + gus->ad_status &= ~0x60; + } + else + { + gus->ad_timer_ctrl = val; + + if (val & 0x01) + gus->t1on = 1; + else + gus->t1 = gus->t1l; + + if (val & 0x02) + gus->t2on = 1; + else + gus->t2 = gus->t2l; + } + } + break; + + case 0x240: + gus->midi_loopback = val & 0x20; + gus->latch_enable = (val & 0x40) ? 2 : 1; + break; + + case 0x24b: + switch (gus->reg_ctrl & 0x07) + { + case 0: + if (gus->latch_enable == 1) + gus->dma = gus_dmas[val & 7]; + if (gus->latch_enable == 2) + { + gus->irq = gus_irqs[val & 7]; + if (val & 0x40) + gus->irq_midi = gus->irq; + else + gus->irq_midi = gus_irqs_midi[(val >> 3) & 7]; + + gus->sb_nmi = val & 0x80; + } + gus->latch_enable = 0; +// pclog("IRQ %i DMA %i\n", gus->irq, gus->dma); + break; + case 1: + gus->gp1 = val; + break; + case 2: + gus->gp2 = val; + break; + case 3: + gus->gp1_addr = val; + break; + case 4: + gus->gp2_addr = val; + break; + case 5: + gus->usrr = 0; + break; + case 6: + break; + } + break; + + case 0x246: + gus->ad_status |= 0x08; + if (gus->sb_ctrl & 0x20) + { + if (gus->sb_nmi) + nmi = 1; + else if (gus->irq != -1) + picint(1 << gus->irq); + } + break; + case 0x24a: + gus->sb_2xa = val; + break; + case 0x24c: + gus->ad_status |= 0x10; + if (gus->sb_ctrl & 0x20) + { + if (gus->sb_nmi) + nmi = 1; + else if (gus->irq != -1) + picint(1 << gus->irq); + } + case 0x24d: + gus->sb_2xc = val; + break; + case 0x24e: + gus->sb_2xe = val; + break; + case 0x24f: + gus->reg_ctrl = val; + break; + } +} + +uint8_t readgus(uint16_t addr, void *p) +{ + gus_t *gus = (gus_t *)p; + uint8_t val; +// /*if (addr!=0x246) */printf("Read GUS %04X %04X(%06X):%04X %02X\n",addr,CS,cs,pc,gus->global); + switch (addr) + { + case 0x340: /*MIDI status*/ + val = gus->midi_status; +// pclog("Read MIDI status %02X\n", val); + break; + + case 0x341: /*MIDI data*/ + val = gus->midi_data; + gus->midi_status &= ~MIDI_INT_RECEIVE; + gus_midi_update_int_status(gus); + break; + + case 0x240: return 0; + case 0x246: /*IRQ status*/ + val = gus->irqstatus & ~0x10; + if (gus->ad_status & 0x19) + val |= 0x10; +// pclog("Read IRQ status %02X\n", val); + return val; + + case 0x24F: return 0; + case 0x342: return gus->voice; + case 0x343: return gus->global; + case 0x344: /*Global low*/ +// /*if (gus->global!=0x43 && gus->global!=0x44) */printf("Reading register %02X %02X\n",gus->global,gus->voice); + switch (gus->global) + { + case 0x82: /*Start addr high*/ + return gus->start[gus->voice]>>16; + case 0x83: /*Start addr low*/ + return gus->start[gus->voice]&0xFF; + + case 0x89: /*Current volume*/ + return gus->rcur[gus->voice]>>6; + case 0x8A: /*Current addr high*/ + return gus->cur[gus->voice]>>16; + case 0x8B: /*Current addr low*/ + return gus->cur[gus->voice]&0xFF; + + case 0x8F: /*IRQ status*/ + val=gus->irqstatus2; +// pclog("Read IRQ status - %02X\n",val); + gus->rampirqs[gus->irqstatus2&0x1F]=0; + gus->waveirqs[gus->irqstatus2&0x1F]=0; + pollgusirqs(gus); + return val; + + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + val = 0xff; + break; + +// default: +// fatal("Bad GUS global low read %02X\n",gus->global); + } + break; + case 0x345: /*Global high*/ +// /*if (gus->global!=0x43 && gus->global!=0x44) */printf("HReading register %02X %02X\n",gus->global,gus->voice); + switch (gus->global) + { + case 0x80: /*Voice control*/ +// pclog("Read voice control %02i %02X\n", gus->voice, gus->ctrl[gus->voice]|(gus->waveirqs[gus->voice]?0x80:0)); + return gus->ctrl[gus->voice]|(gus->waveirqs[gus->voice]?0x80:0); + + case 0x82: /*Start addr high*/ + return gus->start[gus->voice]>>24; + case 0x83: /*Start addr low*/ + return gus->start[gus->voice]>>8; + + case 0x89: /*Current volume*/ +// pclog("Read current volume %i\n", gus->rcur[gus->voice] >> 14); + return gus->rcur[gus->voice]>>14; + + case 0x8A: /*Current addr high*/ + return gus->cur[gus->voice]>>24; + case 0x8B: /*Current addr low*/ + return gus->cur[gus->voice]>>8; + + case 0x8C: /*Pan*/ + return gus->pan_r[gus->voice]; + + case 0x8D: +// pclog("Read ramp control %02X %04X %08X %08X %08X\n",gus->rctrl[gus->voice]|(gus->rampirqs[gus->voice]?0x80:0),gus->rcur[gus->voice] >> 14,gus->rfreq[gus->voice],gus->rstart[gus->voice],gus->rend[gus->voice]); + return gus->rctrl[gus->voice]|(gus->rampirqs[gus->voice]?0x80:0); + + case 0x8F: /*IRQ status*/ +// pclog("Read IRQ 1\n"); + val=gus->irqstatus2; + gus->rampirqs[gus->irqstatus2&0x1F]=0; + gus->waveirqs[gus->irqstatus2&0x1F]=0; + pollgusirqs(gus); +// pclog("Read IRQ status - %02X %i %i\n",val, gus->waveirqs[gus->irqstatus2&0x1F], gus->rampirqs[gus->irqstatus2&0x1F]); + return val; + + case 0x41: /*DMA control*/ + val=gus->dmactrl|((gus->irqstatus&0x80)?0x40:0); + gus->irqstatus&=~0x80; + return val; + case 0x45: /*Timer control*/ + return gus->tctrl; + case 0x49: /*Sampling control*/ + return 0; + + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + val = 0xff; + break; + +// default: +// fatal("Bad GUS global high read %02X\n",gus->global); + } + break; + case 0x346: return 0xff; + case 0x347: /*DRAM access*/ + val=gus->ram[gus->addr]; +// pclog("GUS RAM read %05X %02X\n",gus->addr,val); + gus->addr&=0xFFFFF; + return val; + case 0x349: return 0; + case 0x746: /*Revision level*/ + return 0xff; /*Pre 3.7 - no mixer*/ + + case 0x24b: + switch (gus->reg_ctrl & 0x07) + { + case 1: + val = gus->gp1; + break; + case 2: + val = gus->gp2; + break; + case 3: + val = gus->gp1_addr; + break; + case 4: + val = gus->gp2_addr; + break; + } + break; + + case 0x24c: + val = gus->sb_2xc; + if (gus->reg_ctrl & 0x20) + gus->sb_2xc &= 0x80; + break; + case 0x24e: +/* gus->ad_status |= 0x10; + if (gus->reg_ctrl & 0x80) + { + gus->reg_ctrl_r |= 0x80; + if (gus->sb_nmi) + nmi = 1; + else + picint(1 << gus->irq); + }*/ + return gus->sb_2xe; + + case 0x248: case 0x388: +// pclog("Read ad_status %02X\n", gus->ad_status); + if (gus->tctrl & GUS_TIMER_CTRL_AUTO) + val = gus->sb_2xa; + else + { + val = gus->ad_status & ~(gus->ad_timer_ctrl & 0x60); + if (val & 0x60) + val |= 0x80; + } + break; + + case 0x249: + gus->ad_status &= ~0x01; + nmi = 0; + case 0x389: + val = gus->ad_data; + break; + + case 0x24A: + val = gus->adcommand; +// pclog("Read ad command %02X %02X %p\n", gus->adcommand, val, &gus->adcommand); + break; + + } +// printf("Bad GUS read %04X! %02X\n",addr,gus->global); +// exit(-1); + return val; +} + +void gus_poll_timer_1(void *p) +{ + gus_t *gus = (gus_t *)p; + + gus->timer_1 += (TIMER_USEC * 80); +// pclog("gus_poll_timer_1 %i %i %i %i %02X\n", gustime, gus->t1on, gus->t1, gus->t1l, gus->tctrl); + if (gus->t1on) + { + gus->t1++; + if (gus->t1 > 0xFF) + { +// gus->t1on=0; + gus->t1=gus->t1l; + gus->ad_status |= 0x40; + if (gus->tctrl&4) + { + if (gus->irq != -1) + picint(1 << gus->irq); + gus->ad_status |= 0x04; + gus->irqstatus |= 0x04; +// pclog("GUS T1 IRQ!\n"); + } + } + } + if (gus->irqnext) + { +// pclog("Take IRQ\n"); + gus->irqnext=0; + gus->irqstatus|=0x80; + if (gus->irq != -1) + picint(1 << gus->irq); + } + gus_midi_update_int_status(gus); +} + +void gus_poll_timer_2(void *p) +{ + gus_t *gus = (gus_t *)p; + + gus->timer_2 += (TIMER_USEC * 320); +// pclog("pollgus2 %i %i %i %i %02X\n", gustime, gus->t2on, gus->t2, gus->t2l, gus->tctrl); + if (gus->t2on) + { + gus->t2++; + if (gus->t2 > 0xFF) + { +// gus->t2on=0; + gus->t2=gus->t2l; + gus->ad_status |= 0x20; + if (gus->tctrl&8) + { + if (gus->irq != -1) + picint(1 << gus->irq); + gus->ad_status |= 0x02; + gus->irqstatus |= 0x08; +// pclog("GUS T2 IRQ!\n"); + } + } + } + if (gus->irqnext) + { +// pclog("Take IRQ\n"); + gus->irqnext=0; + gus->irqstatus|=0x80; + if (gus->irq != -1) + picint(1 << gus->irq); + } +} + +static void gus_update(gus_t *gus) +{ + for (; gus->pos < sound_pos_global; gus->pos++) + { + if (gus->out_l < -32768) + gus->buffer[0][gus->pos] = -32768; + else if (gus->out_l > 32767) + gus->buffer[0][gus->pos] = 32767; + else + gus->buffer[0][gus->pos] = gus->out_l; + if (gus->out_r < -32768) + gus->buffer[1][gus->pos] = -32768; + else if (gus->out_r > 32767) + gus->buffer[1][gus->pos] = 32767; + else + gus->buffer[1][gus->pos] = gus->out_r; + } +} + +void gus_poll_wave(void *p) +{ + gus_t *gus = (gus_t *)p; + uint32_t addr; + int d; + int16_t v; + int32_t vl; + int update_irqs = 0; + + gus_update(gus); + + gus->samp_timer += gus->samp_latch; + + gus->out_l = gus->out_r = 0; + + if ((gus->reset & 3) != 3) + return; +//pclog("gus_poll_wave\n"); + for (d=0;d<32;d++) + { + if (!(gus->ctrl[d] & 3)) + { + if (gus->ctrl[d] & 4) + { + addr = gus->cur[d] >> 9; + addr = (addr & 0xC0000) | ((addr << 1) & 0x3FFFE); + if (!(gus->freq[d] >> 10)) /*Interpolate*/ + { + vl = (int16_t)(int8_t)((gus->ram[(addr + 1) & 0xFFFFF] ^ 0x80) - 0x80) * (511 - (gus->cur[d] & 511)); + vl += (int16_t)(int8_t)((gus->ram[(addr + 3) & 0xFFFFF] ^ 0x80) - 0x80) * (gus->cur[d] & 511); + v = vl >> 9; + } + else + v = (int16_t)(int8_t)((gus->ram[(addr + 1) & 0xFFFFF] ^ 0x80) - 0x80); + } + else + { + if (!(gus->freq[d] >> 10)) /*Interpolate*/ + { + vl = ((int8_t)((gus->ram[(gus->cur[d] >> 9) & 0xFFFFF] ^ 0x80) - 0x80)) * (511 - (gus->cur[d] & 511)); + vl += ((int8_t)((gus->ram[((gus->cur[d] >> 9) + 1) & 0xFFFFF] ^ 0x80) - 0x80)) * (gus->cur[d] & 511); + v = vl >> 9; + } + else + v = (int16_t)(int8_t)((gus->ram[(gus->cur[d] >> 9) & 0xFFFFF] ^ 0x80) - 0x80); + } + +// pclog("Voice %i : %04X %05X %04X ", d, v, gus->cur[d] >> 9, gus->rcur[d] >> 10); + if ((gus->rcur[d] >> 14) > 4095) v = (int16_t)(float)(v) * 24.0 * vol16bit[4095]; + else v = (int16_t)(float)(v) * 24.0 * vol16bit[(gus->rcur[d]>>10) & 4095]; +// pclog("%f %04X\n", vol16bit[(gus->rcur[d]>>10) & 4095], v); + + gus->out_l += (v * gus->pan_l[d]) / 7; + gus->out_r += (v * gus->pan_r[d]) / 7; + + if (gus->ctrl[d]&0x40) + { + gus->cur[d] -= (gus->freq[d] >> 1); + if (gus->cur[d] <= gus->start[d]) + { + int diff = gus->start[d] - gus->cur[d]; + if (!(gus->rctrl[d]&4)) + { + if (!(gus->ctrl[d]&8)) + { + gus->ctrl[d] |= 1; + gus->cur[d] = (gus->ctrl[d] & 0x40) ? gus->end[d] : gus->start[d]; + } + else + { + if (gus->ctrl[d]&0x10) gus->ctrl[d]^=0x40; + gus->cur[d] = (gus->ctrl[d] & 0x40) ? (gus->end[d] - diff) : (gus->start[d] + diff); + } + } + if ((gus->ctrl[d] & 0x20) && !gus->waveirqs[d]) + { + gus->waveirqs[d] = 1; + update_irqs = 1; +// pclog("Causing wave IRQ %02X %i\n", gus->ctrl[d], d); + } + } + } + else + { + gus->cur[d] += (gus->freq[d] >> 1); + + if (gus->cur[d] >= gus->end[d]) + { + int diff = gus->cur[d] - gus->end[d]; + if (!(gus->rctrl[d]&4)) + { + if (!(gus->ctrl[d]&8)) + { + gus->ctrl[d] |= 1; + gus->cur[d] = (gus->ctrl[d] & 0x40) ? gus->end[d] : gus->start[d]; + } + else + { + if (gus->ctrl[d]&0x10) gus->ctrl[d]^=0x40; + gus->cur[d] = (gus->ctrl[d] & 0x40) ? (gus->end[d] - diff) : (gus->start[d] + diff); + } + } + if ((gus->ctrl[d] & 0x20) && !gus->waveirqs[d]) + { + gus->waveirqs[d] = 1; + update_irqs = 1; +// pclog("Causing wave IRQ %02X %i\n", gus->ctrl[d], d); + } + } + } + } + if (!(gus->rctrl[d] & 3)) + { + if (gus->rctrl[d] & 0x40) + { + gus->rcur[d] -= gus->rfreq[d]; + if (gus->rcur[d] <= gus->rstart[d]) + { + int diff = gus->rstart[d] - gus->rcur[d]; + if (!(gus->rctrl[d] & 8)) + { + gus->rctrl[d] |= 1; + gus->rcur[d] = (gus->rctrl[d] & 0x40) ? gus->rstart[d] : gus->rend[d]; + } + else + { + if (gus->rctrl[d] & 0x10) gus->rctrl[d] ^= 0x40; + gus->rcur[d] = (gus->rctrl[d] & 0x40) ? (gus->rend[d] - diff) : (gus->rstart[d] + diff); + } + + if ((gus->rctrl[d] & 0x20) && !gus->rampirqs[d]) + { + gus->rampirqs[d] = 1; + update_irqs = 1; +// pclog("Causing ramp IRQ %02X %i\n",gus->rctrl[d], d); + } + } + } + else + { + gus->rcur[d] += gus->rfreq[d]; +// if (d == 1) printf("RCUR+ %i %08X %08X %08X %08X\n",d,gus->rfreq[d],gus->rcur[d],gus->rstart[d],gus->rend[d]); + if (gus->rcur[d] >= gus->rend[d]) + { + int diff = gus->rcur[d] - gus->rend[d]; + if (!(gus->rctrl[d] & 8)) + { + gus->rctrl[d] |= 1; + gus->rcur[d] = (gus->rctrl[d] & 0x40) ? gus->rstart[d] : gus->rend[d]; + } + else + { + if (gus->rctrl[d] & 0x10) gus->rctrl[d] ^= 0x40; + gus->rcur[d] = (gus->rctrl[d] & 0x40) ? (gus->rend[d] - diff) : (gus->rstart[d] + diff); + } + + if ((gus->rctrl[d] & 0x20) && !gus->rampirqs[d]) + { + gus->rampirqs[d] = 1; + update_irqs = 1; +// pclog("Causing ramp IRQ %02X %i\n",gus->rctrl[d], d); + } + } + } + } + } + + if (update_irqs) + pollgusirqs(gus); +} + +static void gus_get_buffer(int32_t *buffer, int len, void *p) +{ + gus_t *gus = (gus_t *)p; + int c; + + gus_update(gus); + + for (c = 0; c < len * 2; c++) + { + buffer[c] += (int32_t)gus->buffer[c & 1][c >> 1]; + } + + gus->pos = 0; +} + + +void *gus_init() +{ + int c; + double out = 1.0; + gus_t *gus = malloc(sizeof(gus_t)); + memset(gus, 0, sizeof(gus_t)); + + gus->ram = malloc(1 << 20); + memset(gus->ram, 0, 1 << 20); + + pclog("gus_init\n"); + + for (c=0;c<32;c++) + { + gus->ctrl[c]=1; + gus->rctrl[c]=1; + gus->rfreq[c]=63*512; + } + + for (c=4095;c>=0;c--) { + vol16bit[c]=out;//(float)c/4095.0;//out; + out/=1.002709201; /* 0.0235 dB Steps */ + } + + printf("Top volume %f %f %f %f\n",vol16bit[4095],vol16bit[3800],vol16bit[3000],vol16bit[2048]); + gus->voices=14; + + gus->samp_timer = gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / 44100.0)); + + gus->t1l = gus->t2l = 0xff; + + io_sethandler(0x0240, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL, gus); + io_sethandler(0x0340, 0x0010, readgus, NULL, NULL, writegus, NULL, NULL, gus); + io_sethandler(0x0746, 0x0001, readgus, NULL, NULL, writegus, NULL, NULL, gus); + io_sethandler(0x0388, 0x0002, readgus, NULL, NULL, writegus, NULL, NULL, gus); + timer_add(gus_poll_wave, &gus->samp_timer, TIMER_ALWAYS_ENABLED, gus); + timer_add(gus_poll_timer_1, &gus->timer_1, TIMER_ALWAYS_ENABLED, gus); + timer_add(gus_poll_timer_2, &gus->timer_2, TIMER_ALWAYS_ENABLED, gus); + + sound_add_handler(gus_get_buffer, gus); + + return gus; +} + +void gus_close(void *p) +{ + gus_t *gus = (gus_t *)p; + + free(gus->ram); + free(gus); +} + +void gus_speed_changed(void *p) +{ + gus_t *gus = (gus_t *)p; + + if (gus->voices < 14) + gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / 44100.0)); + else + gus->samp_latch = (int)(TIMER_USEC * (1000000.0 / gusfreqs[gus->voices - 14])); +} + +device_t gus_device = +{ + "Gravis UltraSound", + 0, + gus_init, + gus_close, + NULL, + gus_speed_changed, + NULL, + NULL +}; diff --git a/src/sound_gus.h b/src/sound_gus.h new file mode 100644 index 000000000..6c124f9f8 --- /dev/null +++ b/src/sound_gus.h @@ -0,0 +1 @@ +extern device_t gus_device; diff --git a/src/sound_mameopl.c b/src/sound_mameopl.c new file mode 100644 index 000000000..caf3691b8 --- /dev/null +++ b/src/sound_mameopl.c @@ -0,0 +1,200 @@ +#include +#include +#include "ibm.h" +#include "io.h" +#include "sound.h" +#include "mame/fmopl.h" +#include "mame/ymf262.h" +#include "sound_opl.h" +#include "sound_dbopl.h" + +/*Interfaces between PCem and the actual OPL emulator*/ + + +uint8_t opl2_read(uint16_t a, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + cycles -= (int)(isa_timing * 8); + opl2_update2(opl); + return ym3812_read(opl->YM3812[0], a); +} +void opl2_write(uint16_t a, uint8_t v, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + opl2_update2(opl); + ym3812_write(opl->YM3812[0],a,v); + ym3812_write(opl->YM3812[1],a,v); +} + +uint8_t opl2_l_read(uint16_t a, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + cycles -= (int)(isa_timing * 8); + opl2_update2(opl); + return ym3812_read(opl->YM3812[0], a); +} +void opl2_l_write(uint16_t a, uint8_t v, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + opl2_update2(opl); + ym3812_write(opl->YM3812[0],a,v); +} + +uint8_t opl2_r_read(uint16_t a, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + cycles -= (int)(isa_timing * 8); + opl2_update2(opl); + return ym3812_read(opl->YM3812[1], a); +} +void opl2_r_write(uint16_t a, uint8_t v, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + opl2_update2(opl); + ym3812_write(opl->YM3812[1],a,v); +} + +uint8_t opl3_read(uint16_t a, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + cycles -= (int)(isa_timing * 8); + opl3_update2(opl); + return ymf262_read(opl->YMF262, a); +} +void opl3_write(uint16_t a, uint8_t v, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + opl3_update2(opl); + ymf262_write(opl->YMF262, a, v); +} + + +void opl2_update2(opl_t *opl) +{ + if (opl->pos < sound_pos_global) + { + ym3812_update_one(opl->YM3812[0], &opl->buffer[opl->pos*2], sound_pos_global - opl->pos); + ym3812_update_one(opl->YM3812[1], &opl->buffer[opl->pos*2 + 1], sound_pos_global - opl->pos); + for (; opl->pos < sound_pos_global; opl->pos++) + { + opl->filtbuf[0] = opl->buffer[opl->pos*2] = (opl->buffer[opl->pos*2] / 4) + ((opl->filtbuf[0] * 11) / 16); + opl->filtbuf[1] = opl->buffer[opl->pos*2+1] = (opl->buffer[opl->pos*2+1] / 4) + ((opl->filtbuf[1] * 11) / 16); + } + } +} + +void opl3_update2(opl_t *opl) +{ + if (opl->pos < sound_pos_global) + { + ymf262_update_one(opl->YMF262, &opl->buffer[opl->pos*2], sound_pos_global - opl->pos); + for (; opl->pos < sound_pos_global; opl->pos++) + { + opl->filtbuf[0] = opl->buffer[opl->pos*2] = (opl->buffer[opl->pos*2] / 4) + ((opl->filtbuf[0] * 11) / 16); + opl->filtbuf[1] = opl->buffer[opl->pos*2+1] = (opl->buffer[opl->pos*2+1] / 4) + ((opl->filtbuf[1] * 11) / 16); + } + } +} + +void ym3812_timer_set_0(void *param, int timer, int64_t period) +{ + opl_t *opl = (opl_t *)param; + + opl->timers[0][timer] = period * TIMER_USEC * 20; + if (!opl->timers[0][timer]) opl->timers[0][timer] = 1; + opl->timers_enable[0][timer] = period ? 1 : 0; +} +void ym3812_timer_set_1(void *param, int timer, int64_t period) +{ + opl_t *opl = (opl_t *)param; + + opl->timers[1][timer] = period * TIMER_USEC * 20; + if (!opl->timers[1][timer]) opl->timers[1][timer] = 1; + opl->timers_enable[1][timer] = period ? 1 : 0; +} + +void ymf262_timer_set(void *param, int timer, int64_t period) +{ + opl_t *opl = (opl_t *)param; + + opl->timers[0][timer] = period * TIMER_USEC * 20; + if (!opl->timers[0][timer]) opl->timers[0][timer] = 1; + opl->timers_enable[0][timer] = period ? 1 : 0; +} + +static void opl_timer_callback00(void *p) +{ + opl_t *opl = (opl_t *)p; + + opl->timers_enable[0][0] = 0; + ym3812_timer_over(opl->YM3812[0], 0); +} +static void opl_timer_callback01(void *p) +{ + opl_t *opl = (opl_t *)p; + + opl->timers_enable[0][1] = 0; + ym3812_timer_over(opl->YM3812[0], 1); +} +static void opl_timer_callback10(void *p) +{ + opl_t *opl = (opl_t *)p; + + opl->timers_enable[1][0] = 0; + ym3812_timer_over(opl->YM3812[1], 0); +} +static void opl_timer_callback11(void *p) +{ + opl_t *opl = (opl_t *)p; + + opl->timers_enable[1][1] = 0; + ym3812_timer_over(opl->YM3812[1], 1); +} +static void opl3_timer_callback00(void *p) +{ + opl_t *opl = (opl_t *)p; + + opl->timers_enable[0][0] = 0; + ymf262_timer_over(opl->YMF262, 0); +} +static void opl3_timer_callback01(void *p) +{ + opl_t *opl = (opl_t *)p; + + opl->timers_enable[0][1] = 0; + ymf262_timer_over(opl->YMF262, 1); +} + +void opl2_init(opl_t *opl) +{ + opl->YM3812[0] = ym3812_init(NULL, 3579545, 48000); + ym3812_reset_chip(opl->YM3812[0]); + ym3812_set_timer_handler(opl->YM3812[0], ym3812_timer_set_0, opl); + + opl->YM3812[1] = ym3812_init(NULL, 3579545, 48000); + ym3812_reset_chip(opl->YM3812[1]); + ym3812_set_timer_handler(opl->YM3812[1], ym3812_timer_set_1, opl); + + timer_add(opl_timer_callback00, &opl->timers[0][0], &opl->timers_enable[0][0], (void *)opl); + timer_add(opl_timer_callback01, &opl->timers[0][1], &opl->timers_enable[0][1], (void *)opl); + timer_add(opl_timer_callback10, &opl->timers[1][0], &opl->timers_enable[1][0], (void *)opl); + timer_add(opl_timer_callback11, &opl->timers[1][1], &opl->timers_enable[1][1], (void *)opl); +} + +void opl3_init(opl_t *opl) +{ + opl->YMF262 = ymf262_init(NULL, 3579545 * 4, 48000); + ymf262_reset_chip(opl->YMF262); + ymf262_set_timer_handler(opl->YMF262, ymf262_timer_set, opl); + timer_add(opl3_timer_callback00, &opl->timers[0][0], &opl->timers_enable[0][0], (void *)opl); + timer_add(opl3_timer_callback01, &opl->timers[0][1], &opl->timers_enable[0][1], (void *)opl); +} + diff --git a/src/sound_mpu401_uart.c b/src/sound_mpu401_uart.c new file mode 100644 index 000000000..3ff22de61 --- /dev/null +++ b/src/sound_mpu401_uart.c @@ -0,0 +1,57 @@ +#include "ibm.h" +#include "io.h" +#include "sound_mpu401_uart.h" + +enum +{ + STATUS_OUTPUT_NOT_READY = 0x40, + STATUS_INPUT_NOT_READY = 0x80 +}; + +static void mpu401_uart_write(uint16_t addr, uint8_t val, void *p) +{ + mpu401_uart_t *mpu = (mpu401_uart_t *)p; + + if (addr & 1) /*Command*/ + { + switch (val) + { + case 0xff: /*Reset*/ + mpu->rx_data = 0xfe; /*Acknowledge*/ + mpu->status = 0; + mpu->uart_mode = 0; + break; + + case 0x3f: /*Enter UART mode*/ + mpu->rx_data = 0xfe; /*Acknowledge*/ + mpu->status = 0; + mpu->uart_mode = 1; + break; + } + return; + } + + /*Data*/ + if (mpu->uart_mode) + midi_write(val); +} + +static uint8_t mpu401_uart_read(uint16_t addr, void *p) +{ + mpu401_uart_t *mpu = (mpu401_uart_t *)p; + + if (addr & 1) /*Status*/ + return mpu->status; + + /*Data*/ + mpu->status |= STATUS_INPUT_NOT_READY; + return mpu->rx_data; +} + +void mpu401_uart_init(mpu401_uart_t *mpu, uint16_t addr) +{ + mpu->status = STATUS_INPUT_NOT_READY; + mpu->uart_mode = 0; + + io_sethandler(addr, 0x0002, mpu401_uart_read, NULL, NULL, mpu401_uart_write, NULL, NULL, mpu); +} diff --git a/src/sound_mpu401_uart.h b/src/sound_mpu401_uart.h new file mode 100644 index 000000000..893c53fc4 --- /dev/null +++ b/src/sound_mpu401_uart.h @@ -0,0 +1,9 @@ +typedef struct mpu401_uart_t +{ + uint8_t status; + uint8_t rx_data; + + int uart_mode; +} mpu401_uart_t; + +void mpu401_uart_init(mpu401_uart_t *mpu, uint16_t addr); diff --git a/src/sound_opl.c b/src/sound_opl.c new file mode 100644 index 000000000..e555f46be --- /dev/null +++ b/src/sound_opl.c @@ -0,0 +1,176 @@ +#include +#include +#include "ibm.h" +#include "io.h" +#include "sound.h" +#include "sound_opl.h" +#include "sound_dbopl.h" + +/*Interfaces between PCem and the actual OPL emulator*/ + + +uint8_t opl2_read(uint16_t a, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + cycles -= (int)(isa_timing * 8); + opl2_update2(opl); + return opl_read(0, a); +} +void opl2_write(uint16_t a, uint8_t v, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + opl2_update2(opl); + opl_write(0, a, v); + opl_write(1, a, v); +} + +uint8_t opl2_l_read(uint16_t a, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + cycles -= (int)(isa_timing * 8); + opl2_update2(opl); + return opl_read(0, a); +} +void opl2_l_write(uint16_t a, uint8_t v, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + opl2_update2(opl); + opl_write(0, a, v); +} + +uint8_t opl2_r_read(uint16_t a, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + cycles -= (int)(isa_timing * 8); + opl2_update2(opl); + return opl_read(1, a); +} +void opl2_r_write(uint16_t a, uint8_t v, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + opl2_update2(opl); + opl_write(1, a, v); +} + +uint8_t opl3_read(uint16_t a, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + cycles -= (int)(isa_timing * 8); + opl3_update2(opl); + return opl_read(0, a); +} +void opl3_write(uint16_t a, uint8_t v, void *priv) +{ + opl_t *opl = (opl_t *)priv; + + opl3_update2(opl); + opl_write(0, a, v); +} + + +void opl2_update2(opl_t *opl) +{ + if (opl->pos < sound_pos_global) + { + opl2_update(0, &opl->buffer[opl->pos*2], sound_pos_global - opl->pos); + opl2_update(1, &opl->buffer[opl->pos*2 + 1], sound_pos_global - opl->pos); + for (; opl->pos < sound_pos_global; opl->pos++) + { + opl->filtbuf[0] = opl->buffer[opl->pos*2] = (opl->buffer[opl->pos*2] / 4) + ((opl->filtbuf[0] * 11) / 16); + opl->filtbuf[1] = opl->buffer[opl->pos*2+1] = (opl->buffer[opl->pos*2+1] / 4) + ((opl->filtbuf[1] * 11) / 16); + } + } +} + +void opl3_update2(opl_t *opl) +{ + if (opl->pos < sound_pos_global) + { + opl3_update(0, &opl->buffer[opl->pos*2], sound_pos_global - opl->pos); + for (; opl->pos < sound_pos_global; opl->pos++) + { + opl->filtbuf[0] = opl->buffer[opl->pos*2] = (opl->buffer[opl->pos*2] / 4) + ((opl->filtbuf[0] * 11) / 16); + opl->filtbuf[1] = opl->buffer[opl->pos*2+1] = (opl->buffer[opl->pos*2+1] / 4) + ((opl->filtbuf[1] * 11) / 16); + } + } +} + +void ym3812_timer_set_0(void *param, int timer, int64_t period) +{ + opl_t *opl = (opl_t *)param; + + opl->timers[0][timer] = period * TIMER_USEC * 20; + if (!opl->timers[0][timer]) opl->timers[0][timer] = 1; + opl->timers_enable[0][timer] = period ? 1 : 0; +} +void ym3812_timer_set_1(void *param, int timer, int64_t period) +{ + opl_t *opl = (opl_t *)param; + + opl->timers[1][timer] = period * TIMER_USEC * 20; + if (!opl->timers[1][timer]) opl->timers[1][timer] = 1; + opl->timers_enable[1][timer] = period ? 1 : 0; +} + +void ymf262_timer_set(void *param, int timer, int64_t period) +{ + opl_t *opl = (opl_t *)param; + + opl->timers[0][timer] = period * TIMER_USEC * 20; + if (!opl->timers[0][timer]) opl->timers[0][timer] = 1; + opl->timers_enable[0][timer] = period ? 1 : 0; +} + +static void opl_timer_callback00(void *p) +{ + opl_t *opl = (opl_t *)p; + + opl->timers_enable[0][0] = 0; + opl_timer_over(0, 0); +} +static void opl_timer_callback01(void *p) +{ + opl_t *opl = (opl_t *)p; + + opl->timers_enable[0][1] = 0; + opl_timer_over(0, 1); +} +static void opl_timer_callback10(void *p) +{ + opl_t *opl = (opl_t *)p; + + opl->timers_enable[1][0] = 0; + opl_timer_over(1, 0); +} +static void opl_timer_callback11(void *p) +{ + opl_t *opl = (opl_t *)p; + + opl->timers_enable[1][1] = 0; + opl_timer_over(1, 1); +} + +void opl2_init(opl_t *opl) +{ + opl_init(ym3812_timer_set_0, opl, 0, 0); + opl_init(ym3812_timer_set_1, opl, 1, 0); + timer_add(opl_timer_callback00, &opl->timers[0][0], &opl->timers_enable[0][0], (void *)opl); + timer_add(opl_timer_callback01, &opl->timers[0][1], &opl->timers_enable[0][1], (void *)opl); + timer_add(opl_timer_callback10, &opl->timers[1][0], &opl->timers_enable[1][0], (void *)opl); + timer_add(opl_timer_callback11, &opl->timers[1][1], &opl->timers_enable[1][1], (void *)opl); +} + +void opl3_init(opl_t *opl) +{ + opl_init(ymf262_timer_set, opl, 0, 1); + timer_add(opl_timer_callback00, &opl->timers[0][0], &opl->timers_enable[0][0], (void *)opl); + timer_add(opl_timer_callback01, &opl->timers[0][1], &opl->timers_enable[0][1], (void *)opl); +} + diff --git a/src/sound_opl.h b/src/sound_opl.h new file mode 100644 index 000000000..9a03fda3a --- /dev/null +++ b/src/sound_opl.h @@ -0,0 +1,30 @@ +typedef struct opl_t +{ + int chip_nr[2]; + + int timers[2][2]; + int timers_enable[2][2]; + + int16_t filtbuf[2]; + + int16_t buffer[SOUNDBUFLEN * 2]; + int pos; +} opl_t; + +uint8_t opl2_read(uint16_t a, void *priv); +void opl2_write(uint16_t a, uint8_t v, void *priv); +uint8_t opl2_l_read(uint16_t a, void *priv); +void opl2_l_write(uint16_t a, uint8_t v, void *priv); +uint8_t opl2_r_read(uint16_t a, void *priv); +void opl2_r_write(uint16_t a, uint8_t v, void *priv); +uint8_t opl3_read(uint16_t a, void *priv); +void opl3_write(uint16_t a, uint8_t v, void *priv); + +void opl2_poll(opl_t *opl, int16_t *bufl, int16_t *bufr); +void opl3_poll(opl_t *opl, int16_t *bufl, int16_t *bufr); + +void opl2_init(opl_t *opl); +void opl3_init(opl_t *opl); + +void opl2_update2(opl_t *opl); +void opl3_update2(opl_t *opl); diff --git a/src/sound_pas16.c b/src/sound_pas16.c new file mode 100644 index 000000000..cc5a23538 --- /dev/null +++ b/src/sound_pas16.c @@ -0,0 +1,763 @@ +#include +#include "ibm.h" + +#include "device.h" +#include "dma.h" +#include "filters.h" +#include "io.h" +#include "pic.h" +#include "pit.h" +#include "sound.h" +#include "sound_opl.h" +#include "sound_pas16.h" +#include "sound_sb_dsp.h" +#include "timer.h" + +/* Original PAS uses + 2 x OPL2 + PIT - sample rate/count + LMC835N/LMC1982 - mixer + YM3802 - MIDI Control System + + + 9A01 - IO base + base >> 2 + + All below + IO base + + B89 - interrupt status / clear + bit 2 - sample rate + bit 3 - PCM + bit 4 - MIDI + + B88 - Audio mixer control register + + B8A - Audio filter control + bit 5 - mute? + + B8B - interrupt mask / board ID + bits 5-7 - board ID (read only on PAS16) + + F88 - PCM data (low) + + F89 - PCM data (high) + + F8A - PCM control? + bit 4 - input/output select (1 = output) + bit 5 - mono/stereo select + bit 6 - PCM enable + + 1388-138b - PIT clocked at 1193180 Hz + 1388 - sample rate + 1389 - sample count + + 178b - + 2789 - board revision + + 8389 - + bit 2 - 8/16 bit + + BF88 - wait states + + EF8B - + bit 3 - 16 bits okay ? + + F388 - + bit 6 - joystick enable + + F389 - + bits 0-2 - DMA + + F38A - + bits 0-3 - IRQ + + F788 - + bit 1 - SB emulation + bit 0 - MPU401 emulation + + F789 - SB base addr + bits 0-3 - addr bits 4-7 + + FB8A - SB IRQ/DMA + bits 3-5 - IRQ + bits 6-7 - DMA + + FF88 - board model + 3 = PAS16 +*/ + +typedef struct pas16_t +{ + uint16_t base; + + int irq, dma; + + uint8_t audiofilt; + + uint8_t audio_mixer; + + uint8_t compat, compat_base; + + uint8_t enhancedscsi; + + uint8_t io_conf_1, io_conf_2, io_conf_3, io_conf_4; + + uint8_t irq_stat, irq_ena; + + uint8_t pcm_ctrl; + uint16_t pcm_dat; + + uint16_t pcm_dat_l, pcm_dat_r; + + uint8_t sb_irqdma; + + int stereo_lr; + + uint8_t sys_conf_1, sys_conf_2, sys_conf_3, sys_conf_4; + + struct + { + uint32_t l[3]; + int c[3]; + uint8_t m[3]; + uint8_t ctrl, ctrls[2]; + int wp, rm[3], wm[3]; + uint16_t rl[3]; + int thit[3]; + int delay[3]; + int rereadlatch[3]; + int enable[3]; + } pit; + + opl_t opl; + sb_dsp_t dsp; + + int16_t pcm_buffer[2][SOUNDBUFLEN]; + + int pos; +} pas16_t; + +static uint8_t pas16_pit_in(uint16_t port, void *priv); +static void pas16_pit_out(uint16_t port, uint8_t val, void *priv); +static void pas16_update(pas16_t *pas16); + +static int pas16_dmas[8] = {4, 1, 2, 3, 0, 5, 6, 7}; +static int pas16_irqs[16] = {0, 2, 3, 4, 5, 6, 7, 10, 11, 12, 14, 15, 0, 0, 0, 0}; +static int pas16_sb_irqs[8] = {0, 2, 3, 5, 7, 10, 11, 12}; +static int pas16_sb_dmas[8] = {0, 1, 2, 3}; + +enum +{ + PAS16_INT_SAMP = 0x04, + PAS16_INT_PCM = 0x08, +}; + +enum +{ + PAS16_PCM_MONO = 0x20, + PAS16_PCM_ENA = 0x40 +}; + +enum +{ + PAS16_SC2_16BIT = 0x04, + PAS16_SC2_MSBINV = 0x10 +}; + +enum +{ + PAS16_FILT_MUTE = 0x20 +}; + +static uint8_t pas16_in(uint16_t port, void *p) +{ + pas16_t *pas16 = (pas16_t *)p; + uint8_t temp; +/* if (CS == 0xCA53 && pc == 0x3AFC) + fatal("here");*/ + switch ((port - pas16->base) + 0x388) + { + case 0x388: case 0x389: case 0x38a: case 0x38b: + temp = opl3_read((port - pas16->base) + 0x388, &pas16->opl); + break; + + case 0xb88: + temp = pas16->audio_mixer; + break; + + case 0xb89: + temp = pas16->irq_stat; + break; + + case 0xb8a: + temp = pas16->audiofilt; + break; + + case 0xb8b: + temp = (pas16->irq_ena & ~0xe0) | 0x20; + break; + + case 0xf8a: + temp = pas16->pcm_ctrl; + break; + + case 0x1388: case 0x1389: case 0x138a: case 0x138b: + temp = pas16_pit_in(port, pas16); + break; + + case 0x2789: /*Board revision*/ + temp = 0; + break; + + case 0x7f89: + temp = pas16->enhancedscsi & ~1; + break; + + case 0x8388: + temp = pas16->sys_conf_1; + break; + case 0x8389: + temp = pas16->sys_conf_2; + break; + case 0x838b: + temp = pas16->sys_conf_3; + break; + case 0x838c: + temp = pas16->sys_conf_4; + break; + + case 0xef8b: + temp = 0x0c; + break; + + case 0xf388: + temp = pas16->io_conf_1; + break; + case 0xf389: + temp = pas16->io_conf_2; + break; + case 0xf38b: + temp = pas16->io_conf_3; + break; + case 0xf38c: + temp = pas16->io_conf_4; + break; + + case 0xf788: + temp = pas16->compat; + break; + case 0xf789: + temp = pas16->compat_base; + break; + + case 0xfb8a: + temp = pas16->sb_irqdma; + break; + + case 0xff88: /*Board model*/ + temp = 4; /*PAS16*/ + break; + case 0xff8b: /*Master mode read*/ + temp = 0x20 | 0x10 | 0x01; /*AT bus, XT/AT timing*/ + break; + } +/* if (port != 0x388 && port != 0x389 && port != 0xb8b) */pclog("pas16_in : port %04X return %02X %04X:%04X\n", port, temp, CS,cpu_state.pc); +/* if (CS == 0x1FF4 && pc == 0x0585) + { + if (output) + fatal("here"); + output = 3; + }*/ + return temp; +} + +static void pas16_out(uint16_t port, uint8_t val, void *p) +{ + pas16_t *pas16 = (pas16_t *)p; +/* if (port != 0x388 && port != 0x389) */pclog("pas16_out : port %04X val %02X %04X:%04X\n", port, val, CS,cpu_state.pc); +/* if (CS == 0x369 && pc == 0x2AC5) + fatal("here\n");*/ + switch ((port - pas16->base) + 0x388) + { + case 0x388: case 0x389: case 0x38a: case 0x38b: + opl3_write((port - pas16->base) + 0x388, val, &pas16->opl); + break; + + case 0xb88: + pas16->audio_mixer = val; + break; + + case 0xb89: + pas16->irq_stat &= ~val; +// pas16_update_irqs(); + break; + + case 0xb8a: + pas16_update(pas16); + pas16->audiofilt = val; + break; + + case 0xb8b: + pas16->irq_ena = val; +// pas16_update_irqs(); + break; + + case 0xf88: + pas16_update(pas16); + pas16->pcm_dat = (pas16->pcm_dat & 0xff00) | val; + break; + case 0xf89: + pas16_update(pas16); + pas16->pcm_dat = (pas16->pcm_dat & 0x00ff) | (val << 8); + break; + case 0xf8a: + if ((val & PAS16_PCM_ENA) && !(pas16->pcm_ctrl & PAS16_PCM_ENA)) /*Guess*/ + pas16->stereo_lr = 0; + pas16->pcm_ctrl = val; + break; + + case 0x1388: case 0x1389: case 0x138a: case 0x138b: + pas16_pit_out(port, val, pas16); + break; + + case 0x7f89: + pas16->enhancedscsi = val; + break; + + case 0x8388: + pas16->sys_conf_1 = val; + break; + case 0x8389: + pas16->sys_conf_2 = val; + break; + case 0x838a: + pas16->sys_conf_3 = val; + break; + case 0x838b: + pas16->sys_conf_4 = val; + break; + + case 0xf388: + pas16->io_conf_1 = val; + break; + case 0xf389: + pas16->io_conf_2 = val; + pas16->dma = pas16_dmas[val & 0x7]; + pclog("pas16_out : set PAS DMA %i\n", pas16->dma); + break; + case 0xf38a: + pas16->io_conf_3 = val; + pas16->irq = pas16_irqs[val & 0xf]; + pclog("pas16_out : set PAS IRQ %i\n", pas16->irq); + break; + case 0xf38b: + pas16->io_conf_4 = val; + break; + + case 0xf788: + pas16->compat = val; + if (pas16->compat & 0x02) + sb_dsp_setaddr(&pas16->dsp, ((pas16->compat_base & 0xf) << 4) | 0x200); + else + sb_dsp_setaddr(&pas16->dsp, 0); + break; + case 0xf789: + pas16->compat_base = val; + if (pas16->compat & 0x02) + sb_dsp_setaddr(&pas16->dsp, ((pas16->compat_base & 0xf) << 4) | 0x200); + break; + + case 0xfb8a: + pas16->sb_irqdma = val; + sb_dsp_setirq(&pas16->dsp, pas16_sb_irqs[(val >> 3) & 7]); + sb_dsp_setdma8(&pas16->dsp, pas16_sb_dmas[(val >> 6) & 3]); + pclog("pas16_out : set SB IRQ %i DMA %i\n", pas16_sb_irqs[(val >> 3) & 7], pas16_sb_dmas[(val >> 6) & 3]); + break; + + default: + pclog("pas16_out : unknown %04X\n", port); + } + if (cpu_state.pc == 0x80048CF3) + { + if (output) + fatal("here\n"); + output = 3; + } +/* if (CS == 0x1FF4 && pc == 0x0431) + output = 3;*/ +} + +static void pas16_pit_out(uint16_t port, uint8_t val, void *p) +{ + pas16_t *pas16 = (pas16_t *)p; + int t; + switch (port & 3) + { + case 3: /*CTRL*/ + if ((val & 0xC0) == 0xC0) + { + if (!(val & 0x20)) + { + if (val & 2) pas16->pit.rl[0] = pas16->pit.c[0] / (PITCONST * (1 << TIMER_SHIFT)); + if (val & 4) pas16->pit.rl[1] = pas16->pit.c[1]; + if (val & 8) pas16->pit.rl[2] = pas16->pit.c[2]; + } + return; + } + t = val >> 6; + pas16->pit.ctrls[t] = pas16->pit.ctrl = val; + if (t == 3) + { + printf("Bad PIT reg select\n"); + return; + } + if (!(pas16->pit.ctrl & 0x30)) + { + pas16->pit.rl[t] = pas16->pit.c[t]; + if (!t) + pas16->pit.rl[t] /= (PITCONST * (1 << TIMER_SHIFT)); + if (pas16->pit.c[t] < 0) + pas16->pit.rl[t] = 0; + pas16->pit.ctrl |= 0x30; + pas16->pit.rereadlatch[t] = 0; + pas16->pit.rm[t] = 3; + } + else + { + pas16->pit.rm[t] = pas16->pit.wm[t] = (pas16->pit.ctrl >> 4) & 3; + pas16->pit.m[t] = (val >> 1) & 7; + if (pas16->pit.m[t] > 5) + pas16->pit.m[t] &= 3; + if (!pas16->pit.rm[t]) + { + pas16->pit.rm[t] = 3; + pas16->pit.rl[t] = pit.c[t]; + if (!t) + pas16->pit.rl[t] /= (PITCONST * (1 << TIMER_SHIFT)); + } + pas16->pit.rereadlatch[t] = 1; + } + pas16->pit.wp = 0; + pas16->pit.thit[t] = 0; + break; + case 0: case 1: case 2: /*Timers*/ + t = port & 3; + switch (pas16->pit.wm[t]) + { + case 1: + pas16->pit.l[t] = val; + pas16->pit.thit[t] = 0; + pas16->pit.c[t] = pas16->pit.l[t]; + if (!t) + pas16->pit.c[t] *= PITCONST * (1 << TIMER_SHIFT); + pas16->pit.enable[t] = 1; + break; + case 2: + pas16->pit.l[t] = val << 8; + pas16->pit.thit[t] = 0; + pas16->pit.c[t] = pas16->pit.l[t]; + if (!t) + pas16->pit.c[t] *= PITCONST * (1 << TIMER_SHIFT); + pas16->pit.enable[t] = 1; + break; + case 0: + pas16->pit.l[t] &= 0xFF; + pas16->pit.l[t] |= (val << 8); + pas16->pit.c[t] = pas16->pit.l[t]; + if (!t) + pas16->pit.c[t] *= PITCONST * (1 << TIMER_SHIFT); + pas16->pit.thit[t] = 0; + pas16->pit.wm[t] = 3; + pas16->pit.enable[t] = 1; + break; + case 3: + pas16->pit.l[t] &= 0xFF00; + pas16->pit.l[t] |= val; + pas16->pit.wm[t] = 0; + break; + } + if (!pas16->pit.l[t]) + { + pas16->pit.l[t] |= 0x10000; + pas16->pit.c[t] = pas16->pit.l[t]; + if (!t) + pas16->pit.c[t] *= PITCONST * (1 << TIMER_SHIFT); + } + break; + } +} + +static uint8_t pas16_pit_in(uint16_t port, void *p) +{ + pas16_t *pas16 = (pas16_t *)p; + uint8_t temp; + int t = port & 3; +// printf("Read PIT %04X ",addr); + switch (port & 3) + { + case 0: case 1: case 2: /*Timers*/ + if (pas16->pit.rereadlatch[t]) + { + pas16->pit.rereadlatch[t] = 0; + if (!t) + { + pas16->pit.rl[t] = pas16->pit.c[t] / (PITCONST * (1 << TIMER_SHIFT)); + if ((pas16->pit.c[t] / (PITCONST * (1 << TIMER_SHIFT))) > 65536) + pas16->pit.rl[t] = 0xFFFF; + } + else + { + pas16->pit.rl[t] = pas16->pit.c[t]; + if (pas16->pit.c[t] > 65536) + pas16->pit.rl[t] = 0xFFFF; + } + } + switch (pas16->pit.rm[t]) + { + case 0: + temp = pas16->pit.rl[t] >> 8; + pas16->pit.rm[t] = 3; + pas16->pit.rereadlatch[t] = 1; + break; + case 1: + temp = (pas16->pit.rl[t]) & 0xFF; + pas16->pit.rereadlatch[t] = 1; + break; + case 2: + temp = (pas16->pit.rl[t]) >> 8; + pas16->pit.rereadlatch[t] = 1; + break; + case 3: + temp = (pas16->pit.rl[t]) & 0xFF; + if (pas16->pit.m[t] & 0x80) pas16->pit.m[t] &= 7; + else pas16->pit.rm[t] = 0; + break; + } + break; + case 3: /*Control*/ + temp = pas16->pit.ctrl; + break; + } +// printf("%02X %i %i %04X:%04X\n",temp,pit.rm[addr&3],pit.wp,cs>>4,pc); + return temp; +} + +static uint8_t pas16_readdma(pas16_t *pas16) +{ + return dma_channel_read(pas16->dma); +} + +static void pas16_pcm_poll(void *p) +{ + pas16_t *pas16 = (pas16_t *)p; + + pas16_update(pas16); +// if (pas16->pcm_ctrl & PAS16_PCM_ENA) +// pclog("pas16_pcm_poll : poll %i %i ", pas16->pit.c[0], pas16->pit.l[0]); + if (pas16->pit.m[0] & 2) + { + if (pas16->pit.l[0]) + pas16->pit.c[0] += (pas16->pit.l[0] * PITCONST * (1 << TIMER_SHIFT)); + else + pas16->pit.c[0] += (0x10000 * PITCONST * (1 << TIMER_SHIFT)); + } + else + { + pas16->pit.c[0] = -1; + pas16->pit.enable[0] = 0; + } +// if (pas16->pcm_ctrl & PAS16_PCM_ENA) +// pclog(" %i\n", pas16->pit.c[0]); + + pas16->irq_stat |= PAS16_INT_SAMP; + if (pas16->irq_ena & PAS16_INT_SAMP) + picint(1 << pas16->irq); +// pas16_update_irqs(); + + /*Update sample rate counter*/ + if (pas16->pit.enable[1]) + { + if (pas16->pcm_ctrl & PAS16_PCM_ENA) + { + uint16_t temp; + + if (pas16->sys_conf_2 & PAS16_SC2_16BIT) + { + temp = pas16_readdma(pas16) << 8; + temp |= pas16_readdma(pas16); + } + else + temp = (pas16_readdma(pas16) ^ 0x80) << 8; + + if (pas16->sys_conf_2 & PAS16_SC2_MSBINV) + temp ^= 0x8000; + if (pas16->pcm_ctrl & PAS16_PCM_MONO) + pas16->pcm_dat_l = pas16->pcm_dat_r = temp; + else + { + if (pas16->stereo_lr) + pas16->pcm_dat_r = temp; + else + pas16->pcm_dat_l = temp; + + pas16->stereo_lr = !pas16->stereo_lr; + } +// pclog("pas16_pcm_poll : %04X %i\n", temp, pas16->stereo_lr); +// pclog("pas16_pcm_poll : %i %02X %i\n", pas16->pit.c[1], temp, pas16->pit.c[0]); +/* if (!pas16_pcm) + pas16_pcm=fopen("pas16->pcm", "wb"); + putc(temp, pas16_pcm);*/ + } + if (pas16->sys_conf_2 & PAS16_SC2_16BIT) + pas16->pit.c[1] -= 2; + else + pas16->pit.c[1]--; + if (pas16->pit.c[1] == 0) + { +// if (pas16->pcm_ctrl & PAS16_PCM_ENA) +// pclog("pas16_pcm_poll : buffer over\n"); + if (pas16->pit.m[1] & 2) + { + if (pas16->pit.l[1]) + pas16->pit.c[1] += pas16->pit.l[1]; + else + pas16->pit.c[1] += 0x10000; + } + else + { + pas16->pit.c[1] = -1; + pas16->pit.enable[1] = 0; + } + + pas16->irq_stat |= PAS16_INT_PCM; + if (pas16->irq_ena & PAS16_INT_PCM) + { + pclog("pas16_pcm_poll : cause IRQ %i %02X\n", pas16->irq, 1 << pas16->irq); + picint(1 << pas16->irq); + } + } + } +} + +static void pas16_out_base(uint16_t port, uint8_t val, void *p) +{ + pas16_t *pas16 = (pas16_t *)p; + + io_removehandler((pas16->base - 0x388) + 0x0388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x0788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x0b88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x0f88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x1388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x1788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x2788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x7f88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0x8388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xbf88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xe388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xe788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xeb88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xef88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xf388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xf788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xfb88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_removehandler((pas16->base - 0x388) + 0xff88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + + pas16->base = val << 2; + pclog("pas16_write_base : PAS16 base now at %04X\n", pas16->base); + + io_sethandler((pas16->base - 0x388) + 0x0388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x0788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x0b88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x0f88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x1388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x1788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x2788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x7f88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0x8388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xbf88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xe388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xe788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xeb88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xef88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xf388, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xf788, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xfb88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); + io_sethandler((pas16->base - 0x388) + 0xff88, 0x0004, pas16_in, NULL, NULL, pas16_out, NULL, NULL, pas16); +} + + +static void pas16_update(pas16_t *pas16) +{ + if (!(pas16->audiofilt & PAS16_FILT_MUTE)) + { + for (; pas16->pos < sound_pos_global; pas16->pos++) + { + pas16->pcm_buffer[0][pas16->pos] = 0; + pas16->pcm_buffer[1][pas16->pos] = 0; + } + } + else + { + for (; pas16->pos < sound_pos_global; pas16->pos++) + { + pas16->pcm_buffer[0][pas16->pos] = (int16_t)pas16->pcm_dat_l; + pas16->pcm_buffer[1][pas16->pos] = (int16_t)pas16->pcm_dat_r; + } + } +} + +void pas16_get_buffer(int32_t *buffer, int len, void *p) +{ + pas16_t *pas16 = (pas16_t *)p; + int c; + + opl3_update2(&pas16->opl); + sb_dsp_update(&pas16->dsp); + pas16_update(pas16); + for (c = 0; c < len * 2; c++) + { + buffer[c] += pas16->opl.buffer[c]; + buffer[c] += (int16_t)(sb_iir(c & 1, (float)pas16->dsp.buffer[c]) / 1.3) / 2; + buffer[c] += (pas16->pcm_buffer[c & 1][c >> 1] / 2); + } + + pas16->pos = 0; + pas16->opl.pos = 0; + pas16->dsp.pos = 0; +} + +void *pas16_init() +{ + pas16_t *pas16 = malloc(sizeof(pas16_t)); + memset(pas16, 0, sizeof(pas16_t)); + + opl3_init(&pas16->opl); + sb_dsp_init(&pas16->dsp, SB2); + + io_sethandler(0x9a01, 0x0001, NULL, NULL, NULL, pas16_out_base, NULL, NULL, pas16); + + timer_add(pas16_pcm_poll, &pas16->pit.c[0], &pas16->pit.enable[0], pas16); + + sound_add_handler(pas16_get_buffer, pas16); + + return pas16; +} + +void pas16_close(void *p) +{ + pas16_t *pas16 = (pas16_t *)p; + + free(pas16); +} + +device_t pas16_device = +{ + "Pro Audio Spectrum 16", + DEVICE_NOT_WORKING, + pas16_init, + pas16_close, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/sound_pas16.h b/src/sound_pas16.h new file mode 100644 index 000000000..e3a134751 --- /dev/null +++ b/src/sound_pas16.h @@ -0,0 +1 @@ +extern device_t pas16_device; diff --git a/src/sound_ps1.c b/src/sound_ps1.c new file mode 100644 index 000000000..4f42cd4d8 --- /dev/null +++ b/src/sound_ps1.c @@ -0,0 +1,174 @@ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "sound.h" +#include "sound_ps1.h" +#include "sound_sn76489.h" + +typedef struct ps1_audio_t +{ + sn76489_t sn76489; + + uint8_t status, ctrl; + + int timer_latch, timer_count, timer_enable; + + uint8_t fifo[2048]; + int fifo_read_idx, fifo_write_idx; + int fifo_threshold; + + uint8_t dac_val; + + int16_t buffer[SOUNDBUFLEN]; + int pos; +} ps1_audio_t; + +static void ps1_update_irq_status(ps1_audio_t *ps1) +{ + if (((ps1->status & ps1->ctrl) & 0x12) && (ps1->ctrl & 0x01)) + picint(1 << 7); + else + picintc(1 << 7); +} + +static uint8_t ps1_audio_read(uint16_t port, void *p) +{ + ps1_audio_t *ps1 = (ps1_audio_t *)p; + uint8_t temp; + +// pclog("ps1_audio_read %04x %04x:%04x\n", port, CS, pc); + + switch (port & 7) + { + case 0: /*ADC data*/ + ps1->status &= ~0x10; + ps1_update_irq_status(ps1); + return 0; + case 2: /*Status*/ + temp = ps1->status; + temp |= (ps1->ctrl & 0x01); + if ((ps1->fifo_write_idx - ps1->fifo_read_idx) >= 2048) + temp |= 0x08; /*FIFO full*/ + if (ps1->fifo_read_idx == ps1->fifo_write_idx) + temp |= 0x04; /*FIFO empty*/ +// pclog("Return status %02x\n", temp); + return temp; + case 3: /*FIFO timer*/ + /*PS/1 technical reference says this should return the current value, + but the PS/1 BIOS and Stunt Island expect it not to change*/ + return ps1->timer_latch; + case 4: case 5: case 6: case 7: + return 0; + } + return 0xff; +} + +static void ps1_audio_write(uint16_t port, uint8_t val, void *p) +{ + ps1_audio_t *ps1 = (ps1_audio_t *)p; + +// pclog("ps1_audio_write %04x %02x\n", port, val); + + switch (port & 7) + { + case 0: /*DAC output*/ +// pclog("DAC write %08x %08x %i\n", ps1->fifo_write_idx, ps1->fifo_read_idx, ps1->fifo_write_idx - ps1->fifo_read_idx); + if ((ps1->fifo_write_idx - ps1->fifo_read_idx) < 2048) + { + ps1->fifo[ps1->fifo_write_idx & 2047] = val; + ps1->fifo_write_idx++; + } + break; + case 2: /*Control*/ + ps1->ctrl = val; + if (!(val & 0x02)) + ps1->status &= ~0x02; + ps1_update_irq_status(ps1); + break; + case 3: /*Timer reload value*/ + ps1->timer_latch = val; + ps1->timer_count = (0xff-val) * TIMER_USEC; + ps1->timer_enable = (val != 0); + break; + case 4: /*Almost empty*/ + ps1->fifo_threshold = val * 4; + break; + } +} + +static void ps1_audio_update(ps1_audio_t *ps1) +{ + for (; ps1->pos < sound_pos_global; ps1->pos++) + ps1->buffer[ps1->pos] = (int8_t)(ps1->dac_val ^ 0x80) * 0x20; +} + +static void ps1_audio_callback(void *p) +{ + ps1_audio_t *ps1 = (ps1_audio_t *)p; + + ps1_audio_update(ps1); + + if (ps1->fifo_read_idx != ps1->fifo_write_idx) + { + ps1->dac_val = ps1->fifo[ps1->fifo_read_idx & 2047]; + ps1->fifo_read_idx++; + } +// pclog("ps1_callback %08x %08x %08x\n", ps1->fifo_write_idx, ps1->fifo_read_idx, ps1->fifo_threshold); + if ((ps1->fifo_write_idx - ps1->fifo_read_idx) == ps1->fifo_threshold) + { +// pclog("FIFO almost empty\n"); + ps1->status |= 0x02; /*FIFO almost empty*/ + } + ps1->status |= 0x10; /*ADC data ready*/ + ps1_update_irq_status(ps1); + + ps1->timer_count += ps1->timer_latch * TIMER_USEC; +} + +static void ps1_audio_get_buffer(int32_t *buffer, int len, void *p) +{ + ps1_audio_t *ps1 = (ps1_audio_t *)p; + int c; + + ps1_audio_update(ps1); + + for (c = 0; c < len * 2; c++) + buffer[c] += ps1->buffer[c >> 1]; + + ps1->pos = 0; +} + +static void *ps1_audio_init() +{ + ps1_audio_t *ps1 = malloc(sizeof(ps1_audio_t)); + memset(ps1, 0, sizeof(ps1_audio_t)); + + sn76489_init(&ps1->sn76489, 0x0205, 0x0001, SN76496, 4000000); + + io_sethandler(0x0200, 0x0001, ps1_audio_read, NULL, NULL, ps1_audio_write, NULL, NULL, ps1); + io_sethandler(0x0202, 0x0006, ps1_audio_read, NULL, NULL, ps1_audio_write, NULL, NULL, ps1); + timer_add(ps1_audio_callback, &ps1->timer_count, &ps1->timer_enable, ps1); + sound_add_handler(ps1_audio_get_buffer, ps1); + + return ps1; +} + +static void ps1_audio_close(void *p) +{ + ps1_audio_t *ps1 = (ps1_audio_t *)p; + + free(ps1); +} + +device_t ps1_audio_device = +{ + "PS/1 Audio Card", + 0, + ps1_audio_init, + ps1_audio_close, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/sound_ps1.h b/src/sound_ps1.h new file mode 100644 index 000000000..04bb209d5 --- /dev/null +++ b/src/sound_ps1.h @@ -0,0 +1 @@ +extern device_t ps1_audio_device; diff --git a/src/sound_pssj.c b/src/sound_pssj.c new file mode 100644 index 000000000..0e4963d5d --- /dev/null +++ b/src/sound_pssj.c @@ -0,0 +1,214 @@ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "sound.h" +#include "sound_pssj.h" +#include "sound_sn76489.h" + +#include "dma.h" +#include "pic.h" +#include "timer.h" + +typedef struct pssj_t +{ + sn76489_t sn76489; + + uint8_t ctrl; + uint8_t wave; + uint8_t dac_val; + uint16_t freq; + int amplitude; + + int irq; + int timer_count; + int enable; + + int wave_pos; + int pulse_width; + + int16_t buffer[SOUNDBUFLEN]; + int pos; +} pssj_t; + +static void pssj_update_irq(pssj_t *pssj) +{ + if (pssj->irq && (pssj->ctrl & 0x10) && (pssj->ctrl & 0x08)) + picint(1 << 7); +} + +static void pssj_write(uint16_t port, uint8_t val, void *p) +{ + pssj_t *pssj = (pssj_t *)p; + +// pclog("pssj_write: port=%04x val=%02x\n", port, val); + switch (port & 3) + { + case 0: + pssj->ctrl = val; + pssj->enable = (val & 4) && (pssj->ctrl & 3); + sn74689_set_extra_divide(&pssj->sn76489, val & 0x40); + if (!(val & 8)) + pssj->irq = 0; + pssj_update_irq(pssj); + break; + case 1: + switch (pssj->ctrl & 3) + { + case 1: /*Sound channel*/ + pssj->wave = val; + pssj->pulse_width = val & 7; + break; + case 3: /*Direct DAC*/ + pssj->dac_val = val; + break; + } + break; + case 2: + pssj->freq = (pssj->freq & 0xf00) | val; + break; + case 3: + pssj->freq = (pssj->freq & 0x0ff) | ((val & 0xf) << 8); + pssj->amplitude = val >> 4; + break; + } +} +static uint8_t pssj_read(uint16_t port, void *p) +{ + pssj_t *pssj = (pssj_t *)p; + +// pclog("pssj_read: port=%04x %02x\n", port, (pssj->ctrl & ~0x88) | (pssj->irq ? 8 : 0)); + switch (port & 3) + { + case 0: + return (pssj->ctrl & ~0x88) | (pssj->irq ? 8 : 0); + case 1: + switch (pssj->ctrl & 3) + { + case 0: /*Joystick*/ + return 0; + case 1: /*Sound channel*/ + return pssj->wave; + case 2: /*Successive approximation*/ + return 0x80; + case 3: /*Direct DAC*/ + return pssj->dac_val; + } + break; + case 2: + return pssj->freq & 0xff; + case 3: + return (pssj->freq >> 8) | (pssj->amplitude << 4); + } +} + +static void pssj_update(pssj_t *pssj) +{ + for (; pssj->pos < sound_pos_global; pssj->pos++) + pssj->buffer[pssj->pos] = (((int8_t)(pssj->dac_val ^ 0x80) * 0x20) * pssj->amplitude) / 15; +} + +static void pssj_callback(void *p) +{ + pssj_t *pssj = (pssj_t *)p; + int data; + + pssj_update(pssj); + if (pssj->ctrl & 2) + { + if ((pssj->ctrl & 3) == 3) + { + data = dma_channel_read(1); + + if (data != DMA_NODATA) + { + pssj->dac_val = data & 0xff; +// pclog("DAC_val=%02x\n", data); + } + } + else + { + data = dma_channel_write(1, 0x80); + } + + if ((data & DMA_OVER) && data != DMA_NODATA) + { +// pclog("Check IRQ %i %02x\n", pssj->irq, pssj->ctrl); + if (pssj->ctrl & 0x08) + { + pssj->irq = 1; + pssj_update_irq(pssj); + } + } + } + else + { + switch (pssj->wave & 0xc0) + { + case 0x00: /*Pulse*/ + pssj->dac_val = (pssj->wave_pos > (pssj->pulse_width << 1)) ? 0xff : 0; + break; + case 0x40: /*Ramp*/ + pssj->dac_val = pssj->wave_pos << 3; + break; + case 0x80: /*Triangle*/ + if (pssj->wave_pos & 16) + pssj->dac_val = (pssj->wave_pos ^ 31) << 4; + else + pssj->dac_val = pssj->wave_pos << 4; + break; + case 0xc0: + pssj->dac_val = 0x80; + break; + } + pssj->wave_pos = (pssj->wave_pos + 1) & 31; + } + + pssj->timer_count += (int)(TIMER_USEC * (1000000.0 / 3579545.0) * (double)(pssj->freq ? pssj->freq : 0x400)); +} + +static void pssj_get_buffer(int32_t *buffer, int len, void *p) +{ + pssj_t *pssj = (pssj_t *)p; + int c; + + pssj_update(pssj); + + for (c = 0; c < len * 2; c++) + buffer[c] += pssj->buffer[c >> 1]; + + pssj->pos = 0; +} + +void *pssj_init() +{ + pssj_t *pssj = malloc(sizeof(pssj_t)); + memset(pssj, 0, sizeof(pssj_t)); + + sn76489_init(&pssj->sn76489, 0x00c0, 0x0004, PSSJ, 3579545); + + io_sethandler(0x00C4, 0x0004, pssj_read, NULL, NULL, pssj_write, NULL, NULL, pssj); + timer_add(pssj_callback, &pssj->timer_count, &pssj->enable, pssj); + sound_add_handler(pssj_get_buffer, pssj); + + return pssj; +} + +void pssj_close(void *p) +{ + pssj_t *pssj = (pssj_t *)p; + + free(pssj); +} + +device_t pssj_device = +{ + "Tandy PSSJ", + 0, + pssj_init, + pssj_close, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/sound_pssj.h b/src/sound_pssj.h new file mode 100644 index 000000000..2255d48fb --- /dev/null +++ b/src/sound_pssj.h @@ -0,0 +1 @@ +extern device_t pssj_device; diff --git a/src/sound_resid.cc b/src/sound_resid.cc new file mode 100644 index 000000000..8185b6046 --- /dev/null +++ b/src/sound_resid.cc @@ -0,0 +1,108 @@ +#include +#include +#include +#include +#include "resid-fp/sid.h" +#include "sound_resid.h" + +typedef struct psid_t +{ + /* resid sid implementation */ + SIDFP *sid; + int16_t last_sample; +} psid_t; + +psid_t *psid; + +void *sid_init() +{ +// psid_t *psid; + int c; + sampling_method method=SAMPLE_INTERPOLATE; + float cycles_per_sec = 14318180.0 / 16.0; + + psid = new psid_t; +// psid = (psid_t *)malloc(sizeof(sound_t)); + psid->sid = new SIDFP; + + psid->sid->set_chip_model(MOS8580FP); + + psid->sid->set_voice_nonlinearity(1.0f); + psid->sid->get_filter().set_distortion_properties(0.f, 0.f, 0.f); + psid->sid->get_filter().set_type4_properties(6.55f, 20.0f); + + psid->sid->enable_filter(true); + psid->sid->enable_external_filter(true); + + psid->sid->reset(); + + for (c=0;c<32;c++) + psid->sid->write(c,0); + + if (!psid->sid->set_sampling_parameters((float)cycles_per_sec, method, + (float)48000, 0.9*48000.0/2.0)) + { + // printf("reSID failed!\n"); + } + + psid->sid->set_chip_model(MOS6581FP); + psid->sid->set_voice_nonlinearity(0.96f); + psid->sid->get_filter().set_distortion_properties(3.7e-3f, 2048.f, 1.2e-4f); + + psid->sid->input(0); + psid->sid->get_filter().set_type3_properties(1.33e6f, 2.2e9f, 1.0056f, 7e3f); + + return (void *)psid; +} + +void sid_close(void *p) +{ +// psid_t *psid = (psid_t *)p; + delete psid->sid; +// free(psid); +} + +void sid_reset(void *p) +{ +// psid_t *psid = (psid_t *)p; + int c; + + psid->sid->reset(); + + for (c = 0; c < 32; c++) + psid->sid->write(c, 0); +} + + +uint8_t sid_read(uint16_t addr, void *p) +{ +// psid_t *psid = (psid_t *)p; + + return psid->sid->read(addr & 0x1f); +// return 0xFF; +} + +void sid_write(uint16_t addr, uint8_t val, void *p) +{ +// psid_t *psid = (psid_t *)p; + + psid->sid->write(addr & 0x1f,val); +} + +#define CLOCK_DELTA(n) (int)(((14318180.0 * n) / 16.0) / 48000.0) + +static void fillbuf2(int& count, int16_t *buf, int len) +{ + int c; + c = psid->sid->clock(count, buf, len, 1); + if (!c) + *buf = psid->last_sample; + psid->last_sample = *buf; +} +void sid_fillbuf(int16_t *buf, int len, void *p) +{ +// psid_t *psid = (psid_t *)p; + int x = CLOCK_DELTA(len); + + fillbuf2(x, buf, len); +} diff --git a/src/sound_resid.h b/src/sound_resid.h new file mode 100644 index 000000000..402ee0ceb --- /dev/null +++ b/src/sound_resid.h @@ -0,0 +1,12 @@ +#ifdef __cplusplus +extern "C" { +#endif + void *sid_init(); + void sid_close(void *p); + void sid_reset(void *p); + uint8_t sid_read(uint16_t addr, void *p); + void sid_write(uint16_t addr, uint8_t val, void *p); + void sid_fillbuf(int16_t *buf, int len, void *p); +#ifdef __cplusplus +} +#endif diff --git a/src/sound_sb.c b/src/sound_sb.c new file mode 100644 index 000000000..34ca8b4d7 --- /dev/null +++ b/src/sound_sb.c @@ -0,0 +1,840 @@ +#include +#include "ibm.h" +#include "device.h" +#include "sound_emu8k.h" +#include "sound_mpu401_uart.h" +#include "sound_opl.h" +#include "sound_sb.h" +#include "sound_sb_dsp.h" + +#include "filters.h" + +typedef struct sb_mixer_t +{ + int master_l, master_r; + int voice_l, voice_r; + int fm_l, fm_r; + int cd_l, cd_r; + int bass_l, bass_r; + int treble_l, treble_r; + int filter; + + int index; + uint8_t regs[256]; +} sb_mixer_t; + +typedef struct sb_t +{ + opl_t opl; + sb_dsp_t dsp; + sb_mixer_t mixer; + mpu401_uart_t mpu; + emu8k_t emu8k; + + int pos; +} sb_t; + +static int sb_att[]= +{ + 310,368,437,520,618,735,873,1038,1234,1467,1743,2072,2463,2927,3479, + 4134,4914,5840,6941,8250,9805,11653,13850,16461,19564,23252,27635,32845, + 39036,46395,55140,65535 +}; + +static void sb_get_buffer_opl2(int32_t *buffer, int len, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_mixer_t *mixer = &sb->mixer; + + int c; + + opl2_update2(&sb->opl); + sb_dsp_update(&sb->dsp); + for (c = 0; c < len * 2; c += 2) + { + int32_t out_l, out_r; + + out_l = ((sb->opl.buffer[c] * mixer->fm_l) >> 16); + out_r = ((sb->opl.buffer[c + 1] * mixer->fm_r) >> 16); + + if (sb->mixer.filter) + { + out_l += (int)(((sb_iir(0, (float)sb->dsp.buffer[c]) / 1.3) * mixer->voice_l) / 3) >> 16; + out_r += (int)(((sb_iir(1, (float)sb->dsp.buffer[c + 1]) / 1.3) * mixer->voice_r) / 3) >> 16; + } + else + { + out_l += ((int32_t)(sb->dsp.buffer[c] * mixer->voice_l) / 3) >> 16; + out_r += ((int32_t)(sb->dsp.buffer[c + 1] * mixer->voice_r) / 3) >> 16; + } + + out_l = (out_l * mixer->master_l) >> 16; + out_r = (out_r * mixer->master_r) >> 16; + + if (mixer->bass_l != 8 || mixer->bass_r != 8 || mixer->treble_l != 8 || mixer->treble_r != 8) + { + if (mixer->bass_l>8) out_l = (out_l + (((int16_t) low_iir(0, (float)out_l) * (mixer->bass_l - 8)) >> 1)) * ((15 - mixer->bass_l) + 16) >> 5; + if (mixer->bass_r>8) out_r = (out_r + (((int16_t) low_iir(1, (float)out_r) * (mixer->bass_r - 8)) >> 1)) * ((15 - mixer->bass_r) + 16) >> 5; + if (mixer->treble_l>8) out_l = (out_l + (((int16_t) high_iir(0, (float)out_l) * (mixer->treble_l - 8)) >> 1)) * ((15 - mixer->treble_l) + 16) >> 5; + if (mixer->treble_r>8) out_r = (out_r + (((int16_t) high_iir(1, (float)out_r) * (mixer->treble_r - 8)) >> 1)) * ((15 - mixer->treble_r) + 16) >> 5; + if (mixer->bass_l<8) out_l = (out_l + (((int16_t) low_cut_iir(0, (float)out_l) * (8 - mixer->bass_l)) >> 1)) * (mixer->bass_l + 16) >> 5; + if (mixer->bass_r<8) out_r = (out_r + (((int16_t) low_cut_iir(1, (float)out_r) * (8 - mixer->bass_r)) >> 1)) * (mixer->bass_r + 16) >> 5; + if (mixer->treble_l<8) out_l = (out_l + (((int16_t)high_cut_iir(0, (float)out_l) * (8 - mixer->treble_l)) >> 1)) * (mixer->treble_l + 16) >> 5; + if (mixer->treble_r<8) out_r = (out_r + (((int16_t)high_cut_iir(1, (float)out_r) * (8 - mixer->treble_r)) >> 1)) * (mixer->treble_r + 16) >> 5; + } + + buffer[c] += out_l; + buffer[c + 1] += out_r; + } + + sb->pos = 0; + sb->opl.pos = 0; + sb->dsp.pos = 0; +} + +static void sb_get_buffer_opl3(int32_t *buffer, int len, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_mixer_t *mixer = &sb->mixer; + + int c; + + opl3_update2(&sb->opl); + sb_dsp_update(&sb->dsp); + for (c = 0; c < len * 2; c += 2) + { + int c_emu8k = (((c/2) * 44100) / 48000)*2; + int32_t out_l, out_r; + + out_l = ((sb->opl.buffer[c] * mixer->fm_l) >> 16); + out_r = ((sb->opl.buffer[c + 1] * mixer->fm_r) >> 16); + + if (sb->mixer.filter) + { + out_l += (int)(((sb_iir(0, (float)sb->dsp.buffer[c]) / 1.3) * mixer->voice_l) / 3) >> 16; + out_r += (int)(((sb_iir(1, (float)sb->dsp.buffer[c + 1]) / 1.3) * mixer->voice_r) / 3) >> 16; + } + else + { + out_l += ((int32_t)(sb->dsp.buffer[c] * mixer->voice_l) / 3) >> 16; + out_r += ((int32_t)(sb->dsp.buffer[c + 1] * mixer->voice_r) / 3) >> 16; + } + + out_l = (out_l * mixer->master_l) >> 16; + out_r = (out_r * mixer->master_r) >> 16; + + if (mixer->bass_l != 8 || mixer->bass_r != 8 || mixer->treble_l != 8 || mixer->treble_r != 8) + { + if (mixer->bass_l>8) out_l = (out_l + (((int16_t) low_iir(0, (float)out_l) * (mixer->bass_l - 8)) >> 1)) * ((15 - mixer->bass_l) + 16) >> 5; + if (mixer->bass_r>8) out_r = (out_r + (((int16_t) low_iir(1, (float)out_r) * (mixer->bass_r - 8)) >> 1)) * ((15 - mixer->bass_r) + 16) >> 5; + if (mixer->treble_l>8) out_l = (out_l + (((int16_t) high_iir(0, (float)out_l) * (mixer->treble_l - 8)) >> 1)) * ((15 - mixer->treble_l) + 16) >> 5; + if (mixer->treble_r>8) out_r = (out_r + (((int16_t) high_iir(1, (float)out_r) * (mixer->treble_r - 8)) >> 1)) * ((15 - mixer->treble_r) + 16) >> 5; + if (mixer->bass_l<8) out_l = (out_l + (((int16_t) low_cut_iir(0, (float)out_l) * (8 - mixer->bass_l)) >> 1)) * (mixer->bass_l + 16) >> 5; + if (mixer->bass_r<8) out_r = (out_r + (((int16_t) low_cut_iir(1, (float)out_r) * (8 - mixer->bass_r)) >> 1)) * (mixer->bass_r + 16) >> 5; + if (mixer->treble_l<8) out_l = (out_l + (((int16_t)high_cut_iir(0, (float)out_l) * (8 - mixer->treble_l)) >> 1)) * (mixer->treble_l + 16) >> 5; + if (mixer->treble_r<8) out_r = (out_r + (((int16_t)high_cut_iir(1, (float)out_r) * (8 - mixer->treble_r)) >> 1)) * (mixer->treble_r + 16) >> 5; + } + + buffer[c] += out_l; + buffer[c + 1] += out_r; + } + + sb->pos = 0; + sb->opl.pos = 0; + sb->dsp.pos = 0; + sb->emu8k.pos = 0; +} + +static void sb_get_buffer_emu8k(int32_t *buffer, int len, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_mixer_t *mixer = &sb->mixer; + + int c; + + opl3_update2(&sb->opl); + sb_dsp_update(&sb->dsp); + emu8k_update(&sb->emu8k); + for (c = 0; c < len * 2; c += 2) + { + int c_emu8k = (((c/2) * 44100) / 48000)*2; + int32_t out_l, out_r; + + out_l = (((int32_t)sb->opl.buffer[c] * (int32_t)mixer->fm_l) >> 16); + out_r = (((int32_t)sb->opl.buffer[c + 1] * (int32_t)mixer->fm_r) >> 16); + + out_l += ((sb->emu8k.buffer[c_emu8k] * mixer->fm_l) >> 16); + out_r += ((sb->emu8k.buffer[c_emu8k + 1] * mixer->fm_l) >> 16); + + if (sb->mixer.filter) + { + out_l += (int)(((sb_iir(0, (float)sb->dsp.buffer[c]) / 1.3) * mixer->voice_l) / 3) >> 16; + out_r += (int)(((sb_iir(1, (float)sb->dsp.buffer[c + 1]) / 1.3) * mixer->voice_r) / 3) >> 16; + } + else + { + out_l += ((int32_t)(sb->dsp.buffer[c] * mixer->voice_l) / 3) >> 16; + out_r += ((int32_t)(sb->dsp.buffer[c + 1] * mixer->voice_r) / 3) >> 16; + } + + out_l = (out_l * mixer->master_l) >> 16; + out_r = (out_r * mixer->master_r) >> 16; + + if (mixer->bass_l != 8 || mixer->bass_r != 8 || mixer->treble_l != 8 || mixer->treble_r != 8) + { + if (mixer->bass_l>8) out_l = (out_l + (((int16_t) low_iir(0, (float)out_l) * (mixer->bass_l - 8)) >> 1)) * ((15 - mixer->bass_l) + 16) >> 5; + if (mixer->bass_r>8) out_r = (out_r + (((int16_t) low_iir(1, (float)out_r) * (mixer->bass_r - 8)) >> 1)) * ((15 - mixer->bass_r) + 16) >> 5; + if (mixer->treble_l>8) out_l = (out_l + (((int16_t) high_iir(0, (float)out_l) * (mixer->treble_l - 8)) >> 1)) * ((15 - mixer->treble_l) + 16) >> 5; + if (mixer->treble_r>8) out_r = (out_r + (((int16_t) high_iir(1, (float)out_r) * (mixer->treble_r - 8)) >> 1)) * ((15 - mixer->treble_r) + 16) >> 5; + if (mixer->bass_l<8) out_l = (out_l + (((int16_t) low_cut_iir(0, (float)out_l) * (8 - mixer->bass_l)) >> 1)) * (mixer->bass_l + 16) >> 5; + if (mixer->bass_r<8) out_r = (out_r + (((int16_t) low_cut_iir(1, (float)out_r) * (8 - mixer->bass_r)) >> 1)) * (mixer->bass_r + 16) >> 5; + if (mixer->treble_l<8) out_l = (out_l + (((int16_t)high_cut_iir(0, (float)out_l) * (8 - mixer->treble_l)) >> 1)) * (mixer->treble_l + 16) >> 5; + if (mixer->treble_r<8) out_r = (out_r + (((int16_t)high_cut_iir(1, (float)out_r) * (8 - mixer->treble_r)) >> 1)) * (mixer->treble_r + 16) >> 5; + } + + buffer[c] += out_l; + buffer[c + 1] += out_r; + } + + sb->pos = 0; + sb->opl.pos = 0; + sb->dsp.pos = 0; + sb->emu8k.pos = 0; +} + +void sb_pro_mixer_write(uint16_t addr, uint8_t val, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_mixer_t *mixer = &sb->mixer; + + if (!(addr & 1)) + mixer->index = val & 0xff; + else + { + mixer->regs[mixer->index] = val; + + mixer->master_l = sb_att[(mixer->regs[0x22] >> 4) | 0x11]; + mixer->master_r = sb_att[(mixer->regs[0x22] & 0xf) | 0x11]; + mixer->voice_l = sb_att[(mixer->regs[0x04] >> 4) | 0x11]; + mixer->voice_r = sb_att[(mixer->regs[0x04] & 0xf) | 0x11]; + mixer->fm_l = sb_att[(mixer->regs[0x26] >> 4) | 0x11]; + mixer->fm_r = sb_att[(mixer->regs[0x26] & 0xf) | 0x11]; + mixer->cd_l = sb_att[(mixer->regs[0x28] >> 4) | 0x11]; + mixer->cd_r = sb_att[(mixer->regs[0x28] & 0xf) | 0x11]; + mixer->filter = !(mixer->regs[0xe] & 0x20); + mixer->bass_l = mixer->bass_r = 8; + mixer->treble_l = mixer->treble_r = 8; + sound_set_cd_volume(((uint32_t)mixer->master_l * (uint32_t)mixer->cd_l) / 65535, + ((uint32_t)mixer->master_r * (uint32_t)mixer->cd_r) / 65535); +// pclog("%02X %02X %02X\n", mixer->regs[0x04], mixer->regs[0x22], mixer->regs[0x26]); +// pclog("Mixer - %04X %04X %04X %04X %04X %04X\n", mixer->master_l, mixer->master_r, mixer->voice_l, mixer->voice_r, mixer->fm_l, mixer->fm_r); + if (mixer->index == 0xe) + sb_dsp_set_stereo(&sb->dsp, val & 2); + } +} + +uint8_t sb_pro_mixer_read(uint16_t addr, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_mixer_t *mixer = &sb->mixer; + + if (!(addr & 1)) + return mixer->index; + + return mixer->regs[mixer->index]; +} + +void sb_16_mixer_write(uint16_t addr, uint8_t val, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_mixer_t *mixer = &sb->mixer; + + if (!(addr & 1)) + mixer->index = val; + else + { + mixer->regs[mixer->index] = val; + switch (mixer->index) + { + case 0x22: + mixer->regs[0x30] = ((mixer->regs[0x22] >> 4) | 0x11) << 3; + mixer->regs[0x31] = ((mixer->regs[0x22] & 0xf) | 0x11) << 3; + break; + case 0x04: + mixer->regs[0x32] = ((mixer->regs[0x04] >> 4) | 0x11) << 3; + mixer->regs[0x33] = ((mixer->regs[0x04] & 0xf) | 0x11) << 3; + break; + case 0x26: + mixer->regs[0x34] = ((mixer->regs[0x26] >> 4) | 0x11) << 3; + mixer->regs[0x35] = ((mixer->regs[0x26] & 0xf) | 0x11) << 3; + break; + case 0x28: + mixer->regs[0x36] = ((mixer->regs[0x28] >> 4) | 0x11) << 3; + mixer->regs[0x37] = ((mixer->regs[0x28] & 0xf) | 0x11) << 3; + break; + case 0x80: + if (val & 1) sb->dsp.sb_irqnum = 2; + if (val & 2) sb->dsp.sb_irqnum = 5; + if (val & 4) sb->dsp.sb_irqnum = 7; + if (val & 8) sb->dsp.sb_irqnum = 10; + break; + } + mixer->master_l = sb_att[mixer->regs[0x30] >> 3]; + mixer->master_r = sb_att[mixer->regs[0x31] >> 3]; + mixer->voice_l = sb_att[mixer->regs[0x32] >> 3]; + mixer->voice_r = sb_att[mixer->regs[0x33] >> 3]; + mixer->fm_l = sb_att[mixer->regs[0x34] >> 3]; + mixer->fm_r = sb_att[mixer->regs[0x35] >> 3]; + mixer->cd_l = sb_att[mixer->regs[0x36] >> 3]; + mixer->cd_r = sb_att[mixer->regs[0x37] >> 3]; + mixer->bass_l = mixer->regs[0x46] >> 4; + mixer->bass_r = mixer->regs[0x47] >> 4; + mixer->treble_l = mixer->regs[0x44] >> 4; + mixer->treble_r = mixer->regs[0x45] >> 4; + mixer->filter = 0; + sound_set_cd_volume(((uint32_t)mixer->master_l * (uint32_t)mixer->cd_l) / 65535, + ((uint32_t)mixer->master_r * (uint32_t)mixer->cd_r) / 65535); +// pclog("%02X %02X %02X %02X %02X %02X\n", mixer->regs[0x30], mixer->regs[0x31], mixer->regs[0x32], mixer->regs[0x33], mixer->regs[0x34], mixer->regs[0x35]); +// pclog("Mixer - %04X %04X %04X %04X %04X %04X\n", mixer->master_l, mixer->master_r, mixer->voice_l, mixer->voice_r, mixer->fm_l, mixer->fm_r); + } +} + +uint8_t sb_16_mixer_read(uint16_t addr, void *p) +{ + sb_t *sb = (sb_t *)p; + sb_mixer_t *mixer = &sb->mixer; + + if (!(addr & 1)) + return mixer->index; + + switch (mixer->index) + { + case 0x80: + switch (sb->dsp.sb_irqnum) + { + case 2: return 1; /*IRQ 7*/ + case 5: return 2; /*IRQ 7*/ + case 7: return 4; /*IRQ 7*/ + case 10: return 8; /*IRQ 7*/ + } + break; + case 0x81: + return 0x22; /*DMA 1 and 5*/ + case 0x82: + return ((sb->dsp.sb_irq8) ? 1 : 0) | ((sb->dsp.sb_irq16) ? 2 : 0); + } + return mixer->regs[mixer->index]; +} + +void sb_mixer_init(sb_mixer_t *mixer) +{ + mixer->master_l = mixer->master_r = 65535; + mixer->voice_l = mixer->voice_r = 65535; + mixer->fm_l = mixer->fm_r = 65535; + mixer->bass_l = mixer->bass_r = 8; + mixer->treble_l = mixer->treble_r = 8; + mixer->filter = 1; +} + +void *sb_1_init() +{ + sb_t *sb = malloc(sizeof(sb_t)); + uint16_t addr = device_get_config_int("addr"); + memset(sb, 0, sizeof(sb_t)); + + opl2_init(&sb->opl); + sb_dsp_init(&sb->dsp, SB1); + sb_dsp_setaddr(&sb->dsp, addr); + sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); + sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); + sb_mixer_init(&sb->mixer); + io_sethandler(addr+8, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + sound_add_handler(sb_get_buffer_opl2, sb); + return sb; +} +void *sb_15_init() +{ + sb_t *sb = malloc(sizeof(sb_t)); + uint16_t addr = device_get_config_int("addr"); + memset(sb, 0, sizeof(sb_t)); + + opl2_init(&sb->opl); + sb_dsp_init(&sb->dsp, SB15); + sb_dsp_setaddr(&sb->dsp, addr); + sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); + sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); + sb_mixer_init(&sb->mixer); + io_sethandler(addr+8, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + sound_add_handler(sb_get_buffer_opl2, sb); + return sb; +} +void *sb_2_init() +{ + sb_t *sb = malloc(sizeof(sb_t)); + uint16_t addr = device_get_config_int("addr"); + memset(sb, 0, sizeof(sb_t)); + + opl2_init(&sb->opl); + sb_dsp_init(&sb->dsp, SB2); + sb_dsp_setaddr(&sb->dsp, addr); + sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); + sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); + sb_mixer_init(&sb->mixer); + io_sethandler(addr+8, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + sound_add_handler(sb_get_buffer_opl2, sb); + return sb; +} + +void *sb_pro_v1_init() +{ + sb_t *sb = malloc(sizeof(sb_t)); + uint16_t addr = device_get_config_int("addr"); + memset(sb, 0, sizeof(sb_t)); + + opl2_init(&sb->opl); + sb_dsp_init(&sb->dsp, SBPRO); + sb_dsp_setaddr(&sb->dsp, addr); + sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); + sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); + sb_mixer_init(&sb->mixer); + io_sethandler(addr+0, 0x0002, opl2_l_read, NULL, NULL, opl2_l_write, NULL, NULL, &sb->opl); + io_sethandler(addr+2, 0x0002, opl2_r_read, NULL, NULL, opl2_r_write, NULL, NULL, &sb->opl); + io_sethandler(addr+8, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0002, opl2_read, NULL, NULL, opl2_write, NULL, NULL, &sb->opl); + io_sethandler(addr+4, 0x0002, sb_pro_mixer_read, NULL, NULL, sb_pro_mixer_write, NULL, NULL, sb); + sound_add_handler(sb_get_buffer_opl2, sb); + + sb->mixer.regs[0x22] = 0xff; + sb->mixer.regs[0x04] = 0xff; + sb->mixer.regs[0x26] = 0xff; + sb->mixer.regs[0xe] = 0; + + return sb; +} + +void *sb_pro_v2_init() +{ + sb_t *sb = malloc(sizeof(sb_t)); + uint16_t addr = device_get_config_int("addr"); + memset(sb, 0, sizeof(sb_t)); + + opl3_init(&sb->opl); + sb_dsp_init(&sb->dsp, SBPRO2); + sb_dsp_setaddr(&sb->dsp, addr); + sb_dsp_setirq(&sb->dsp, device_get_config_int("irq")); + sb_dsp_setdma8(&sb->dsp, device_get_config_int("dma")); + sb_mixer_init(&sb->mixer); + io_sethandler(addr+0, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(addr+8, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(addr+4, 0x0002, sb_pro_mixer_read, NULL, NULL, sb_pro_mixer_write, NULL, NULL, sb); + sound_add_handler(sb_get_buffer_opl3, sb); + + sb->mixer.regs[0x22] = 0xff; + sb->mixer.regs[0x04] = 0xff; + sb->mixer.regs[0x26] = 0xff; + sb->mixer.regs[0xe] = 0; + + return sb; +} + +void *sb_16_init() +{ + sb_t *sb = malloc(sizeof(sb_t)); + memset(sb, 0, sizeof(sb_t)); + + opl3_init(&sb->opl); + sb_dsp_init(&sb->dsp, SB16); + sb_dsp_setaddr(&sb->dsp, 0x0220); + sb_mixer_init(&sb->mixer); + io_sethandler(0x0220, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(0x0228, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(0x0224, 0x0002, sb_16_mixer_read, NULL, NULL, sb_16_mixer_write, NULL, NULL, sb); + sound_add_handler(sb_get_buffer_opl3, sb); + mpu401_uart_init(&sb->mpu, 0x330); + + sb->mixer.regs[0x30] = 31 << 3; + sb->mixer.regs[0x31] = 31 << 3; + sb->mixer.regs[0x32] = 31 << 3; + sb->mixer.regs[0x33] = 31 << 3; + sb->mixer.regs[0x34] = 31 << 3; + sb->mixer.regs[0x35] = 31 << 3; + sb->mixer.regs[0x44] = 8 << 4; + sb->mixer.regs[0x45] = 8 << 4; + sb->mixer.regs[0x46] = 8 << 4; + sb->mixer.regs[0x47] = 8 << 4; + sb->mixer.regs[0x22] = (sb->mixer.regs[0x30] & 0xf0) | (sb->mixer.regs[0x31] >> 4); + sb->mixer.regs[0x04] = (sb->mixer.regs[0x32] & 0xf0) | (sb->mixer.regs[0x33] >> 4); + sb->mixer.regs[0x26] = (sb->mixer.regs[0x34] & 0xf0) | (sb->mixer.regs[0x35] >> 4); + + return sb; +} + +int sb_awe32_available() +{ + return rom_present("roms/awe32.raw"); +} + +void *sb_awe32_init() +{ + sb_t *sb = malloc(sizeof(sb_t)); + int onboard_ram = device_get_config_int("onboard_ram"); + memset(sb, 0, sizeof(sb_t)); + + opl3_init(&sb->opl); + sb_dsp_init(&sb->dsp, SB16 + 1); + sb_dsp_setaddr(&sb->dsp, 0x0220); + sb_mixer_init(&sb->mixer); + io_sethandler(0x0220, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(0x0228, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(0x0388, 0x0002, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &sb->opl); + io_sethandler(0x0224, 0x0002, sb_16_mixer_read, NULL, NULL, sb_16_mixer_write, NULL, NULL, sb); + sound_add_handler(sb_get_buffer_emu8k, sb); + mpu401_uart_init(&sb->mpu, 0x330); + emu8k_init(&sb->emu8k, onboard_ram); + + sb->mixer.regs[0x30] = 31 << 3; + sb->mixer.regs[0x31] = 31 << 3; + sb->mixer.regs[0x32] = 31 << 3; + sb->mixer.regs[0x33] = 31 << 3; + sb->mixer.regs[0x34] = 31 << 3; + sb->mixer.regs[0x35] = 31 << 3; + sb->mixer.regs[0x44] = 8 << 4; + sb->mixer.regs[0x45] = 8 << 4; + sb->mixer.regs[0x46] = 8 << 4; + sb->mixer.regs[0x47] = 8 << 4; + sb->mixer.regs[0x22] = (sb->mixer.regs[0x30] & 0xf0) | (sb->mixer.regs[0x31] >> 4); + sb->mixer.regs[0x04] = (sb->mixer.regs[0x32] & 0xf0) | (sb->mixer.regs[0x33] >> 4); + sb->mixer.regs[0x26] = (sb->mixer.regs[0x34] & 0xf0) | (sb->mixer.regs[0x35] >> 4); + + return sb; +} + +void sb_close(void *p) +{ + sb_t *sb = (sb_t *)p; + + free(sb); +} + +void sb_awe32_close(void *p) +{ + sb_t *sb = (sb_t *)p; + + emu8k_close(&sb->emu8k); + + free(sb); +} + +void sb_speed_changed(void *p) +{ + sb_t *sb = (sb_t *)p; + + sb_dsp_speed_changed(&sb->dsp); +} + +void sb_add_status_info(char *s, int max_len, void *p) +{ + sb_t *sb = (sb_t *)p; + + sb_dsp_add_status_info(s, max_len, &sb->dsp); +} + +static device_config_t sb_config[] = +{ + { + .name = "addr", + .description = "Address", + .type = CONFIG_BINARY, + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "0x220", + .value = 0x220 + }, + { + .description = "0x240", + .value = 0x240 + }, + { + .description = "" + } + }, + .default_int = 0x220 + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "IRQ 2", + .value = 2 + }, + { + .description = "IRQ 3", + .value = 3 + }, + { + .description = "IRQ 5", + .value = 5 + }, + { + .description = "IRQ 7", + .value = 7 + }, + { + .description = "" + } + }, + .default_int = 7 + }, + { + .name = "dma", + .description = "DMA", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "DMA 1", + .value = 1 + }, + { + .description = "DMA 3", + .value = 3 + }, + { + .description = "" + } + }, + .default_int = 1 + }, + { + .type = -1 + } +}; + +static device_config_t sb_pro_config[] = +{ + { + .name = "addr", + .description = "Address", + .type = CONFIG_BINARY, + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "0x220", + .value = 0x220 + }, + { + .description = "0x240", + .value = 0x240 + }, + { + .description = "" + } + }, + .default_int = 0x220 + }, + { + .name = "irq", + .description = "IRQ", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "IRQ 2", + .value = 2 + }, + { + .description = "IRQ 5", + .value = 5 + }, + { + .description = "IRQ 7", + .value = 7 + }, + { + .description = "IRQ 10", + .value = 10 + }, + { + .description = "" + } + }, + .default_int = 7 + }, + { + .name = "dma", + .description = "DMA", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "DMA 1", + .value = 1 + }, + { + .description = "DMA 3", + .value = 3 + }, + { + .description = "" + } + }, + .default_int = 1 + }, + { + .type = -1 + } +}; + +static device_config_t sb_16_config[] = +{ + { + .name = "midi", + .description = "MIDI out device", + .type = CONFIG_MIDI, + .default_int = 0 + }, + { + .type = -1 + } +}; + +static device_config_t sb_awe32_config[] = +{ + { + .name = "midi", + .description = "MIDI out device", + .type = CONFIG_MIDI, + .default_int = 0 + }, + { + .name = "onboard_ram", + .description = "Onboard RAM", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "None", + .value = 0 + }, + { + .description = "512 KB", + .value = 512 + }, + { + .description = "2 MB", + .value = 2048 + }, + { + .description = "8 MB", + .value = 8192 + }, + { + .description = "28 MB", + .value = 28*1024 + }, + { + .description = "" + } + }, + .default_int = 512 + }, + { + .type = -1 + } +}; + +device_t sb_1_device = +{ + "Sound Blaster v1.0", + 0, + sb_1_init, + sb_close, + NULL, + sb_speed_changed, + NULL, + sb_add_status_info, + sb_config +}; +device_t sb_15_device = +{ + "Sound Blaster v1.5", + 0, + sb_15_init, + sb_close, + NULL, + sb_speed_changed, + NULL, + sb_add_status_info, + sb_config +}; +device_t sb_2_device = +{ + "Sound Blaster v2.0", + 0, + sb_2_init, + sb_close, + NULL, + sb_speed_changed, + NULL, + sb_add_status_info, + sb_config +}; +device_t sb_pro_v1_device = +{ + "Sound Blaster Pro v1", + 0, + sb_pro_v1_init, + sb_close, + NULL, + sb_speed_changed, + NULL, + sb_add_status_info, + sb_pro_config +}; +device_t sb_pro_v2_device = +{ + "Sound Blaster Pro v2", + 0, + sb_pro_v2_init, + sb_close, + NULL, + sb_speed_changed, + NULL, + sb_add_status_info, + sb_pro_config +}; +device_t sb_16_device = +{ + "Sound Blaster 16", + 0, + sb_16_init, + sb_close, + NULL, + sb_speed_changed, + NULL, + sb_add_status_info, + sb_16_config +}; +device_t sb_awe32_device = +{ + "Sound Blaster AWE32", + 0, + sb_awe32_init, + sb_close, + sb_awe32_available, + sb_speed_changed, + NULL, + sb_add_status_info, + sb_awe32_config +}; diff --git a/src/sound_sb.h b/src/sound_sb.h new file mode 100644 index 000000000..81130fecd --- /dev/null +++ b/src/sound_sb.h @@ -0,0 +1,7 @@ +extern device_t sb_1_device; +extern device_t sb_15_device; +extern device_t sb_2_device; +extern device_t sb_pro_v1_device; +extern device_t sb_pro_v2_device; +extern device_t sb_16_device; +extern device_t sb_awe32_device; diff --git a/src/sound_sb_dsp.c b/src/sound_sb_dsp.c new file mode 100644 index 000000000..dc4013c1c --- /dev/null +++ b/src/sound_sb_dsp.c @@ -0,0 +1,1013 @@ +/*Jazz sample rates : + 386-33 - 12kHz + 486-33 - 20kHz + 486-50 - 32kHz + Pentium - 45kHz*/ + +#include +#include +#include "ibm.h" + + +#include "dma.h" +#include "io.h" +#include "pic.h" +#include "sound.h" +#include "sound_sb_dsp.h" +#include "timer.h" + +void pollsb(void *p); +void sb_poll_i(void *p); + + + +static int sbe2dat[4][9] = { + { 0x01, -0x02, -0x04, 0x08, -0x10, 0x20, 0x40, -0x80, -106 }, + { -0x01, 0x02, -0x04, 0x08, 0x10, -0x20, 0x40, -0x80, 165 }, + { -0x01, 0x02, 0x04, -0x08, 0x10, -0x20, -0x40, 0x80, -151 }, + { 0x01, -0x02, 0x04, -0x08, -0x10, 0x20, -0x40, 0x80, 90 } +}; + +static int sb_commands[256]= +{ + -1, 2,-1,-1, 1, 2,-1, 0, 1,-1,-1,-1,-1,-1, 2, 1, + 1,-1,-1,-1, 2,-1, 2, 2,-1,-1,-1,-1, 0,-1,-1, 0, + 0,-1,-1,-1, 2,-1,-1,-1,-1,-1,-1,-1, 0,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 1, 2, 2,-1,-1,-1,-1,-1, 2,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1, 2, 2, 2, 2,-1,-1,-1,-1,-1, 0,-1, 0, + 2, 2,-1,-1,-1,-1,-1,-1, 2, 2,-1,-1,-1,-1,-1,-1, + 0,-1,-1,-1,-1,-1,-1,-1, 0,-1,-1,-1,-1,-1,-1,-1, + -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 0, 0,-1, 0, 0, 0, 0,-1, 0, 0, 0,-1,-1,-1,-1,-1, + 1, 0, 1, 0, 1,-1,-1, 0, 0,-1,-1,-1,-1,-1,-1,-1, + -1,-1, 0,-1,-1,-1,-1,-1,-1, 1, 2,-1,-1,-1,-1, 0 +}; + +char sb16_copyright[] = "COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992."; +uint16_t sb_dsp_versions[] = {0, 0, 0x105, 0x200, 0x201, 0x300, 0x302, 0x405, 0x40d}; + +/*These tables were 'borrowed' from DOSBox*/ + int8_t scaleMap4[64] = { + 0, 1, 2, 3, 4, 5, 6, 7, 0, -1, -2, -3, -4, -5, -6, -7, + 1, 3, 5, 7, 9, 11, 13, 15, -1, -3, -5, -7, -9, -11, -13, -15, + 2, 6, 10, 14, 18, 22, 26, 30, -2, -6, -10, -14, -18, -22, -26, -30, + 4, 12, 20, 28, 36, 44, 52, 60, -4, -12, -20, -28, -36, -44, -52, -60 + }; + uint8_t adjustMap4[64] = { + 0, 0, 0, 0, 0, 16, 16, 16, + 0, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 16, 16, 16, + 240, 0, 0, 0, 0, 0, 0, 0, + 240, 0, 0, 0, 0, 0, 0, 0 + }; + + int8_t scaleMap26[40] = { + 0, 1, 2, 3, 0, -1, -2, -3, + 1, 3, 5, 7, -1, -3, -5, -7, + 2, 6, 10, 14, -2, -6, -10, -14, + 4, 12, 20, 28, -4, -12, -20, -28, + 5, 15, 25, 35, -5, -15, -25, -35 + }; + uint8_t adjustMap26[40] = { + 0, 0, 0, 8, 0, 0, 0, 8, + 248, 0, 0, 8, 248, 0, 0, 8, + 248, 0, 0, 8, 248, 0, 0, 8, + 248, 0, 0, 8, 248, 0, 0, 8, + 248, 0, 0, 0, 248, 0, 0, 0 + }; + + int8_t scaleMap2[24] = { + 0, 1, 0, -1, 1, 3, -1, -3, + 2, 6, -2, -6, 4, 12, -4, -12, + 8, 24, -8, -24, 6, 48, -16, -48 + }; + uint8_t adjustMap2[24] = { + 0, 4, 0, 4, + 252, 4, 252, 4, 252, 4, 252, 4, + 252, 4, 252, 4, 252, 4, 252, 4, + 252, 0, 252, 0 + }; + + + +void sb_irq(sb_dsp_t *dsp, int irq8) +{ +// pclog("IRQ %i %02X\n",irq8,pic.mask); + if (irq8) dsp->sb_irq8 = 1; + else dsp->sb_irq16 = 1; + picint(1 << dsp->sb_irqnum); +} +void sb_irqc(sb_dsp_t *dsp, int irq8) +{ + if (irq8) dsp->sb_irq8 = 0; + else dsp->sb_irq16 = 0; + picintc(1 << dsp->sb_irqnum); +} + +void sb_dsp_reset(sb_dsp_t *dsp) +{ + dsp->sbenable = dsp->sb_enable_i = 0; + dsp->sb_command = 0; + + dsp->sb_8_length = 0xffff; + dsp->sb_8_autolen = 0xffff; + + sb_irqc(dsp, 0); + sb_irqc(dsp, 1); + dsp->sb_16_pause = 0; + dsp->sb_read_wp = dsp->sb_read_rp = 0; + dsp->sb_data_stat = -1; + dsp->sb_speaker = 0; + dsp->sb_pausetime = -1; + dsp->sbe2 = 0xAA; + dsp->sbe2count = 0; + + dsp->sbreset = 0; + dsp->sbenable = dsp->sb_enable_i = dsp->sb_count_i = 0; + + picintc(1 << dsp->sb_irqnum); + + dsp->asp_data_len = 0; +} + +void sb_doreset(sb_dsp_t *dsp) +{ + int c; + + sb_dsp_reset(dsp); + + if (dsp->sb_type==SB16) sb_commands[8] = 1; + else sb_commands[8] = -1; + + for (c = 0; c < 256; c++) + dsp->sb_asp_regs[c] = 0; + dsp->sb_asp_regs[5] = 0x01; + dsp->sb_asp_regs[9] = 0xf8; +} + +void sb_dsp_speed_changed(sb_dsp_t *dsp) +{ + if (dsp->sb_timeo < 256) + dsp->sblatcho = TIMER_USEC * (256 - dsp->sb_timeo); + else + dsp->sblatcho = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timeo - 256))); + + if (dsp->sb_timei < 256) + dsp->sblatchi = TIMER_USEC * (256 - dsp->sb_timei); + else + dsp->sblatchi = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_timei - 256))); +} + +void sb_add_data(sb_dsp_t *dsp, uint8_t v) +{ + dsp->sb_read_data[dsp->sb_read_wp++] = v; + dsp->sb_read_wp &= 0xff; +} + +#define ADPCM_4 1 +#define ADPCM_26 2 +#define ADPCM_2 3 + +void sb_start_dma(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len) +{ + dsp->sb_pausetime = -1; + if (dma8) + { + dsp->sb_8_length = len; + dsp->sb_8_format = format; + dsp->sb_8_autoinit = autoinit; + dsp->sb_8_pause = 0; + dsp->sb_8_enable = 1; + if (dsp->sb_16_enable && dsp->sb_16_output) dsp->sb_16_enable = 0; + dsp->sb_8_output = 1; + timer_process(); + dsp->sbenable = dsp->sb_8_enable; + timer_update_outstanding(); + dsp->sbleftright = 0; + dsp->sbdacpos = 0; +// pclog("Start 8-bit DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len); + } + else + { + dsp->sb_16_length = len; + dsp->sb_16_format = format; + dsp->sb_16_autoinit = autoinit; + dsp->sb_16_pause = 0; + dsp->sb_16_enable = 1; + if (dsp->sb_8_enable && dsp->sb_8_output) dsp->sb_8_enable = 0; + dsp->sb_16_output = 1; + timer_process(); + dsp->sbenable = dsp->sb_16_enable; + timer_update_outstanding(); +// pclog("Start 16-bit DMA addr %06X len %04X\n",dma16.ac[1]+(dma16.page[1]<<16),len); + } +} + +void sb_start_dma_i(sb_dsp_t *dsp, int dma8, int autoinit, uint8_t format, int len) +{ + if (dma8) + { + dsp->sb_8_length = len; + dsp->sb_8_format = format; + dsp->sb_8_autoinit = autoinit; + dsp->sb_8_pause = 0; + dsp->sb_8_enable = 1; + if (dsp->sb_16_enable && !dsp->sb_16_output) dsp->sb_16_enable = 0; + dsp->sb_8_output = 0; + timer_process(); + dsp->sb_enable_i = dsp->sb_8_enable; + timer_update_outstanding(); +// pclog("Start 8-bit input DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len); + } + else + { + dsp->sb_16_length = len; + dsp->sb_16_format = format; + dsp->sb_16_autoinit = autoinit; + dsp->sb_16_pause = 0; + dsp->sb_16_enable = 1; + if (dsp->sb_8_enable && !dsp->sb_8_output) dsp->sb_8_enable = 0; + dsp->sb_16_output = 0; + timer_process(); + dsp->sb_enable_i = dsp->sb_16_enable; + timer_update_outstanding(); +// pclog("Start 16-bit input DMA addr %06X len %04X\n",dma.ac[1]+(dma.page[1]<<16),len); + } +} + +int sb_8_read_dma(sb_dsp_t *dsp) +{ + return dma_channel_read(dsp->sb_8_dmanum); +} +void sb_8_write_dma(sb_dsp_t *dsp, uint8_t val) +{ + dma_channel_write(dsp->sb_8_dmanum, val); +} +uint16_t sb_16_read_dma(sb_dsp_t *dsp) +{ + return dma_channel_read(5); +} +void sb_16_write_dma(sb_dsp_t *dsp, uint16_t val) +{ + dma_channel_write(5, val); +} + +void sb_dsp_setirq(sb_dsp_t *dsp, int irq) +{ + dsp->sb_irqnum = irq; +} + +void sb_dsp_setdma8(sb_dsp_t *dsp, int dma) +{ + dsp->sb_8_dmanum = dma; +} + +void sb_exec_command(sb_dsp_t *dsp) +{ + int temp,c; +// pclog("sb_exec_command : SB command %02X\n", dsp->sb_command); + switch (dsp->sb_command) + { + case 0x01: /*???*/ + if (dsp->sb_type < SB16) break; + dsp->asp_data_len = dsp->sb_data[0] + (dsp->sb_data[1] << 8) + 1; + break; + case 0x03: /*ASP status*/ + sb_add_data(dsp, 0); + break; + case 0x10: /*8-bit direct mode*/ + sb_dsp_update(dsp); + dsp->sbdat = dsp->sbdatl = dsp->sbdatr = (dsp->sb_data[0] ^ 0x80) << 8; + break; + case 0x14: /*8-bit single cycle DMA output*/ + sb_start_dma(dsp, 1, 0, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + break; + case 0x17: /*2-bit ADPCM output with reference*/ + dsp->sbref = sb_8_read_dma(dsp); + dsp->sbstep = 0; +// pclog("Ref byte 2 %02X\n",sbref); + case 0x16: /*2-bit ADPCM output*/ + sb_start_dma(dsp, 1, 0, ADPCM_2, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + break; + case 0x1C: /*8-bit autoinit DMA output*/ + if (dsp->sb_type < SB15) break; + sb_start_dma(dsp, 1, 1, 0, dsp->sb_8_autolen); + break; + case 0x1F: /*2-bit ADPCM autoinit output*/ + if (dsp->sb_type < SB15) break; + sb_start_dma(dsp, 1, 1, ADPCM_2, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + break; + case 0x20: /*8-bit direct input*/ + sb_add_data(dsp, 0); + break; + case 0x24: /*8-bit single cycle DMA input*/ + sb_start_dma_i(dsp, 1, 0, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + break; + case 0x2C: /*8-bit autoinit DMA input*/ + if (dsp->sb_type < SB15) break; + sb_start_dma_i(dsp, 1, 1, 0, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + break; + case 0x40: /*Set time constant*/ + dsp->sb_timei = dsp->sb_timeo = dsp->sb_data[0]; + dsp->sblatcho = dsp->sblatchi = TIMER_USEC * (256 - dsp->sb_data[0]); + temp = 256 - dsp->sb_data[0]; + temp = 1000000 / temp; +// pclog("Sample rate - %ihz (%i)\n",temp, dsp->sblatcho); + dsp->sb_freq = temp; + break; + case 0x41: /*Set output sampling rate*/ + case 0x42: /*Set input sampling rate*/ + if (dsp->sb_type < SB16) break; + dsp->sblatcho = (int)(TIMER_USEC * (1000000.0f / (float)(dsp->sb_data[1] + (dsp->sb_data[0] << 8)))); +// pclog("Sample rate - %ihz (%i)\n",dsp->sb_data[1]+(dsp->sb_data[0]<<8), dsp->sblatcho); + dsp->sb_freq = dsp->sb_data[1] + (dsp->sb_data[0] << 8); + dsp->sb_timeo = 256 + dsp->sb_freq; + dsp->sblatchi = dsp->sblatcho; + dsp->sb_timei = dsp->sb_timeo; + break; + case 0x48: /*Set DSP block transfer size*/ + dsp->sb_8_autolen = dsp->sb_data[0] + (dsp->sb_data[1] << 8); + break; + case 0x75: /*4-bit ADPCM output with reference*/ + dsp->sbref = sb_8_read_dma(dsp); + dsp->sbstep = 0; +// pclog("Ref byte 4 %02X\n",sbref); + case 0x74: /*4-bit ADPCM output*/ + sb_start_dma(dsp, 1, 0, ADPCM_4, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + break; + case 0x77: /*2.6-bit ADPCM output with reference*/ + dsp->sbref = sb_8_read_dma(dsp); + dsp->sbstep = 0; +// pclog("Ref byte 26 %02X\n",sbref); + case 0x76: /*2.6-bit ADPCM output*/ + sb_start_dma(dsp, 1, 0, ADPCM_26, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + break; + case 0x7D: /*4-bit ADPCM autoinit output*/ + if (dsp->sb_type < SB15) break; + sb_start_dma(dsp, 1, 1, ADPCM_4, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + break; + case 0x7F: /*2.6-bit ADPCM autoinit output*/ + if (dsp->sb_type < SB15) break; + sb_start_dma(dsp, 1, 1, ADPCM_26, dsp->sb_data[0] + (dsp->sb_data[1] << 8)); + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + break; + case 0x80: /*Pause DAC*/ + dsp->sb_pausetime = dsp->sb_data[0] + (dsp->sb_data[1] << 8); +// pclog("SB pause %04X\n",sb_pausetime); + timer_process(); + dsp->sbenable = 1; + timer_update_outstanding(); + break; + case 0x90: /*High speed 8-bit autoinit DMA output*/ + if (dsp->sb_type < SB2) break; + sb_start_dma(dsp, 1, 1, 0, dsp->sb_8_autolen); + break; + case 0x91: /*High speed 8-bit single cycle DMA output*/ + if (dsp->sb_type < SB2) break; + sb_start_dma(dsp, 1, 0, 0, dsp->sb_8_autolen); + break; + case 0x98: /*High speed 8-bit autoinit DMA input*/ + if (dsp->sb_type < SB2) break; + sb_start_dma_i(dsp, 1, 1, 0, dsp->sb_8_autolen); + break; + case 0x99: /*High speed 8-bit single cycle DMA input*/ + if (dsp->sb_type < SB2) break; + sb_start_dma_i(dsp, 1, 0, 0, dsp->sb_8_autolen); + break; + case 0xA0: /*Set input mode to mono*/ + case 0xA8: /*Set input mode to stereo*/ + break; + case 0xB0: case 0xB1: case 0xB2: case 0xB3: + case 0xB4: case 0xB5: case 0xB6: case 0xB7: /*16-bit DMA output*/ + if (dsp->sb_type < SB16) break; + sb_start_dma(dsp, 0, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8)); + dsp->sb_16_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8); + break; + case 0xB8: case 0xB9: case 0xBA: case 0xBB: + case 0xBC: case 0xBD: case 0xBE: case 0xBF: /*16-bit DMA input*/ + if (dsp->sb_type < SB16) break; + sb_start_dma_i(dsp, 0, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8)); + dsp->sb_16_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8); + break; + case 0xC0: case 0xC1: case 0xC2: case 0xC3: + case 0xC4: case 0xC5: case 0xC6: case 0xC7: /*8-bit DMA output*/ + if (dsp->sb_type < SB16) break; + sb_start_dma(dsp, 1, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8)); + dsp->sb_8_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8); + break; + case 0xC8: case 0xC9: case 0xCA: case 0xCB: + case 0xCC: case 0xCD: case 0xCE: case 0xCF: /*8-bit DMA input*/ + if (dsp->sb_type < SB16) break; + sb_start_dma_i(dsp, 1, dsp->sb_command & 4, dsp->sb_data[0], dsp->sb_data[1] + (dsp->sb_data[2] << 8)); + dsp->sb_8_autolen = dsp->sb_data[1] + (dsp->sb_data[2] << 8); + break; + case 0xD0: /*Pause 8-bit DMA*/ + dsp->sb_8_pause = 1; + break; + case 0xD1: /*Speaker on*/ + dsp->sb_speaker = 1; + break; + case 0xD3: /*Speaker off*/ + dsp->sb_speaker = 0; + break; + case 0xD4: /*Continue 8-bit DMA*/ + dsp->sb_8_pause = 0; + break; + case 0xD5: /*Pause 16-bit DMA*/ + if (dsp->sb_type < SB16) break; + dsp->sb_16_pause = 1; + break; + case 0xD6: /*Continue 16-bit DMA*/ + if (dsp->sb_type < SB16) break; + dsp->sb_16_pause = 0; + break; + case 0xD8: /*Get speaker status*/ + sb_add_data(dsp, dsp->sb_speaker ? 0xff : 0); + break; + case 0xD9: /*Exit 16-bit auto-init mode*/ + if (dsp->sb_type < SB16) break; + dsp->sb_16_autoinit = 0; + break; + case 0xDA: /*Exit 8-bit auto-init mode*/ + dsp->sb_8_autoinit = 0; + break; + case 0xE0: /*DSP identification*/ + sb_add_data(dsp, ~dsp->sb_data[0]); + break; + case 0xE1: /*Get DSP version*/ + sb_add_data(dsp, sb_dsp_versions[dsp->sb_type] >> 8); + sb_add_data(dsp, sb_dsp_versions[dsp->sb_type] & 0xff); + break; + case 0xE2: /*Stupid ID/protection*/ + for (c = 0; c < 8; c++) + if (dsp->sb_data[0] & (1 << c)) dsp->sbe2 += sbe2dat[dsp->sbe2count & 3][c]; + dsp->sbe2 += sbe2dat[dsp->sbe2count & 3][8]; + dsp->sbe2count++; + sb_8_write_dma(dsp, dsp->sbe2); + break; + case 0xE3: /*DSP copyright*/ + if (dsp->sb_type < SB16) break; + c = 0; + while (sb16_copyright[c]) + sb_add_data(dsp, sb16_copyright[c++]); + sb_add_data(dsp, 0); + break; + case 0xE4: /*Write test register*/ + dsp->sb_test = dsp->sb_data[0]; + break; + case 0xE8: /*Read test register*/ + sb_add_data(dsp, dsp->sb_test); + break; + case 0xF2: /*Trigger 8-bit IRQ*/ +// pclog("Trigger IRQ\n"); + sb_irq(dsp, 1); + break; + case 0xE7: /*???*/ + case 0xFA: /*???*/ + break; + case 0x07: /*No, that's not how you program auto-init DMA*/ + case 0xFF: + break; + case 0x08: /*ASP get version*/ + if (dsp->sb_type < SB16) break; + sb_add_data(dsp, 0x18); + break; + case 0x0E: /*ASP set register*/ + if (dsp->sb_type < SB16) break; + dsp->sb_asp_regs[dsp->sb_data[0]] = dsp->sb_data[1]; +// pclog("ASP write reg %02X %02X\n", sb_data[0], sb_data[1]); + break; + case 0x0F: /*ASP get register*/ + if (dsp->sb_type < SB16) break; +// sb_add_data(0); + sb_add_data(dsp, dsp->sb_asp_regs[dsp->sb_data[0]]); +// pclog("ASP read reg %02X %02X\n", sb_data[0], sb_asp_regs[sb_data[0]]); + break; + case 0xF9: + if (dsp->sb_type < SB16) break; + if (dsp->sb_data[0] == 0x0e) sb_add_data(dsp, 0xff); + else if (dsp->sb_data[0] == 0x0f) sb_add_data(dsp, 0x07); + else if (dsp->sb_data[0] == 0x37) sb_add_data(dsp, 0x38); + else sb_add_data(dsp, 0x00); + case 0x04: + case 0x05: + break; +// default: +// fatal("Exec bad SB command %02X\n",sb_command); + } +} + +void sb_write(uint16_t a, uint8_t v, void *priv) +{ + sb_dsp_t *dsp = (sb_dsp_t *)priv; +// pclog("sb_write : Write soundblaster %04X %02X %04X:%04X %02X\n",a,v,CS,pc,dsp->sb_command); + switch (a&0xF) + { + case 6: /*Reset*/ + if (!(v & 1) && (dsp->sbreset & 1)) + { + sb_dsp_reset(dsp); + sb_add_data(dsp, 0xAA); + } + dsp->sbreset = v; + return; + case 0xC: /*Command/data write*/ + timer_process(); + dsp->wb_time = TIMER_USEC * 1; + dsp->wb_full = 1; + timer_update_outstanding(); + if (dsp->asp_data_len) + { +// pclog("ASP data %i\n", dsp->asp_data_len); + dsp->asp_data_len--; + if (!dsp->asp_data_len) + sb_add_data(dsp, 0); + return; + } + if (dsp->sb_data_stat == -1) + { + dsp->sb_command = v; + if (v == 0x01) + sb_add_data(dsp, 0); +// if (sb_commands[v]==-1) +// fatal("Bad SB command %02X\n",v); + dsp->sb_data_stat++; + } + else + dsp->sb_data[dsp->sb_data_stat++] = v; + if (dsp->sb_data_stat == sb_commands[dsp->sb_command] || sb_commands[dsp->sb_command] == -1) + { + sb_exec_command(dsp); + dsp->sb_data_stat = -1; + } + break; + } +} + +uint8_t sb_read(uint16_t a, void *priv) +{ + sb_dsp_t *dsp = (sb_dsp_t *)priv; +// if (a==0x224) output=1; +// pclog("sb_read : Read soundblaster %04X %04X:%04X\n",a,CS,pc); + switch (a & 0xf) + { + case 0xA: /*Read data*/ + dsp->sbreaddat = dsp->sb_read_data[dsp->sb_read_rp]; + if (dsp->sb_read_rp != dsp->sb_read_wp) + { + dsp->sb_read_rp++; + dsp->sb_read_rp &= 0xFF; + } +// pclog("SB read %02X\n",sbreaddat); + return dsp->sbreaddat; + case 0xC: /*Write data ready*/ + if (dsp->wb_full) + { + dsp->wb_full = dsp->wb_time; + return 0xff; + } + return 0x7f; + case 0xE: /*Read data ready*/ + picintc(1 << dsp->sb_irqnum); + dsp->sb_irq8 = dsp->sb_irq16 = 0; + return (dsp->sb_read_rp == dsp->sb_read_wp) ? 0x7f : 0xff; + case 0xF: /*16-bit ack*/ + dsp->sb_irq16 = 0; + if (!dsp->sb_irq8) picintc(1 << dsp->sb_irqnum); + return 0xff; + } + return 0; +} + +static void sb_wb_clear(void *p) +{ + sb_dsp_t *dsp = (sb_dsp_t *)p; + + dsp->wb_time = 0; +} + +void sb_dsp_init(sb_dsp_t *dsp, int type) +{ + dsp->sb_type = type; + + dsp->sb_irqnum = 7; + dsp->sb_8_dmanum = 1; + + sb_doreset(dsp); + + timer_add(pollsb, &dsp->sbcount, &dsp->sbenable, dsp); + timer_add(sb_poll_i, &dsp->sb_count_i, &dsp->sb_enable_i, dsp); + timer_add(sb_wb_clear, &dsp->wb_time, &dsp->wb_time, dsp); +} + +void sb_dsp_setaddr(sb_dsp_t *dsp, uint16_t addr) +{ +// pclog("sb_dsp_setaddr : %04X\n", addr); + io_removehandler(dsp->sb_addr + 6, 0x0002, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); + io_removehandler(dsp->sb_addr + 0xa, 0x0006, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); + dsp->sb_addr = addr; + if (dsp->sb_addr != 0) + { + io_sethandler(dsp->sb_addr + 6, 0x0002, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); + io_sethandler(dsp->sb_addr + 0xa, 0x0006, sb_read, NULL, NULL, sb_write, NULL, NULL, dsp); + } +} + +void sb_dsp_set_stereo(sb_dsp_t *dsp, int stereo) +{ + dsp->stereo = stereo; +} + +void pollsb(void *p) +{ + sb_dsp_t *dsp = (sb_dsp_t *)p; + int tempi,ref; + + dsp->sbcount += dsp->sblatcho; +// pclog("PollSB %i %i %i %i\n",sb_8_enable,sb_8_pause,sb_pausetime,sb_8_output); + if (dsp->sb_8_enable && !dsp->sb_8_pause && dsp->sb_pausetime < 0 && dsp->sb_8_output) + { + int data[2]; + + sb_dsp_update(dsp); +// pclog("Dopoll %i %02X %i\n", sb_8_length, sb_8_format, sblatcho); + switch (dsp->sb_8_format) + { + case 0x00: /*Mono unsigned*/ + data[0] = sb_8_read_dma(dsp); + /*Needed to prevent clicking in Worms, which programs the DSP to + auto-init DMA but programs the DMA controller to single cycle*/ + if (data[0] == DMA_NODATA) + break; + dsp->sbdat = (data[0] ^ 0x80) << 8; + if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo) + { + if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat; + else dsp->sbdatr = dsp->sbdat; + dsp->sbleftright = !dsp->sbleftright; + } + else + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + dsp->sb_8_length--; + break; + case 0x10: /*Mono signed*/ + data[0] = sb_8_read_dma(dsp); + if (data[0] == DMA_NODATA) + break; + dsp->sbdat = data[0] << 8; + if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo) + { + if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat; + else dsp->sbdatr = dsp->sbdat; + dsp->sbleftright = !dsp->sbleftright; + } + else + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + dsp->sb_8_length--; + break; + case 0x20: /*Stereo unsigned*/ + data[0] = sb_8_read_dma(dsp); + data[1] = sb_8_read_dma(dsp); + if (data[0] == DMA_NODATA || data[1] == DMA_NODATA) + break; + dsp->sbdatl = (data[0] ^ 0x80) << 8; + dsp->sbdatr = (data[1] ^ 0x80) << 8; + dsp->sb_8_length -= 2; + break; + case 0x30: /*Stereo signed*/ + data[0] = sb_8_read_dma(dsp); + data[1] = sb_8_read_dma(dsp); + if (data[0] == DMA_NODATA || data[1] == DMA_NODATA) + break; + dsp->sbdatl = data[0] << 8; + dsp->sbdatr = data[1] << 8; + dsp->sb_8_length -= 2; + break; + + case ADPCM_4: + if (dsp->sbdacpos) tempi = (dsp->sbdat2 & 0xF) + dsp->sbstep; + else tempi = (dsp->sbdat2 >> 4) + dsp->sbstep; + if (tempi < 0) tempi = 0; + if (tempi > 63) tempi = 63; + + ref = dsp->sbref + scaleMap4[tempi]; + if (ref > 0xff) dsp->sbref = 0xff; + else if (ref < 0x00) dsp->sbref = 0x00; + else dsp->sbref = ref; + + dsp->sbstep = (dsp->sbstep + adjustMap4[tempi]) & 0xff; + + dsp->sbdat = (dsp->sbref ^ 0x80) << 8; + + dsp->sbdacpos++; + if (dsp->sbdacpos >= 2) + { + dsp->sbdacpos = 0; + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + } + + if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo) + { + if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat; + else dsp->sbdatr = dsp->sbdat; + dsp->sbleftright = !dsp->sbleftright; + } + else + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + break; + + case ADPCM_26: + if (!dsp->sbdacpos) tempi = (dsp->sbdat2 >> 5) + dsp->sbstep; + else if (dsp->sbdacpos == 1) tempi = ((dsp->sbdat2 >> 2) & 7) + dsp->sbstep; + else tempi = ((dsp->sbdat2 << 1) & 7) + dsp->sbstep; + + if (tempi < 0) tempi = 0; + if (tempi > 39) tempi = 39; + + ref = dsp->sbref + scaleMap26[tempi]; + if (ref > 0xff) dsp->sbref = 0xff; + else if (ref < 0x00) dsp->sbref = 0x00; + else dsp->sbref = ref; + dsp->sbstep = (dsp->sbstep + adjustMap26[tempi]) & 0xff; + + dsp->sbdat = (dsp->sbref ^ 0x80) << 8; + + dsp->sbdacpos++; + if (dsp->sbdacpos>=3) + { + dsp->sbdacpos = 0; + dsp->sbdat2 = sb_8_read_dma(dsp); + dsp->sb_8_length--; + } + + if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo) + { + if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat; + else dsp->sbdatr = dsp->sbdat; + dsp->sbleftright = !dsp->sbleftright; + } + else + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + break; + + case ADPCM_2: + tempi = ((dsp->sbdat2 >> ((3 - dsp->sbdacpos) * 2)) & 3) + dsp->sbstep; + if (tempi < 0) tempi = 0; + if (tempi > 23) tempi = 23; + + ref = dsp->sbref + scaleMap2[tempi]; + if (ref > 0xff) dsp->sbref = 0xff; + else if (ref < 0x00) dsp->sbref = 0x00; + else dsp->sbref = ref; + dsp->sbstep = (dsp->sbstep + adjustMap2[tempi]) & 0xff; + + dsp->sbdat = (dsp->sbref ^ 0x80) << 8; + + dsp->sbdacpos++; + if (dsp->sbdacpos >= 4) + { + dsp->sbdacpos = 0; + dsp->sbdat2 = sb_8_read_dma(dsp); + } + + if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo) + { + if (dsp->sbleftright) dsp->sbdatl = dsp->sbdat; + else dsp->sbdatr = dsp->sbdat; + dsp->sbleftright = !dsp->sbleftright; + } + else + dsp->sbdatl = dsp->sbdatr = dsp->sbdat; + break; + +// default: + //fatal("Unrecognised SB 8-bit format %02X\n",sb_8_format); + } + + if (dsp->sb_8_length < 0) + { + if (dsp->sb_8_autoinit) dsp->sb_8_length = dsp->sb_8_autolen; + else dsp->sb_8_enable = dsp->sbenable=0; + sb_irq(dsp, 1); + } + } + if (dsp->sb_16_enable && !dsp->sb_16_pause && dsp->sb_pausetime < 0 && dsp->sb_16_output) + { + sb_dsp_update(dsp); + + switch (dsp->sb_16_format) + { + case 0x00: /*Mono unsigned*/ + dsp->sbdatl = dsp->sbdatr = sb_16_read_dma(dsp) ^ 0x8000; + dsp->sb_16_length--; + break; + case 0x10: /*Mono signed*/ + dsp->sbdatl = dsp->sbdatr = sb_16_read_dma(dsp); + dsp->sb_16_length--; + break; + case 0x20: /*Stereo unsigned*/ + dsp->sbdatl = sb_16_read_dma(dsp) ^ 0x8000; + dsp->sbdatr = sb_16_read_dma(dsp) ^ 0x8000; + dsp->sb_16_length -= 2; + break; + case 0x30: /*Stereo signed*/ + dsp->sbdatl = sb_16_read_dma(dsp); + dsp->sbdatr = sb_16_read_dma(dsp); + dsp->sb_16_length -= 2; + break; + +// default: +// fatal("Unrecognised SB 16-bit format %02X\n",sb_16_format); + } + + if (dsp->sb_16_length < 0) + { +// pclog("16DMA over %i\n",dsp->sb_16_autoinit); + if (dsp->sb_16_autoinit) dsp->sb_16_length = dsp->sb_16_autolen; + else dsp->sb_16_enable = dsp->sbenable = 0; + sb_irq(dsp, 0); + } + } + if (dsp->sb_pausetime > -1) + { + dsp->sb_pausetime--; + if (dsp->sb_pausetime < 0) + { + sb_irq(dsp, 1); + dsp->sbenable = dsp->sb_8_enable; +// pclog("SB pause over\n"); + } + } +} + +void sb_poll_i(void *p) +{ + sb_dsp_t *dsp = (sb_dsp_t *)p; + + dsp->sb_count_i += dsp->sblatchi; +// pclog("PollSBi %i %i %i %i\n",sb_8_enable,sb_8_pause,sb_pausetime,sb_8_output); + if (dsp->sb_8_enable && !dsp->sb_8_pause && dsp->sb_pausetime < 0 && !dsp->sb_8_output) + { + switch (dsp->sb_8_format) + { + case 0x00: /*Mono unsigned*/ + sb_8_write_dma(dsp, 0x80); + dsp->sb_8_length--; + break; + case 0x10: /*Mono signed*/ + sb_8_write_dma(dsp, 0x00); + dsp->sb_8_length--; + break; + case 0x20: /*Stereo unsigned*/ + sb_8_write_dma(dsp, 0x80); + sb_8_write_dma(dsp, 0x80); + dsp->sb_8_length -= 2; + break; + case 0x30: /*Stereo signed*/ + sb_8_write_dma(dsp, 0x00); + sb_8_write_dma(dsp, 0x00); + dsp->sb_8_length -= 2; + break; + +// default: +// fatal("Unrecognised SB 8-bit input format %02X\n",sb_8_format); + } + + if (dsp->sb_8_length < 0) + { +// pclog("Input DMA over %i\n",sb_8_autoinit); + if (dsp->sb_8_autoinit) dsp->sb_8_length = dsp->sb_8_autolen; + else dsp->sb_8_enable = dsp->sbenable = 0; + sb_irq(dsp, 1); + } + } + if (dsp->sb_16_enable && !dsp->sb_16_pause && dsp->sb_pausetime < 0 && !dsp->sb_16_output) + { + switch (dsp->sb_16_format) + { + case 0x00: /*Unsigned mono*/ + sb_16_write_dma(dsp, 0x8000); + dsp->sb_16_length--; + break; + case 0x10: /*Signed mono*/ + sb_16_write_dma(dsp, 0); + dsp->sb_16_length--; + break; + case 0x20: /*Unsigned stereo*/ + sb_16_write_dma(dsp, 0x8000); + sb_16_write_dma(dsp, 0x8000); + dsp->sb_16_length -= 2; + break; + case 0x30: /*Signed stereo*/ + sb_16_write_dma(dsp, 0); + sb_16_write_dma(dsp, 0); + dsp->sb_16_length -= 2; + break; + +// default: +// fatal("Unrecognised SB 16-bit input format %02X\n",sb_16_format); + } + + if (dsp->sb_16_length < 0) + { +// pclog("16iDMA over %i\n",sb_16_autoinit); + if (dsp->sb_16_autoinit) dsp->sb_16_length = dsp->sb_16_autolen; + else dsp->sb_16_enable = dsp->sbenable = 0; + sb_irq(dsp, 0); + } + } +} + +void sb_dsp_update(sb_dsp_t *dsp) +{ + for (; dsp->pos < sound_pos_global; dsp->pos++) + { + dsp->buffer[dsp->pos*2] = dsp->sbdatl; + dsp->buffer[dsp->pos*2 + 1] = dsp->sbdatr; + } +} + +void sb_dsp_add_status_info(char *s, int max_len, sb_dsp_t *dsp) +{ + char temps[128]; + int len; + int freq; + + if (dsp->sb_timeo < 256) + freq = 1000000 / (256 - dsp->sb_timeo); + else + freq = dsp->sb_timeo - 256; + + if (dsp->sb_8_enable && dsp->sb_8_output) + { + switch (dsp->sb_8_format) + { + case 0x00: /*Mono unsigned*/ + case 0x10: /*Mono signed*/ + if (dsp->sb_type >= SBPRO && dsp->sb_type < SB16 && dsp->stereo) + { + strcpy(temps, "SB playback format : 8-bit stereo\n"); + freq /= 2; + } + else + strcpy(temps, "SB playback format : 8-bit mono\n"); + break; + case 0x20: /*Stereo unsigned*/ + case 0x30: /*Stereo signed*/ + strcpy(temps, "SB playback format : 8-bit stereo\n"); + break; + case ADPCM_4: + strcpy(temps, "SB playback format : 4-bit ADPCM\n"); + break; + case ADPCM_26: + strcpy(temps, "SB playback format : 2.6-bit ADPCM\n"); + break; + case ADPCM_2: + strcpy(temps, "SB playback format : 2-bit ADPCM\n"); + break; + } + } + else if (dsp->sb_16_enable && dsp->sb_16_output) + { + switch (dsp->sb_16_format) + { + case 0x00: /*Mono unsigned*/ + case 0x10: /*Mono signed*/ + strcpy(temps, "SB playback format : 16-bit mono\n"); + break; + case 0x20: /*Stereo unsigned*/ + case 0x30: /*Stereo signed*/ + strcpy(temps, "SB playback format : 16-bit stereo\n"); + break; + } + } + else + strcpy(temps, "SB playback stopped\n"); + strncat(s, temps, max_len); + + if ((dsp->sb_8_enable && dsp->sb_8_output) || (dsp->sb_16_enable && dsp->sb_16_output)) + { + sprintf(temps, "SB playback frequency : %iHz\n", freq); + strncat(s, temps, max_len); + } +} diff --git a/src/sound_sb_dsp.h b/src/sound_sb_dsp.h new file mode 100644 index 000000000..444513642 --- /dev/null +++ b/src/sound_sb_dsp.h @@ -0,0 +1,78 @@ +typedef struct sb_dsp_t +{ + int sb_type; + + int sb_8_length, sb_8_format, sb_8_autoinit, sb_8_pause, sb_8_enable, sb_8_autolen, sb_8_output; + int sb_8_dmanum; + int sb_16_length, sb_16_format, sb_16_autoinit, sb_16_pause, sb_16_enable, sb_16_autolen, sb_16_output; + int sb_pausetime; + + uint8_t sb_read_data[256]; + int sb_read_wp, sb_read_rp; + int sb_speaker; + + int sb_data_stat; + + int sb_irqnum; + + uint8_t sbe2; + int sbe2count; + + uint8_t sb_data[8]; + + int sb_freq; + + int16_t sbdat; + int sbdat2; + int16_t sbdatl, sbdatr; + + uint8_t sbref; + int8_t sbstep; + + int sbdacpos; + + int sbleftright; + + int sbreset; + uint8_t sbreaddat; + uint8_t sb_command; + uint8_t sb_test; + int sb_timei, sb_timeo; + + int sb_irq8, sb_irq16; + + uint8_t sb_asp_regs[256]; + + int sbenable, sb_enable_i; + + int sbcount, sb_count_i; + + int sblatcho, sblatchi; + + uint16_t sb_addr; + + int stereo; + + int asp_data_len; + + int wb_time, wb_full; + + int16_t buffer[SOUNDBUFLEN * 2]; + int pos; +} sb_dsp_t; + +void sb_dsp_init(sb_dsp_t *dsp, int type); + +void sb_dsp_setirq(sb_dsp_t *dsp, int irq); +void sb_dsp_setdma8(sb_dsp_t *dsp, int dma); +void sb_dsp_setaddr(sb_dsp_t *dsp, uint16_t addr); + +void sb_dsp_speed_changed(sb_dsp_t *dsp); + +void sb_dsp_poll(sb_dsp_t *dsp, int16_t *l, int16_t *r); + +void sb_dsp_set_stereo(sb_dsp_t *dsp, int stereo); + +void sb_dsp_add_status_info(char *s, int max_len, sb_dsp_t *dsp); + +void sb_dsp_update(sb_dsp_t *dsp); diff --git a/src/sound_sn76489.c b/src/sound_sn76489.c new file mode 100644 index 000000000..2dae07669 --- /dev/null +++ b/src/sound_sn76489.c @@ -0,0 +1,250 @@ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "sound.h" +#include "sound_sn76489.h" + +int sn76489_mute; + +static float volslog[16]= +{ + 0.00000f,0.59715f,0.75180f,0.94650f, + 1.19145f,1.50000f,1.88835f,2.37735f, + 2.99295f,3.76785f,4.74345f,5.97165f, + 7.51785f,9.46440f,11.9194f,15.0000f +}; + +//#define PSGCONST ((3579545.0 / 64.0) / 48000.0) + +void sn76489_update(sn76489_t *sn76489) +{ + for (; sn76489->pos < sound_pos_global; sn76489->pos++) + { + int c; + int16_t result = 0; + + for (c = 1; c < 4; c++) + { + if (sn76489->latch[c] > 256) result += (int16_t) (volslog[sn76489->vol[c]] * sn76489->stat[c]); + else result += (int16_t) (volslog[sn76489->vol[c]] * 127); + + sn76489->count[c] -= (256 * sn76489->psgconst); + while ((int)sn76489->count[c] < 0) + { + sn76489->count[c] += sn76489->latch[c]; + sn76489->stat[c] = -sn76489->stat[c]; + } + } + result += (((sn76489->shift & 1) ^ 1) * 127 * volslog[sn76489->vol[0]] * 2); + + sn76489->count[0] -= (512 * sn76489->psgconst); + while ((int)sn76489->count[0] < 0 && sn76489->latch[0]) + { + sn76489->count[0] += (sn76489->latch[0] * 4); + if (!(sn76489->noise & 4)) + { + if (sn76489->shift & 1) + sn76489->shift |= 0x8000; + sn76489->shift >>= 1; + } + else + { + if ((sn76489->shift & 1) ^ ((sn76489->shift >> 1) & 1)) + sn76489->shift |= 0x8000; + sn76489->shift >>= 1; + } + } + + sn76489->buffer[sn76489->pos] = result; + } +} + +void sn76489_get_buffer(int32_t *buffer, int len, void *p) +{ + sn76489_t *sn76489 = (sn76489_t *)p; + + int c; + + sn76489_update(sn76489); + + if (!sn76489_mute) + { + for (c = 0; c < len * 2; c++) + buffer[c] += sn76489->buffer[c >> 1]; + } + + sn76489->pos = 0; +} + +void sn76489_write(uint16_t addr, uint8_t data, void *p) +{ + sn76489_t *sn76489 = (sn76489_t *)p; + int freq; + + sn76489_update(sn76489); + + if (data & 0x80) + { + sn76489->firstdat = data; + switch (data & 0x70) + { + case 0: + sn76489->freqlo[3] = data & 0xf; + sn76489->latch[3] = (sn76489->freqlo[3] | (sn76489->freqhi[3] << 4)) << 6; + if (sn76489->extra_divide) + sn76489->latch[3] &= 0x3ff; + if (!sn76489->latch[3]) + sn76489->latch[3] = (sn76489->extra_divide ? 2048 : 1024) << 6; + sn76489->lasttone = 3; + break; + case 0x10: + data &= 0xf; + sn76489->vol[3] = 0xf - data; + break; + case 0x20: + sn76489->freqlo[2] = data & 0xf; + sn76489->latch[2] = (sn76489->freqlo[2] | (sn76489->freqhi[2] << 4)) << 6; + if (sn76489->extra_divide) + sn76489->latch[2] &= 0x3ff; + if (!sn76489->latch[2]) + sn76489->latch[2] = (sn76489->extra_divide ? 2048 : 1024) << 6; + sn76489->lasttone = 2; + break; + case 0x30: + data &= 0xf; + sn76489->vol[2] = 0xf - data; + break; + case 0x40: + sn76489->freqlo[1] = data & 0xf; + sn76489->latch[1] = (sn76489->freqlo[1] | (sn76489->freqhi[1] << 4)) << 6; + if (sn76489->extra_divide) + sn76489->latch[1] &= 0x3ff; + if (!sn76489->latch[1]) + sn76489->latch[1] = (sn76489->extra_divide ? 2048 : 1024) << 6; + sn76489->lasttone = 1; + break; + case 0x50: + data &= 0xf; + sn76489->vol[1] = 0xf - data; + break; + case 0x60: + if ((data & 4) != (sn76489->noise & 4) || sn76489->type == SN76496) + sn76489->shift = 0x4000; + sn76489->noise = data & 0xf; + if ((data & 3) == 3) sn76489->latch[0] = sn76489->latch[1]; + else sn76489->latch[0] = 0x400 << (data & 3); + if (sn76489->extra_divide) + sn76489->latch[0] &= 0x3ff; + if (!sn76489->latch[0]) + sn76489->latch[0] = (sn76489->extra_divide ? 2048 : 1024) << 6; + break; + case 0x70: + data &= 0xf; + sn76489->vol[0] = 0xf - data; + break; + } + } + else + { + if ((sn76489->firstdat & 0x70) == 0x60 && (sn76489->type == SN76496)) + { + if ((data & 4) != (sn76489->noise & 4) || sn76489->type == SN76496) + sn76489->shift = 0x4000; + sn76489->noise = data & 0xf; + if ((data & 3) == 3) sn76489->latch[0] = sn76489->latch[1]; + else sn76489->latch[0] = 0x400 << (data & 3); + if (!sn76489->latch[0]) + sn76489->latch[0] = 1024 << 6; + } + else if ((sn76489->firstdat & 0x70) != 0x60) + { + sn76489->freqhi[sn76489->lasttone] = data & 0x7F; + freq = sn76489->freqlo[sn76489->lasttone] | (sn76489->freqhi[sn76489->lasttone] << 4); + if (sn76489->extra_divide) + freq &= 0x3ff; + if (!freq) + freq = sn76489->extra_divide ? 2048 : 1024; + if ((sn76489->noise & 3) == 3 && sn76489->lasttone == 1) + sn76489->latch[0] = freq << 6; + sn76489->latch[sn76489->lasttone] = freq << 6; + } + } +} + +void sn74689_set_extra_divide(sn76489_t *sn76489, int enable) +{ + sn76489->extra_divide = enable; +} + +void sn76489_init(sn76489_t *sn76489, uint16_t base, uint16_t size, int type, int freq) +{ + sound_add_handler(sn76489_get_buffer, sn76489); + + sn76489->latch[0] = sn76489->latch[1] = sn76489->latch[2] = sn76489->latch[3] = 0x3FF << 6; + sn76489->vol[0] = 0; + sn76489->vol[1] = sn76489->vol[2] = sn76489->vol[3] = 8; + sn76489->stat[0] = sn76489->stat[1] = sn76489->stat[2] = sn76489->stat[3] = 127; + srand(time(NULL)); + sn76489->count[0] = 0; + sn76489->count[1] = (rand()&0x3FF)<<6; + sn76489->count[2] = (rand()&0x3FF)<<6; + sn76489->count[3] = (rand()&0x3FF)<<6; + sn76489->noise = 3; + sn76489->shift = 0x4000; + sn76489->type = type; + sn76489->psgconst = (((double)freq / 64.0) / 48000.0); + + sn76489_mute = 0; + + io_sethandler(base, size, NULL, NULL, NULL, sn76489_write, NULL, NULL, sn76489); +} + +void *sn76489_device_init() +{ + sn76489_t *sn76489 = malloc(sizeof(sn76489_t)); + memset(sn76489, 0, sizeof(sn76489_t)); + + sn76489_init(sn76489, 0x00c0, 0x0008, SN76496, 3579545); + + return sn76489; +} +void *ncr8496_device_init() +{ + sn76489_t *sn76489 = malloc(sizeof(sn76489_t)); + memset(sn76489, 0, sizeof(sn76489_t)); + + sn76489_init(sn76489, 0x00c0, 0x0008, NCR8496, 3579545); + + return sn76489; +} + +void sn76489_device_close(void *p) +{ + sn76489_t *sn76489 = (sn76489_t *)p; + + free(sn76489); +} + +device_t sn76489_device = +{ + "TI SN74689 PSG", + 0, + sn76489_device_init, + sn76489_device_close, + NULL, + NULL, + NULL, + NULL +}; +device_t ncr8496_device = +{ + "NCR8496 PSG", + 0, + ncr8496_device_init, + sn76489_device_close, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/sound_sn76489.h b/src/sound_sn76489.h new file mode 100644 index 000000000..84c102821 --- /dev/null +++ b/src/sound_sn76489.h @@ -0,0 +1,33 @@ +enum +{ + SN76496, + NCR8496, + PSSJ +}; + +extern device_t sn76489_device; +extern device_t ncr8496_device; + +extern int sn76489_mute; + +typedef struct sn76489_t +{ + int stat[4]; + int latch[4], count[4]; + int freqlo[4], freqhi[4]; + int vol[4]; + uint32_t shift; + uint8_t noise; + int lasttone; + uint8_t firstdat; + int type; + int extra_divide; + + int16_t buffer[SOUNDBUFLEN]; + int pos; + + double psgconst; +} sn76489_t; + +void sn76489_init(sn76489_t *sn76489, uint16_t base, uint16_t size, int type, int freq); +void sn74689_set_extra_divide(sn76489_t *sn76489, int enable); diff --git a/src/sound_speaker.c b/src/sound_speaker.c new file mode 100644 index 000000000..8e678253e --- /dev/null +++ b/src/sound_speaker.c @@ -0,0 +1,59 @@ +#include "ibm.h" +#include "sound.h" +#include "sound_speaker.h" + +int speaker_mute = 0; + +static int16_t speaker_buffer[SOUNDBUFLEN]; + +static int speaker_pos = 0; + +int speaker_gated = 0; +int speaker_enable = 0, was_speaker_enable = 0; + +void speaker_update() +{ + int16_t val; + +// printf("SPeaker - %i %i %i %02X\n",speakval,gated,speakon,pit.m[2]); + for (; speaker_pos < sound_pos_global; speaker_pos++) + { + if (speaker_gated && was_speaker_enable) + { + if (!pit.m[2] || pit.m[2]==4) + val = speakval; + else if (pit.l[2] < 0x40) + val = 0xa00; + else + val = speakon ? 0x1400 : 0; + } + else + val = was_speaker_enable ? 0x1400 : 0; + + if (!speaker_enable) + was_speaker_enable = 0; + + speaker_buffer[speaker_pos] = val; + } +} + +static void speaker_get_buffer(int32_t *buffer, int len, void *p) +{ + int c; + + speaker_update(); + + if (!speaker_mute) + { + for (c = 0; c < len * 2; c++) + buffer[c] += speaker_buffer[c >> 1]; + } + + speaker_pos = 0; +} + +void speaker_init() +{ + sound_add_handler(speaker_get_buffer, NULL); + speaker_mute = 0; +} diff --git a/src/sound_speaker.h b/src/sound_speaker.h new file mode 100644 index 000000000..409a7c4e6 --- /dev/null +++ b/src/sound_speaker.h @@ -0,0 +1,8 @@ +void speaker_init(); + +extern int speaker_mute; + +extern int speaker_gated; +extern int speaker_enable, was_speaker_enable; + +void speaker_update(); diff --git a/src/sound_ssi2001.c b/src/sound_ssi2001.c new file mode 100644 index 000000000..fd675c309 --- /dev/null +++ b/src/sound_ssi2001.c @@ -0,0 +1,87 @@ +#include +#include "ibm.h" +#include "device.h" +#include "sound.h" + +#include "sound_resid.h" +#include "sound_ssi2001.h" + +typedef struct ssi2001_t +{ + void *psid; + int16_t buffer[SOUNDBUFLEN * 2]; + int pos; +} ssi2001_t; + +static void ssi2001_update(ssi2001_t *ssi2001) +{ + if (ssi2001->pos >= sound_pos_global) + return; + + sid_fillbuf(&ssi2001->buffer[ssi2001->pos], sound_pos_global - ssi2001->pos, ssi2001->psid); + ssi2001->pos = sound_pos_global; +} + +static void ssi2001_get_buffer(int32_t *buffer, int len, void *p) +{ + ssi2001_t *ssi2001 = (ssi2001_t *)p; + int c; + + ssi2001_update(ssi2001); + + for (c = 0; c < len * 2; c++) + buffer[c] += ssi2001->buffer[c >> 1] / 2; + + ssi2001->pos = 0; +} + +static uint8_t ssi2001_read(uint16_t addr, void *p) +{ + ssi2001_t *ssi2001 = (ssi2001_t *)p; + + ssi2001_update(ssi2001); + + return sid_read(addr, p); +} + +static void ssi2001_write(uint16_t addr, uint8_t val, void *p) +{ + ssi2001_t *ssi2001 = (ssi2001_t *)p; + + ssi2001_update(ssi2001); + sid_write(addr, val, p); +} + +void *ssi2001_init() +{ + ssi2001_t *ssi2001 = malloc(sizeof(ssi2001_t)); + memset(ssi2001, 0, sizeof(ssi2001_t)); + + pclog("ssi2001_init\n"); + ssi2001->psid = sid_init(); + sid_reset(ssi2001->psid); + io_sethandler(0x0280, 0x0020, ssi2001_read, NULL, NULL, ssi2001_write, NULL, NULL, ssi2001); + sound_add_handler(ssi2001_get_buffer, ssi2001); + return ssi2001; +} + +void ssi2001_close(void *p) +{ + ssi2001_t *ssi2001 = (ssi2001_t *)p; + + sid_close(ssi2001->psid); + + free(ssi2001); +} + +device_t ssi2001_device = +{ + "Innovation SSI-2001", + 0, + ssi2001_init, + ssi2001_close, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/sound_ssi2001.h b/src/sound_ssi2001.h new file mode 100644 index 000000000..337c6260a --- /dev/null +++ b/src/sound_ssi2001.h @@ -0,0 +1 @@ +extern device_t ssi2001_device; diff --git a/src/sound_wss.c b/src/sound_wss.c new file mode 100644 index 000000000..b5fecd08f --- /dev/null +++ b/src/sound_wss.c @@ -0,0 +1,125 @@ +/*PCem v0.8 by Tom Walker + + Windows Sound System emulation*/ + +#include +#include +#include "ibm.h" + +#include "device.h" +#include "dma.h" +#include "io.h" +#include "pic.h" +#include "sound_ad1848.h" +#include "sound_opl.h" +#include "sound_wss.h" + +/*530, 11, 3 - 530=23*/ +/*530, 11, 1 - 530=22*/ +/*530, 11, 0 - 530=21*/ +/*530, 10, 1 - 530=1a*/ +/*530, 9, 1 - 530=12*/ +/*530, 7, 1 - 530=0a*/ +/*604, 11, 1 - 530=22*/ +/*e80, 11, 1 - 530=22*/ +/*f40, 11, 1 - 530=22*/ + + +static int wss_dma[4] = {0, 0, 1, 3}; +static int wss_irq[8] = {5, 7, 9, 10, 11, 12, 14, 15}; /*W95 only uses 7-9, others may be wrong*/ +static uint16_t wss_addr[4] = {0x530, 0x604, 0xe80, 0xf40}; + +typedef struct wss_t +{ + uint8_t config; + + ad1848_t ad1848; + opl_t opl; +} wss_t; + +uint8_t wss_read(uint16_t addr, void *p) +{ + wss_t *wss = (wss_t *)p; + uint8_t temp; +// pclog("wss_read - addr %04X %04X(%08X):%08X ", addr, CS, cs, pc); + temp = 4 | (wss->config & 0x40); +// pclog("return %02X\n", temp); + return temp; +} + +void wss_write(uint16_t addr, uint8_t val, void *p) +{ + wss_t *wss = (wss_t *)p; +// pclog("wss_write - addr %04X val %02X %04X(%08X):%08X\n", addr, val, CS, cs, pc); + + wss->config = val; + ad1848_setdma(&wss->ad1848, wss_dma[val & 3]); + ad1848_setirq(&wss->ad1848, wss_irq[(val >> 3) & 7]); +} + +static void wss_get_buffer(int32_t *buffer, int len, void *p) +{ + wss_t *wss = (wss_t *)p; + + int c; + + opl3_update2(&wss->opl); + ad1848_update(&wss->ad1848); + for (c = 0; c < len * 2; c++) + { + buffer[c] += wss->opl.buffer[c]; + buffer[c] += (wss->ad1848.buffer[c] / 2); + } + + wss->opl.pos = 0; + wss->ad1848.pos = 0; +} + +void *wss_init() +{ + wss_t *wss = malloc(sizeof(wss_t)); + int c; + double attenuation; + + memset(wss, 0, sizeof(wss_t)); + + opl3_init(&wss->opl); + ad1848_init(&wss->ad1848); + + ad1848_setirq(&wss->ad1848, 7); + ad1848_setdma(&wss->ad1848, 3); + + io_sethandler(0x0388, 0x0004, opl3_read, NULL, NULL, opl3_write, NULL, NULL, &wss->opl); + io_sethandler(0x0530, 0x0004, wss_read, NULL, NULL, wss_write, NULL, NULL, wss); + io_sethandler(0x0534, 0x0004, ad1848_read, NULL, NULL, ad1848_write, NULL, NULL, &wss->ad1848); + + sound_add_handler(wss_get_buffer, wss); + + return wss; +} + +void wss_close(void *p) +{ + wss_t *wss = (wss_t *)p; + + free(wss); +} + +void wss_speed_changed(void *p) +{ + wss_t *wss = (wss_t *)p; + + ad1848_speed_changed(&wss->ad1848); +} + +device_t wss_device = +{ + "Windows Sound System", + 0, + wss_init, + wss_close, + NULL, + wss_speed_changed, + NULL, + NULL +}; diff --git a/src/sound_wss.h b/src/sound_wss.h new file mode 100644 index 000000000..bd387d6f3 --- /dev/null +++ b/src/sound_wss.h @@ -0,0 +1 @@ +extern device_t wss_device; diff --git a/src/sound_ym7128.c b/src/sound_ym7128.c new file mode 100644 index 000000000..7c1aa06ff --- /dev/null +++ b/src/sound_ym7128.c @@ -0,0 +1,142 @@ +#include "ibm.h" +#include "sound_ym7128.h" + +static int attenuation[32]; +static int tap_position[32]; + +void ym7128_init(ym7128_t *ym7128) +{ + int c; + double out = 65536.0; + + for (c = 0; c < 32; c++) + tap_position[c] = c * (2400 / 31); + + for (c = 31; c >= 1; c--) + { + attenuation[c] = (int)out; + out /= 1.25963; /*2 dB steps*/ + } + attenuation[0] = 0; +} + +#define GET_ATTENUATION(val) (val & 0x20) ? -attenuation[val & 0x1f] : attenuation[val & 0x1f] + +void ym7128_write(ym7128_t *ym7128, uint8_t val) +{ + int new_dat = val & 1; + int new_sci = val & 2; + int new_a0 = val & 4; +// pclog("ym7128_write %i %i %i\n", new_dat, new_sci, new_a0); + if (!ym7128->sci && new_sci) + ym7128->dat = (ym7128->dat << 1) | new_dat; + + if (ym7128->a0 != new_a0) + { +// pclog("ym7128 write %i %02x\n", ym7128->a0, ym7128->dat); + if (!ym7128->a0) + ym7128->reg_sel = ym7128->dat & 0x1f; + else + { +// pclog("YM7128 write %02x %02x\n", ym7128->reg_sel, ym7128->dat); + switch (ym7128->reg_sel) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x04: case 0x05: case 0x06: case 0x07: + ym7128->gl[ym7128->reg_sel & 7] = GET_ATTENUATION(ym7128->dat); +// pclog(" GL[%i] = %04x\n", ym7128->reg_sel & 7, GET_ATTENUATION(ym7128->dat)); + break; + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + ym7128->gr[ym7128->reg_sel & 7] = GET_ATTENUATION(ym7128->dat); +// pclog(" GR[%i] = %04x\n", ym7128->reg_sel & 7, GET_ATTENUATION(ym7128->dat)); + break; + + case 0x10: + ym7128->vm = GET_ATTENUATION(ym7128->dat); +// pclog(" VM = %04x\n", GET_ATTENUATION(ym7128->dat)); + break; + case 0x11: + ym7128->vc = GET_ATTENUATION(ym7128->dat); +// pclog(" VC = %04x\n", GET_ATTENUATION(ym7128->dat)); + break; + case 0x12: + ym7128->vl = GET_ATTENUATION(ym7128->dat); +// pclog(" VL = %04x\n", GET_ATTENUATION(ym7128->dat)); + break; + case 0x13: + ym7128->vr = GET_ATTENUATION(ym7128->dat); +// pclog(" VR = %04x\n", GET_ATTENUATION(ym7128->dat)); + break; + + case 0x14: + ym7128->c0 = (ym7128->dat & 0x3f) << 6; + if (ym7128->dat & 0x20) + ym7128->c0 |= 0xfffff000; + break; + case 0x15: + ym7128->c1 = (ym7128->dat & 0x3f) << 6; + if (ym7128->dat & 0x20) + ym7128->c1 |= 0xfffff000; + break; + + case 0x16: case 0x17: case 0x18: case 0x19: + case 0x1a: case 0x1b: case 0x1c: case 0x1d: case 0x1e: + ym7128->t[ym7128->reg_sel - 0x16] = tap_position[ym7128->dat & 0x1f]; +// pclog(" T[%i] = %i\n", ym7128->reg_sel - 0x16, tap_position[ym7128->dat & 0x1f]); + break; + } + ym7128->regs[ym7128->reg_sel] = ym7128->dat; + } + ym7128->dat = 0; + } + + ym7128->sci = new_sci; + ym7128->a0 = new_a0; +} + +#define GET_DELAY_SAMPLE(ym7128, offset) (((ym7128->delay_pos - offset) < 0) ? ym7128->delay_buffer[(ym7128->delay_pos - offset) + 2400] : ym7128->delay_buffer[ym7128->delay_pos - offset]) + +void ym7128_apply(ym7128_t *ym7128, int16_t *buffer, int len) +{ + int c, d; + + for (c = 0; c < len*2; c += 4) + { + /*YM7128 samples a mono stream at ~24 kHz, so downsample*/ + int32_t samp = ((int32_t)buffer[c] + (int32_t)buffer[c+1] + (int32_t)buffer[c+2] + (int32_t)buffer[c+3]) / 4; + int32_t filter_temp, filter_out; + int32_t samp_l = 0, samp_r = 0; + + filter_temp = GET_DELAY_SAMPLE(ym7128, ym7128->t[0]); + filter_out = ((filter_temp * ym7128->c0) >> 11) + ((ym7128->filter_dat * ym7128->c1) >> 11); + filter_out = (filter_out * ym7128->vc) >> 16; + + samp = (samp * ym7128->vm) >> 16; + samp += filter_out; + + ym7128->delay_buffer[ym7128->delay_pos] = samp; + + for (d = 0; d < 8; d++) + { + samp_l += (GET_DELAY_SAMPLE(ym7128, ym7128->t[d+1]) * ym7128->gl[d]) >> 16; + samp_r += (GET_DELAY_SAMPLE(ym7128, ym7128->t[d+1]) * ym7128->gr[d]) >> 16; + } + + samp_l = (samp_l * ym7128->vl*2) >> 16; + samp_r = (samp_r * ym7128->vr*2) >> 16; + + buffer[c] += ((int32_t)samp_l + (int32_t)ym7128->prev_l) / 2; + buffer[c+1] += ((int32_t)samp_r + (int32_t)ym7128->prev_r) / 2; + buffer[c+2] += samp_l; + buffer[c+3] += samp_r; + + ym7128->delay_pos++; + if (ym7128->delay_pos >= 2400) + ym7128->delay_pos = 0; + + ym7128->filter_dat = filter_temp; + ym7128->prev_l = samp_l; + ym7128->prev_r = samp_r; + } +} diff --git a/src/sound_ym7128.h b/src/sound_ym7128.h new file mode 100644 index 000000000..f71aa2f86 --- /dev/null +++ b/src/sound_ym7128.h @@ -0,0 +1,25 @@ +typedef struct ym7128_t +{ + int a0, sci; + uint8_t dat; + + int reg_sel; + uint8_t regs[32]; + + int gl[8], gr[8]; + int vm, vc, vl, vr; + int c0, c1; + int t[9]; + + int16_t filter_dat; + int16_t prev_l, prev_r; + + int16_t delay_buffer[2400]; + int delay_pos; + + int16_t last_samp; +} ym7128_t; + +void ym7128_init(ym7128_t *ym7128); +void ym7128_write(ym7128_t *ym7128, uint8_t val); +void ym7128_apply(ym7128_t *ym7128, int16_t *buffer, int len); diff --git a/src/soundopenal.c b/src/soundopenal.c new file mode 100644 index 000000000..78f81ed87 --- /dev/null +++ b/src/soundopenal.c @@ -0,0 +1,257 @@ +#define USE_OPENAL +#include +#include +#include +#ifdef USE_OPENAL +#include +#include +#endif +#include "ibm.h" +#include "sound.h" + +FILE *allog; +#ifdef USE_OPENAL +ALuint buffers[4]; // front and back buffers +ALuint buffers_cd[4]; // front and back buffers +static ALuint source[2]; // audio source +#endif +#define FREQ 48000 +#define BUFLEN SOUNDBUFLEN + +void closeal(); +ALvoid alutInit(ALint *argc,ALbyte **argv) +{ + ALCcontext *Context; + ALCdevice *Device; + + //Open device + Device=alcOpenDevice((ALubyte*)""); + //Create context(s) + Context=alcCreateContext(Device,NULL); + //Set active context + alcMakeContextCurrent(Context); + //Register extensions +} + +ALvoid alutExit(ALvoid) +{ + ALCcontext *Context; + ALCdevice *Device; + + //Unregister extensions + + //Get active context + Context=alcGetCurrentContext(); + //Get device for active context + Device=alcGetContextsDevice(Context); + //Disable context + alcMakeContextCurrent(NULL); + //Release context(s) + alcDestroyContext(Context); + //Close device + alcCloseDevice(Device); +} +void initalmain(int argc, char *argv[]) +{ +#ifdef USE_OPENAL + alutInit(0,0); +// printf("AlutInit\n"); + atexit(closeal); +// printf("AlutInit\n"); +#endif +} + +void closeal() +{ +#ifdef USE_OPENAL + alutExit(); +#endif +} + +void check() +{ +#ifdef USE_OPENAL + ALenum error; + if ((error = alGetError()) != AL_NO_ERROR) + { +// printf("Error : %08X\n", error); +// exit(-1); + } +#endif +} + +void inital() +{ +#ifdef USE_OPENAL + int c; + int16_t buf[BUFLEN*2]; + +// printf("1\n"); + check(); + +// printf("2\n"); + alGenBuffers(4, buffers); + check(); + alGenBuffers(4, buffers_cd); + check(); + +// printf("3\n"); + alGenSources(2, source); + check(); + +// printf("4\n"); + alSource3f(source[0], AL_POSITION, 0.0, 0.0, 0.0); + alSource3f(source[0], AL_VELOCITY, 0.0, 0.0, 0.0); + alSource3f(source[0], AL_DIRECTION, 0.0, 0.0, 0.0); + alSourcef (source[0], AL_ROLLOFF_FACTOR, 0.0 ); + alSourcei (source[0], AL_SOURCE_RELATIVE, AL_TRUE ); + check(); + alSource3f(source[1], AL_POSITION, 0.0, 0.0, 0.0); + alSource3f(source[1], AL_VELOCITY, 0.0, 0.0, 0.0); + alSource3f(source[1], AL_DIRECTION, 0.0, 0.0, 0.0); + alSourcef (source[1], AL_ROLLOFF_FACTOR, 0.0 ); + alSourcei (source[1], AL_SOURCE_RELATIVE, AL_TRUE ); + check(); + + memset(buf,0,BUFLEN*4); + +// printf("5\n"); + for (c = 0; c < 4; c++) + { + alBufferData(buffers[c], AL_FORMAT_STEREO16, buf, BUFLEN*2*2, FREQ); + alBufferData(buffers_cd[c], AL_FORMAT_STEREO16, buf, CD_BUFLEN*2*2, CD_FREQ); + } + + alSourceQueueBuffers(source[0], 4, buffers); + check(); + alSourceQueueBuffers(source[1], 4, buffers_cd); + check(); +// printf("6 %08X\n",source); + alSourcePlay(source[0]); + check(); + alSourcePlay(source[1]); + check(); +// printf("InitAL!!! %08X\n",source); +#endif +} + +void givealbuffer(int32_t *buf) +{ +#ifdef USE_OPENAL + int16_t buf16[BUFLEN*2]; + int processed; + int state; + + //return; + +// printf("Start\n"); + check(); + +// printf("GiveALBuffer %08X\n",source); + + alGetSourcei(source[0], AL_SOURCE_STATE, &state); + + check(); + + if (state==0x1014) + { + alSourcePlay(source[0]); +// printf("Resetting sound\n"); + } +// printf("State - %i %08X\n",state,state); + alGetSourcei(source[0], AL_BUFFERS_PROCESSED, &processed); + +// printf("P "); + check(); +// printf("Processed - %i\n",processed); + + if (processed>=1) + { + int c; + ALuint buffer; + + alSourceUnqueueBuffers(source[0], 1, &buffer); +// printf("U "); + check(); + + for (c=0;c 32767) + buf16[c] = 32767; + else + buf16[c] = buf[c]; + } +// for (c=0;c=1) + { + ALuint buffer; + + alSourceUnqueueBuffers(source[1], 1, &buffer); +// printf("U "); + check(); + +// for (c=0;c +#include "ibm.h" +#include "device.h" +#include "tandy_eeprom.h" + +typedef struct +{ + int state; + int count; + int addr; + int clock; + uint16_t data; + uint16_t store[64]; + + int romset; +} tandy_eeprom_t; + +enum +{ + EEPROM_IDLE, + EEPROM_GET_OPERATION, + EEPROM_READ, + EEPROM_WRITE +}; + +static int eeprom_data_out; + +void tandy_eeprom_write(uint16_t addr, uint8_t val, void *p) +{ + tandy_eeprom_t *eeprom = (tandy_eeprom_t *)p; + + if ((val & 4) && !eeprom->clock) + { +// pclog("eeprom_write %02x %i %i\n", val, eeprom->state, eeprom->count); + switch (eeprom->state) + { + case EEPROM_IDLE: + switch (eeprom->count) + { + case 0: + if (!(val & 3)) + eeprom->count = 1; + else + eeprom->count = 0; + break; + case 1: + if ((val & 3) == 2) + eeprom->count = 2; + else + eeprom->count = 0; + break; + case 2: + if ((val & 3) == 3) + eeprom->state = EEPROM_GET_OPERATION; + eeprom->count = 0; + break; + } + break; + case EEPROM_GET_OPERATION: + eeprom->data = (eeprom->data << 1) | (val & 1); + eeprom->count++; + if (eeprom->count == 8) + { + eeprom->count = 0; +// pclog("EEPROM get operation %02x\n", eeprom->data); + eeprom->addr = eeprom->data & 0x3f; + switch (eeprom->data & 0xc0) + { + case 0x40: + eeprom->state = EEPROM_WRITE; + break; + case 0x80: + eeprom->state = EEPROM_READ; + eeprom->data = eeprom->store[eeprom->addr]; +// pclog("EEPROM read data %02x %04x\n", eeprom->addr, eeprom->data); + break; + default: + eeprom->state = EEPROM_IDLE; + break; + } + } + break; + + case EEPROM_READ: + eeprom_data_out = eeprom->data & 0x8000; + eeprom->data <<= 1; + eeprom->count++; + if (eeprom->count == 16) + { + eeprom->count = 0; + eeprom->state = EEPROM_IDLE; + } + break; + case EEPROM_WRITE: + eeprom->data = (eeprom->data << 1) | (val & 1); + eeprom->count++; + if (eeprom->count == 16) + { + eeprom->count = 0; + eeprom->state = EEPROM_IDLE; +// pclog("EEPROM write %04x to %02x\n", eeprom->data, eeprom->addr); + eeprom->store[eeprom->addr] = eeprom->data; + } + break; + } + } + + eeprom->clock = val & 4; +} + +int tandy_eeprom_read() +{ +// pclog("tandy_eeprom_read: data_out=%x\n", eeprom_data_out); + return eeprom_data_out; +} + +void *tandy_eeprom_init() +{ + tandy_eeprom_t *eeprom = malloc(sizeof(tandy_eeprom_t)); + FILE *f; + + memset(eeprom, 0, sizeof(tandy_eeprom_t)); + + eeprom->romset = romset; + switch (romset) + { + case ROM_TANDY1000HX: + f = romfopen("nvr/tandy1000hx.bin" ,"rb"); + break; + case ROM_TANDY1000SL2: + f = romfopen("nvr/tandy1000sl2.bin" ,"rb"); + break; + } + if (f) + { + fread(eeprom->store, 128, 1, f); + fclose(f); + } + else + memset(eeprom->store, 0, 128); + + io_sethandler(0x037c, 0x0001, NULL, NULL, NULL, tandy_eeprom_write, NULL, NULL, eeprom); + + return eeprom; +} + +void tandy_eeprom_close(void *p) +{ + tandy_eeprom_t *eeprom = (tandy_eeprom_t *)p; + FILE *f; + + switch (eeprom->romset) + { + case ROM_TANDY1000HX: + f = romfopen("nvr/tandy1000hx.bin" ,"wb"); + break; + case ROM_TANDY1000SL2: + f = romfopen("nvr/tandy1000sl2.bin" ,"wb"); + break; + } + fwrite(eeprom->store, 128, 1, f); + fclose(f); + + free(eeprom); +} + +device_t tandy_eeprom_device = +{ + "Tandy EEPROM", + 0, + tandy_eeprom_init, + tandy_eeprom_close, + NULL, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/tandy_eeprom.h b/src/tandy_eeprom.h new file mode 100644 index 000000000..c129050c8 --- /dev/null +++ b/src/tandy_eeprom.h @@ -0,0 +1,2 @@ +device_t tandy_eeprom_device; +int tandy_eeprom_read(); diff --git a/src/tandy_rom.c b/src/tandy_rom.c new file mode 100644 index 000000000..f95ca0dfb --- /dev/null +++ b/src/tandy_rom.c @@ -0,0 +1,94 @@ +#include +#include "ibm.h" +#include "device.h" +#include "mem.h" +#include "tandy_rom.h" + +static uint8_t *tandy_rom; +static uint8_t tandy_rom_bank; +static int tandy_rom_offset; +static mem_mapping_t tandy_rom_mapping; + +uint8_t tandy_read_rom(uint32_t addr, void *p) +{ + uint32_t addr2 = (addr & 0xffff) + tandy_rom_offset; +// if (!nopageerrors) pclog("tandy_read_rom: %05x %05x %02x %04x:%04x\n", addr, addr2, tandy_rom[addr2], CS,pc); + return tandy_rom[addr2]; +} +uint16_t tandy_read_romw(uint32_t addr, void *p) +{ + uint32_t addr2 = (addr & 0xffff) + tandy_rom_offset; +// if (!nopageerrors) pclog("tandy_read_romw: %05x %05x %04x %04x:%04x\n", addr, addr2, *(uint16_t *)&tandy_rom[addr2], CS,pc); + return *(uint16_t *)&tandy_rom[addr2]; +} +uint32_t tandy_read_roml(uint32_t addr, void *p) +{ + uint32_t addr2 = (addr & 0xffff) + tandy_rom_offset; +// if (!nopageerrors) pclog("tandy_read_roml: %05x %05x %08x\n", addr, addr2, *(uint32_t *)&tandy_rom[addr2]); + return *(uint32_t *)&tandy_rom[addr]; +} + +uint8_t tandy_rom_bank_read(uint16_t port, void *p) +{ + if (port == 0xffea) + return tandy_rom_bank ^ 0x10; + else + return 0xff; +} +void tandy_rom_bank_write(uint16_t port, uint8_t val, void *p) +{ + if (port == 0xffea) + { + tandy_rom_bank = val; + tandy_rom_offset = ((val ^ 4) & 7) * 0x10000; + mem_mapping_set_exec(&tandy_rom_mapping, &tandy_rom[tandy_rom_offset]); +// pclog("tandy_rom_bank_write: port=%04x val=%02x offset=%05x\n", port, val, tandy_rom_offset); + } +// else +// pclog("Bad tandy write port=%04x val=%02x\n", port, val); +} + +void *tandy_rom_init() +{ + FILE *f, *ff; + int c; + + tandy_rom = malloc(0x80000); + + f = romfopen("roms/tandy1000sl2/8079047.hu1" ,"rb"); + ff = romfopen("roms/tandy1000sl2/8079048.hu2","rb"); + for (c = 0x0000; c < 0x80000; c += 2) + { + tandy_rom[c] = getc(f); + tandy_rom[c + 1] = getc(ff); + } + fclose(ff); + fclose(f); + + mem_mapping_add(&tandy_rom_mapping, 0xe0000, 0x10000, + tandy_read_rom, tandy_read_romw, tandy_read_roml, + NULL, NULL, NULL, + tandy_rom, MEM_MAPPING_EXTERNAL, NULL); + + io_sethandler(0xffe8, 0x0008, tandy_rom_bank_read, NULL, NULL, tandy_rom_bank_write, NULL, NULL, NULL); + + return tandy_rom; +} + +void tandy_rom_close(void *p) +{ + free(p); +} + +device_t tandy_rom_device = +{ + "Tandy 1000SL/2 ROM", + 0, + tandy_rom_init, + tandy_rom_close, + NULL, + NULL, + NULL, + NULL, + NULL +}; diff --git a/src/tandy_rom.h b/src/tandy_rom.h new file mode 100644 index 000000000..4dfbb3e71 --- /dev/null +++ b/src/tandy_rom.h @@ -0,0 +1 @@ +extern device_t tandy_rom_device; diff --git a/src/thread-pthread.c b/src/thread-pthread.c new file mode 100644 index 000000000..3a9a185db --- /dev/null +++ b/src/thread-pthread.c @@ -0,0 +1,89 @@ +#include +#include +#include +#include +#include "thread.h" + +typedef struct event_pthread_t +{ + pthread_cond_t cond; + pthread_mutex_t mutex; +} event_pthread_t; + +thread_t *thread_create(void (*thread_rout)(void *param), void *param) +{ + pthread_t *thread = malloc(sizeof(pthread_t)); + + pthread_create(thread, NULL, thread_rout, param); + + return thread; +} + +void thread_kill(thread_t *handle) +{ + pthread_t *thread = (pthread_t *)handle; + + pthread_cancel(*thread); + pthread_join(*thread, NULL); + + free(thread); +} + +event_t *thread_create_event() +{ + event_pthread_t *event = malloc(sizeof(event_pthread_t)); + + pthread_cond_init(&event->cond, NULL); + pthread_mutex_init(&event->mutex, NULL); + + return (event_t *)event; +} + +void thread_set_event(event_t *handle) +{ + event_pthread_t *event = (event_pthread_t *)handle; + + pthread_mutex_lock(&event->mutex); + pthread_cond_broadcast(&event->cond); + pthread_mutex_unlock(&event->mutex); +} + +void thread_reset_event(event_t *handle) +{ +} + +int thread_wait_event(event_t *handle, int timeout) +{ + event_pthread_t *event = (event_pthread_t *)handle; + struct timespec abstime; + + clock_gettime(CLOCK_REALTIME, &abstime); + abstime.tv_nsec += (timeout % 1000) * 1000000; + abstime.tv_sec += (timeout / 1000); + if (abstime.tv_nsec > 1000000000) + { + abstime.tv_nsec -= 1000000000; + abstime.tv_sec++; + } + + pthread_mutex_lock(&event->mutex); + pthread_cond_timedwait(&event->cond, &event->mutex, &abstime); + pthread_mutex_unlock(&event->mutex); + + return 0; +} + +void thread_destroy_event(event_t *handle) +{ + event_pthread_t *event = (event_pthread_t *)handle; + + pthread_cond_destroy(&event->cond); + pthread_mutex_destroy(&event->mutex); + + free(event); +} + +void thread_sleep(int t) +{ + usleep(t * 1000); +} diff --git a/src/thread.h b/src/thread.h new file mode 100644 index 000000000..815b4f049 --- /dev/null +++ b/src/thread.h @@ -0,0 +1,12 @@ +typedef void thread_t; +thread_t *thread_create(void (*thread_rout)(void *param), void *param); +void thread_kill(thread_t *handle); + +typedef void event_t; +event_t *thread_create_event(); +void thread_set_event(event_t *event); +void thread_reset_event(event_t *_event); +int thread_wait_event(event_t *event, int timeout); +void thread_destroy_event(event_t *_event); + +void thread_sleep(int t); diff --git a/src/timer.c b/src/timer.c new file mode 100644 index 000000000..45268869e --- /dev/null +++ b/src/timer.c @@ -0,0 +1,118 @@ +#include "ibm.h" + +/*#include "sound_opl.h" +#include "adlibgold.h" +#include "sound_pas16.h" +#include "sound_sb.h" +#include "sound_sb_dsp.h" +#include "sound_wss.h"*/ +#include "timer.h" + +#define TIMERS_MAX 32 + +int TIMER_USEC; + +static struct +{ + int present; + void (*callback)(void *priv); + void *priv; + int *enable; + int *count; +} timers[TIMERS_MAX]; + +int timers_present = 0; +int timer_one = 1; + +int timer_count = 0, timer_latch = 0; +int timer_start = 0; + +void timer_process() +{ + int c; + int retry; + int process = 0; + /*Get actual elapsed time*/ + int diff = timer_latch - timer_count; + int enable[TIMERS_MAX]; + + timer_latch = 0; + + for (c = 0; c < timers_present; c++) + { + enable[c] = *timers[c].enable; + if (*timers[c].enable) + { + *timers[c].count = *timers[c].count - diff; + if (*timers[c].count <= 0) + process = 1; + } + } + + if (!process) + return; + + while (1) + { + int lowest = 1, lowest_c; + + for (c = 0; c < timers_present; c++) + { + if (enable[c]) + { + if (*timers[c].count < lowest) + { + lowest = *timers[c].count; + lowest_c = c; + } + } + } + + if (lowest > 0) + break; + + timers[lowest_c].callback(timers[lowest_c].priv); + enable[lowest_c] = *timers[lowest_c].enable; + } +} + +void timer_update_outstanding() +{ + int c; + timer_latch = 0x7fffffff; + for (c = 0; c < timers_present; c++) + { + if (*timers[c].enable && *timers[c].count < timer_latch) + timer_latch = *timers[c].count; + } + timer_count = timer_latch = (timer_latch + ((1 << TIMER_SHIFT) - 1)) >> TIMER_SHIFT; +} + +void timer_reset() +{ + pclog("timer_reset\n"); + timers_present = 0; + timer_latch = timer_count = 0; +// timer_process(); +} + +int timer_add(void (*callback)(void *priv), int *count, int *enable, void *priv) +{ + if (timers_present < TIMERS_MAX) + { +// pclog("timer_add : adding timer %i\n", timers_present); + timers[timers_present].present = 1; + timers[timers_present].callback = callback; + timers[timers_present].priv = priv; + timers[timers_present].count = count; + timers[timers_present].enable = enable; + timers_present++; + return timers_present - 1; + } + return -1; +} + +void timer_set_callback(int timer, void (*callback)(void *priv)) +{ + timers[timer].callback = callback; +} diff --git a/src/timer.h b/src/timer.h new file mode 100644 index 000000000..50c83e55c --- /dev/null +++ b/src/timer.h @@ -0,0 +1,58 @@ +#ifndef _TIMER_H_ +#define _TIMER_H_ + +#include "cpu.h" + +extern int timer_start; + +#define timer_start_period(cycles) \ + timer_start = cycles; + +#define timer_end_period(cycles) \ + do \ + { \ + int diff = timer_start - (cycles); \ + timer_count -= diff; \ + timer_start = cycles; \ + if (timer_count <= 0) \ + { \ + timer_process(); \ + timer_update_outstanding(); \ + } \ + } while (0) + +#define timer_clock() \ + do \ + { \ + int diff; \ + if (AT) \ + { \ + diff = timer_start - (cycles << TIMER_SHIFT); \ + timer_start = cycles << TIMER_SHIFT; \ + } \ + else \ + { \ + diff = timer_start - (cycles * xt_cpu_multi); \ + timer_start = cycles * xt_cpu_multi; \ + } \ + timer_count -= diff; \ + timer_process(); \ + timer_update_outstanding(); \ + } while (0) + +void timer_process(); +void timer_update_outstanding(); +void timer_reset(); +int timer_add(void (*callback)(void *priv), int *count, int *enable, void *priv); +void timer_set_callback(int timer, void (*callback)(void *priv)); + +#define TIMER_ALWAYS_ENABLED &timer_one + +extern int timer_count; +extern int timer_one; + +#define TIMER_SHIFT 6 + +extern int TIMER_USEC; + +#endif /*_TIMER_H_*/ diff --git a/src/um8669f.c b/src/um8669f.c new file mode 100644 index 000000000..85d527cff --- /dev/null +++ b/src/um8669f.c @@ -0,0 +1,137 @@ +/*um8669f : + + aa to 108 unlocks + next 108 write is register select (Cx?) + data read/write to 109 + 55 to 108 locks + + + + +C0 +bit 3 = LPT1 enable +bit 2 = COM2 enable +bit 1 = COM1 enable +bit 0 = FDC enable + +C1 +bits 7-6 = LPT1 mode : 11 = ECP/EPP, 01 = EPP, 10 = SPP +bit 3 = clear when LPT1 = 278 + +C3 +bits 7-6 = LPT1 DMA mode : 11 = ECP/EPP DMA1, 10 = ECP/EPP DMA3, 01 = EPP/SPP, 00 = ECP +bits 5-4 = LPT1 addr : 10 = 278/IRQ5, 01 = 3BC/IRQ7, 00 = 378/IRQ7 + +COM1 : +3f8, IRQ4 - C1 = BF, C3 = 00 +2f8, IRQ3 - C1 = BF, C3 = 03 +3e8, IRQ4 - C1 = BD, C3 = 00 +2e8, IRQ3 - B1 = BD, C3 = 03 + +COM2 : +3f8, IRQ4 - C1 = BF, C3 = 0C +2f8, IRQ3 - C1 = BF, C3 = 00 +3e8, IRQ4 - C1 = BB, C3 = 0C +2e8, IRQ3 - C1 = BB, C3 = 00 + + */ + +#include "ibm.h" + +#include "fdc.h" +#include "io.h" +#include "lpt.h" +#include "mouse_serial.h" +#include "serial.h" +#include "um8669f.h" + +static int um8669f_locked; +static int um8669f_curreg; +static uint8_t um8669f_regs[256]; + +void um8669f_write(uint16_t port, uint8_t val, void *priv) +{ + int temp; +// pclog("um8669f_write : port=%04x reg %02X = %02X locked=%i\n", port, um8669f_curreg, val, um8669f_locked); + if (um8669f_locked) + { + if (port == 0x108 && val == 0xaa) + um8669f_locked = 0; + } + else + { + if (port == 0x108) + { + if (val == 0x55) + um8669f_locked = 1; + else + um8669f_curreg = val; + } + else + { + um8669f_regs[um8669f_curreg] = val; + + fdc_remove(); + if (um8669f_regs[0xc0] & 1) + fdc_add(); + + if (um8669f_regs[0xc0] & 2) + { + temp = um8669f_regs[0xc3] & 1; /*might be & 2*/ + if (!(um8669f_regs[0xc1] & 2)) + temp |= 2; + switch (temp) + { + case 0: serial1_set(0x3f8, 4); break; + case 1: serial1_set(0x2f8, 4); break; + case 2: serial1_set(0x3e8, 4); break; + case 3: serial1_set(0x2e8, 4); break; + } + } + + if (um8669f_regs[0xc0] & 4) + { + temp = (um8669f_regs[0xc3] & 4) ? 0 : 1; /*might be & 8*/ + if (!(um8669f_regs[0xc1] & 4)) + temp |= 2; + switch (temp) + { + case 0: serial2_set(0x3f8, 3); break; + case 1: serial2_set(0x2f8, 3); break; + case 2: serial2_set(0x3e8, 3); break; + case 3: serial2_set(0x2e8, 3); break; + } + } + + mouse_serial_init(); + + lpt1_remove(); + lpt2_remove(); + temp = (um8669f_regs[0xc3] >> 4) & 3; + switch (temp) + { + case 0: lpt1_init(0x378); break; + case 1: lpt1_init(0x3bc); break; + case 2: lpt1_init(0x278); break; + } + } + } +} + +uint8_t um8669f_read(uint16_t port, void *priv) +{ +// pclog("um8669f_read : port=%04x reg %02X locked=%i\n", port, um8669f_curreg, um8669f_locked); + if (um8669f_locked) + return 0xff; + + if (port == 0x108) + return um8669f_curreg; /*???*/ + else + return um8669f_regs[um8669f_curreg]; +} + +void um8669f_init() +{ + io_sethandler(0x0108, 0x0002, um8669f_read, NULL, NULL, um8669f_write, NULL, NULL, NULL); + um8669f_locked = 1; +} diff --git a/src/um8669f.h b/src/um8669f.h new file mode 100644 index 000000000..409ad51c2 --- /dev/null +++ b/src/um8669f.h @@ -0,0 +1 @@ +extern void um8669f_init(); diff --git a/src/um8881f.c b/src/um8881f.c new file mode 100644 index 000000000..29f89630f --- /dev/null +++ b/src/um8881f.c @@ -0,0 +1,70 @@ +#include "ibm.h" +#include "io.h" +#include "mem.h" +#include "pci.h" + +#include "um8881f.h" + +static uint8_t card_16[256]; +static uint8_t card_18[256]; + +void um8881f_write(int func, int addr, uint8_t val, void *priv) +{ +// pclog("um8881f_write : addr=%02x val=%02x %04x:%04x\n", addr, val, CS, pc); + if (addr == 0x54) + { +/* if ((card_16[0x54] ^ val) & 0x01) + { + if (val & 1) + mem_bios_set_state(0xe0000, 0x10000, 1, 1); + else + mem_bios_set_state(0xe0000, 0x10000, 0, 0); + }*/ + flushmmucache_nopc(); + } + if (addr == 0x55) + { + if ((card_16[0x55] ^ val) & 0xc0) + { +/* switch (val & 0xc0) + { + case 0x00: mem_bios_set_state(0xf0000, 0x10000, 0, 1); break; + case 0x40: mem_bios_set_state(0xf0000, 0x10000, 0, 0); break; + case 0x80: mem_bios_set_state(0xf0000, 0x10000, 1, 1); break; + case 0xc0: mem_bios_set_state(0xf0000, 0x10000, 1, 0); break; + }*/ + shadowbios = val & 0x80; + shadowbios_write = !(val & 0x40); + flushmmucache_nopc(); + } + } + if (addr >= 4) + card_16[addr] = val; +} + +uint8_t um8881f_read(int func, int addr, void *priv) +{ + return card_16[addr]; +} + +void um8886f_write(int func, int addr, uint8_t val, void *priv) +{ + if (addr >= 4) + card_18[addr] = val; +} + +uint8_t um8886f_read(int func, int addr, void *priv) +{ + return card_18[addr]; +} + +void um8881f_init() +{ + pci_add_specific(16, um8881f_read, um8881f_write, NULL); + pci_add_specific(18, um8886f_read, um8886f_write, NULL); + + card_16[0] = card_18[0] = 0x60; /*UMC*/ + card_16[1] = card_18[1] = 0x10; + card_16[2] = 0x81; card_16[3] = 0x88; /*UM8881 Host - PCI bridge*/ + card_18[2] = 0x86; card_18[3] = 0x88; /*UM8886 PCI - ISA bridge*/ +} diff --git a/src/um8881f.h b/src/um8881f.h new file mode 100644 index 000000000..7411a742f --- /dev/null +++ b/src/um8881f.h @@ -0,0 +1 @@ +void um8881f_init(); diff --git a/src/vid_ati18800.c b/src/vid_ati18800.c new file mode 100644 index 000000000..cf8003ef1 --- /dev/null +++ b/src/vid_ati18800.c @@ -0,0 +1,199 @@ +/*ATI 18800 emulation (VGA Edge-16)*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "video.h" +#include "vid_ati18800.h" +#include "vid_ati_eeprom.h" +#include "vid_svga.h" + +typedef struct ati18800_t +{ + svga_t svga; + ati_eeprom_t eeprom; + + rom_t bios_rom; + + uint8_t regs[256]; + int index; +} ati18800_t; + +void ati18800_out(uint16_t addr, uint8_t val, void *p) +{ + ati18800_t *ati18800 = (ati18800_t *)p; + svga_t *svga = &ati18800->svga; + uint8_t old; + +// pclog("ati18800_out : %04X %02X %04X:%04X\n", addr, val, CS,cpu_state.pc); + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) addr ^= 0x60; + + switch (addr) + { + case 0x1ce: + ati18800->index = val; + break; + case 0x1cf: + ati18800->regs[ati18800->index] = val; + switch (ati18800->index) + { + case 0xb2: + case 0xbe: + if (ati18800->regs[0xbe] & 8) /*Read/write bank mode*/ + { + svga->read_bank = ((ati18800->regs[0xb2] >> 5) & 7) * 0x10000; + svga->write_bank = ((ati18800->regs[0xb2] >> 1) & 7) * 0x10000; + } + else /*Single bank mode*/ + svga->read_bank = svga->write_bank = ((ati18800->regs[0xb2] >> 1) & 7) * 0x10000; + break; + case 0xb3: + ati_eeprom_write(&ati18800->eeprom, val & 8, val & 2, val & 1); + break; + } + break; + + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if (svga->crtcreg <= 0x18) + val &= mask_crtc[svga->crtcreg]; + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t ati18800_in(uint16_t addr, void *p) +{ + ati18800_t *ati18800 = (ati18800_t *)p; + svga_t *svga = &ati18800->svga; + uint8_t temp; + +// if (addr != 0x3da) pclog("ati18800_in : %04X ", addr); + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) addr ^= 0x60; + + switch (addr) + { + case 0x1ce: + temp = ati18800->index; + break; + case 0x1cf: + switch (ati18800->index) + { + case 0xb7: + temp = ati18800->regs[ati18800->index] & ~8; + if (ati_eeprom_read(&ati18800->eeprom)) + temp |= 8; + break; + + default: + temp = ati18800->regs[ati18800->index]; + break; + } + break; + + case 0x3D4: + temp = svga->crtcreg; + break; + case 0x3D5: + temp = svga->crtc[svga->crtcreg]; + break; + default: + temp = svga_in(addr, svga); + break; + } +#ifndef RELEASE_BUILD + if (addr != 0x3da) pclog("%02X %04X:%04X\n", temp, CS,cpu_state.pc); +#endif + return temp; +} + +void *ati18800_init() +{ + ati18800_t *ati18800 = malloc(sizeof(ati18800_t)); + memset(ati18800, 0, sizeof(ati18800_t)); + + rom_init(&ati18800->bios_rom, "roms/vgaedge16.vbi", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + svga_init(&ati18800->svga, ati18800, 1 << 19, /*512kb*/ + NULL, + ati18800_in, ati18800_out, + NULL, + NULL); + + io_sethandler(0x01ce, 0x0002, ati18800_in, NULL, NULL, ati18800_out, NULL, NULL, ati18800); + io_sethandler(0x03c0, 0x0020, ati18800_in, NULL, NULL, ati18800_out, NULL, NULL, ati18800); + + ati18800->svga.miscout = 1; + + ati_eeprom_load(&ati18800->eeprom, "ati18800.nvr", 0); + + return ati18800; +} + +static int ati18800_available() +{ + return rom_present("roms/vgaedge16.vbi"); +} + +void ati18800_close(void *p) +{ + ati18800_t *ati18800 = (ati18800_t *)p; + + svga_close(&ati18800->svga); + + free(ati18800); +} + +void ati18800_speed_changed(void *p) +{ + ati18800_t *ati18800 = (ati18800_t *)p; + + svga_recalctimings(&ati18800->svga); +} + +void ati18800_force_redraw(void *p) +{ + ati18800_t *ati18800 = (ati18800_t *)p; + + ati18800->svga.fullchange = changeframecount; +} + +void ati18800_add_status_info(char *s, int max_len, void *p) +{ + ati18800_t *ati18800 = (ati18800_t *)p; + + svga_add_status_info(s, max_len, &ati18800->svga); +} + +device_t ati18800_device = +{ + "ATI-18800", + 0, + ati18800_init, + ati18800_close, + ati18800_available, + ati18800_speed_changed, + ati18800_force_redraw, + ati18800_add_status_info +}; + diff --git a/src/vid_ati18800.h b/src/vid_ati18800.h new file mode 100644 index 000000000..6cdd2366b --- /dev/null +++ b/src/vid_ati18800.h @@ -0,0 +1 @@ +extern device_t ati18800_device; diff --git a/src/vid_ati28800.c b/src/vid_ati28800.c new file mode 100644 index 000000000..aa7a33afd --- /dev/null +++ b/src/vid_ati28800.c @@ -0,0 +1,279 @@ +/*ATI 28800 emulation (VGA Charger)*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "video.h" +#include "vid_ati28800.h" +#include "vid_ati_eeprom.h" +#include "vid_svga.h" +#include "vid_svga_render.h" + +typedef struct ati28800_t +{ + svga_t svga; + ati_eeprom_t eeprom; + + rom_t bios_rom; + + uint8_t regs[256]; + int index; +} ati28800_t; + +void ati28800_out(uint16_t addr, uint8_t val, void *p) +{ + ati28800_t *ati28800 = (ati28800_t *)p; + svga_t *svga = &ati28800->svga; + uint8_t old; + +// pclog("ati28800_out : %04X %02X %04X:%04X\n", addr, val, CS,cpu_state.pc); + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) + addr ^= 0x60; + + switch (addr) + { + case 0x1ce: + ati28800->index = val; + break; + case 0x1cf: + ati28800->regs[ati28800->index] = val; + switch (ati28800->index) + { + case 0xb2: + case 0xbe: + if (ati28800->regs[0xbe] & 8) /*Read/write bank mode*/ + { + svga->read_bank = ((ati28800->regs[0xb2] >> 5) & 7) * 0x10000; + svga->write_bank = ((ati28800->regs[0xb2] >> 1) & 7) * 0x10000; + } + else /*Single bank mode*/ + svga->read_bank = svga->write_bank = ((ati28800->regs[0xb2] >> 1) & 7) * 0x10000; + break; + case 0xb3: + ati_eeprom_write(&ati28800->eeprom, val & 8, val & 2, val & 1); + break; + } + break; + + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if (svga->crtcreg <= 0x18) + val &= mask_crtc[svga->crtcreg]; + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t ati28800_in(uint16_t addr, void *p) +{ + ati28800_t *ati28800 = (ati28800_t *)p; + svga_t *svga = &ati28800->svga; + uint8_t temp; + +// if (addr != 0x3da) pclog("ati28800_in : %04X ", addr); + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) addr ^= 0x60; + + switch (addr) + { + case 0x1ce: + temp = ati28800->index; + break; + case 0x1cf: + switch (ati28800->index) + { + case 0xb7: + temp = ati28800->regs[ati28800->index] & ~8; + if (ati_eeprom_read(&ati28800->eeprom)) + temp |= 8; + break; + + default: + temp = ati28800->regs[ati28800->index]; + break; + } + break; + + case 0x3c2: + if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x50) + temp = 0; + else + temp = 0x10; + break; + case 0x3D4: + temp = svga->crtcreg; + break; + case 0x3D5: + temp = svga->crtc[svga->crtcreg]; + break; + default: + temp = svga_in(addr, svga); + break; + } +#ifndef RELEASE_BUILD + if (addr != 0x3da) pclog("%02X %04X:%04X\n", temp, CS,cpu_state.pc); +#endif + return temp; +} + +void ati28800_recalctimings(svga_t *svga) +{ + ati28800_t *ati28800 = (ati28800_t *)svga->p; +#ifndef RELEASE_BUILD + pclog("ati28800_recalctimings\n"); +#endif + if (!svga->scrblank && (ati28800->regs[0xb0] & 0x20)) /*Extended 256 colour modes*/ + { +#ifndef RELEASE_BUILD + pclog("8bpp_highres\n"); +#endif + svga->render = svga_render_8bpp_highres; + svga->rowoffset <<= 1; + svga->ma <<= 1; + } +} + +void *ati28800_init() +{ + uint32_t memory = 512; + if (gfxcard == GFX_VGAWONDERXL) device_get_config_int("memory"); + memory <<= 10; + ati28800_t *ati28800 = malloc(sizeof(ati28800_t)); + memset(ati28800, 0, sizeof(ati28800_t)); + + if (gfxcard == GFX_VGAWONDERXL) + { + rom_init_interleaved(&ati28800->bios_rom, + "roms/XLEVEN.BIN", + "roms/XLODD.BIN", + 0xc0000, 0x10000, 0xffff, 0, MEM_MAPPING_EXTERNAL); + } + else + rom_init(&ati28800->bios_rom, "roms/bios.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + svga_init(&ati28800->svga, ati28800, memory, /*512kb*/ + ati28800_recalctimings, + ati28800_in, ati28800_out, + NULL, + NULL); + + io_sethandler(0x01ce, 0x0002, ati28800_in, NULL, NULL, ati28800_out, NULL, NULL, ati28800); + io_sethandler(0x03c0, 0x0020, ati28800_in, NULL, NULL, ati28800_out, NULL, NULL, ati28800); + + ati28800->svga.miscout = 1; + + ati_eeprom_load(&ati28800->eeprom, "ati28800.nvr", 0); + + return ati28800; +} + +static int ati28800_available() +{ + return rom_present("roms/bios.bin"); +} + +static int compaq_ati28800_available() +{ + return (rom_present("roms/XLEVEN.bin") && rom_present("roms/XLODD.bin")); +} + +void ati28800_close(void *p) +{ + ati28800_t *ati28800 = (ati28800_t *)p; + + svga_close(&ati28800->svga); + + free(ati28800); +} + +void ati28800_speed_changed(void *p) +{ + ati28800_t *ati28800 = (ati28800_t *)p; + + svga_recalctimings(&ati28800->svga); +} + +void ati28800_force_redraw(void *p) +{ + ati28800_t *ati28800 = (ati28800_t *)p; + + ati28800->svga.fullchange = changeframecount; +} + +void ati28800_add_status_info(char *s, int max_len, void *p) +{ + ati28800_t *ati28800 = (ati28800_t *)p; + + svga_add_status_info(s, max_len, &ati28800->svga); +} + +static device_config_t compaq_ati28800_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "512 kB", + .value = 512 + }, + { + .description = "1 MB", + .value = 1024 + }, + { + .description = "" + } + }, + .default_int = 512 + }, + { + .type = -1 + } +}; + +device_t ati28800_device = +{ + "ATI-28800", + 0, + ati28800_init, + ati28800_close, + ati28800_available, + ati28800_speed_changed, + ati28800_force_redraw, + ati28800_add_status_info +}; + +device_t compaq_ati28800_device = +{ + "Compaq ATI-28800", + 0, + ati28800_init, + ati28800_close, + compaq_ati28800_available, + ati28800_speed_changed, + ati28800_force_redraw, + ati28800_add_status_info, + compaq_ati28800_config +}; diff --git a/src/vid_ati28800.h b/src/vid_ati28800.h new file mode 100644 index 000000000..68f488783 --- /dev/null +++ b/src/vid_ati28800.h @@ -0,0 +1,2 @@ +extern device_t ati28800_device; +extern device_t compaq_ati28800_device; diff --git a/src/vid_ati68860_ramdac.c b/src/vid_ati68860_ramdac.c new file mode 100644 index 000000000..273c9673e --- /dev/null +++ b/src/vid_ati68860_ramdac.c @@ -0,0 +1,176 @@ +/*ATI 68860 RAMDAC emulation (for Mach64)*/ +/* +ATI 68860/68880 Truecolor DACs: +REG08 (R/W): +bit 0-? Always 2 ?? + +REG0A (R/W): +bit 0-? Always 1Dh ?? + +REG0B (R/W): (GMR ?) +bit 0-7 Mode. 82h: 4bpp, 83h: 8bpp, A0h: 15bpp, A1h: 16bpp, C0h: 24bpp, + E3h: 32bpp (80h for VGA modes ?) + +REG0C (R/W): Device Setup Register A +bit 0 Controls 6/8bit DAC. 0: 8bit DAC/LUT, 1: 6bit DAC/LUT + 2-3 Depends on Video memory (= VRAM width ?) . 1: Less than 1Mb, 2: 1Mb, + 3: > 1Mb + 5-6 Always set ? + 7 If set can remove "snow" in some cases (A860_Delay_L ?) ?? +*/ +#include "ibm.h" +#include "mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_ati68860_ramdac.h" +#include "vid_svga_render.h" + +void ati68860_ramdac_out(uint16_t addr, uint8_t val, ati68860_ramdac_t *ramdac, svga_t *svga) +{ +// pclog("ati68860_out : addr %04X val %02X %04X:%04X\n", addr, val, CS,pc); + switch (addr) + { + case 0: + svga_out(0x3c8, val, svga); + break; + case 1: + svga_out(0x3c9, val, svga); + break; + case 2: + svga_out(0x3c6, val, svga); + break; + case 3: + svga_out(0x3c7, val, svga); + break; + default: + ramdac->regs[addr & 0xf] = val; + switch (addr & 0xf) + { + case 0x4: + ramdac->dac_write = val; + ramdac->dac_pos = 0; + break; + case 0x5: + switch (ramdac->dac_pos) + { + case 0: + ramdac->dac_r = val; + ramdac->dac_pos++; + break; + case 1: + ramdac->dac_g = val; + ramdac->dac_pos++; + break; + case 2: + if (ramdac->dac_write > 1) + break; + ramdac->pal[ramdac->dac_write].r = ramdac->dac_r; + ramdac->pal[ramdac->dac_write].g = ramdac->dac_g; + ramdac->pal[ramdac->dac_write].b = val; + if (ramdac->ramdac_type == RAMDAC_8BIT) + ramdac->pallook[ramdac->dac_write] = makecol32(ramdac->pal[ramdac->dac_write].r, ramdac->pal[ramdac->dac_write].g, ramdac->pal[ramdac->dac_write].b); + else + ramdac->pallook[ramdac->dac_write] = makecol32((ramdac->pal[ramdac->dac_write].r & 0x3f) * 4, (ramdac->pal[ramdac->dac_write].g & 0x3f) * 4, (ramdac->pal[ramdac->dac_write].b & 0x3f) * 4); + ramdac->dac_pos = 0; + ramdac->dac_write = (ramdac->dac_write + 1) & 255; + break; + } + break; + + case 0xb: + switch (val) + { + case 0x82: + ramdac->render = svga_render_4bpp_highres; + break; + case 0x83: + ramdac->render = svga_render_8bpp_highres; + break; + case 0xa0: case 0xb0: + ramdac->render = svga_render_15bpp_highres; + break; + case 0xa1: case 0xb1: + ramdac->render = svga_render_16bpp_highres; + break; + case 0xc0: case 0xd0: + ramdac->render = svga_render_24bpp_highres; + break; + case 0xe2: case 0xf7: + ramdac->render = svga_render_32bpp_highres; + break; + case 0xe3: + ramdac->render = svga_render_ABGR8888_highres; + break; + case 0xf2: + ramdac->render = svga_render_RGBA8888_highres; + break; + default: + ramdac->render = svga_render_8bpp_highres; + break; + } + break; + case 0xc: + svga_set_ramdac_type(svga, (val & 1) ? RAMDAC_6BIT : RAMDAC_8BIT); + break; + } + break; + } +} + +uint8_t ati68860_ramdac_in(uint16_t addr, ati68860_ramdac_t *ramdac, svga_t *svga) +{ + uint8_t ret = 0; + switch (addr) + { + case 0: + ret = svga_in(0x3c8, svga); + break; + case 1: + ret = svga_in(0x3c9, svga); + break; + case 2: + ret = svga_in(0x3c6, svga); + break; + case 3: + ret = svga_in(0x3c7, svga); + break; + case 4: case 8: + ret = 2; + break; + case 6: case 0xa: + ret = 0x1d; + break; + case 0xf: + ret = 0xd0; + break; + + default: + ret = ramdac->regs[addr & 0xf]; + break; + } +// pclog("ati68860_in : addr %04X ret %02X %04X:%04X\n", addr, ret, CS,pc); + return ret; +} + +void ati68860_ramdac_init(ati68860_ramdac_t *ramdac) +{ + ramdac->render = svga_render_8bpp_highres; +} + +void ati68860_set_ramdac_type(ati68860_ramdac_t *ramdac, int type) +{ + int c; + + if (ramdac->ramdac_type != type) + { + ramdac->ramdac_type = type; + + for (c = 0; c < 2; c++) + { + if (ramdac->ramdac_type == RAMDAC_8BIT) + ramdac->pallook[c] = makecol32(ramdac->pal[c].r, ramdac->pal[c].g, ramdac->pal[c].b); + else + ramdac->pallook[c] = makecol32((ramdac->pal[c].r & 0x3f) * 4, (ramdac->pal[c].g & 0x3f) * 4, (ramdac->pal[c].b & 0x3f) * 4); + } + } +} diff --git a/src/vid_ati68860_ramdac.h b/src/vid_ati68860_ramdac.h new file mode 100644 index 000000000..9add13a62 --- /dev/null +++ b/src/vid_ati68860_ramdac.h @@ -0,0 +1,17 @@ +typedef struct ati68860_ramdac_t +{ + uint8_t regs[16]; + void (*render)(struct svga_t *svga); + + int dac_write, dac_pos; + int dac_r, dac_g; + PALETTE pal; + uint32_t pallook[2]; + + int ramdac_type; +} ati68860_ramdac_t; + +void ati68860_ramdac_out(uint16_t addr, uint8_t val, ati68860_ramdac_t *ramdac, svga_t *svga); +uint8_t ati68860_ramdac_in(uint16_t addr, ati68860_ramdac_t *ramdac, svga_t *svga); +void ati68860_ramdac_init(ati68860_ramdac_t *ramdac); +void ati68860_set_ramdac_type(ati68860_ramdac_t *ramdac, int type); diff --git a/src/vid_ati_eeprom.c b/src/vid_ati_eeprom.c new file mode 100644 index 000000000..285f90878 --- /dev/null +++ b/src/vid_ati_eeprom.c @@ -0,0 +1,220 @@ +#include "ibm.h" +#include "vid_ati_eeprom.h" + +enum +{ + EEPROM_IDLE, + EEPROM_WAIT, + EEPROM_OPCODE, + EEPROM_INPUT, + EEPROM_OUTPUT +}; + +enum +{ + EEPROM_OP_EW = 4, + EEPROM_OP_WRITE = 5, + EEPROM_OP_READ = 6, + EEPROM_OP_ERASE = 7, + + EEPROM_OP_WRALMAIN = -1 +}; + +enum +{ + EEPROM_OP_EWDS = 0, + EEPROM_OP_WRAL = 1, + EEPROM_OP_ERAL = 2, + EEPROM_OP_EWEN = 3 +}; + +void ati_eeprom_load(ati_eeprom_t *eeprom, char *fn, int type) +{ + FILE *f; + eeprom->type = type; + strcpy(eeprom->fn, fn); + f = romfopen(eeprom->fn, "rb"); + if (!f) + { + memset(eeprom->data, 0, eeprom->type ? 512 : 128); + return; + } + fread(eeprom->data, 1, eeprom->type ? 512 : 128, f); + fclose(f); +} + +void ati_eeprom_save(ati_eeprom_t *eeprom) +{ + FILE *f = romfopen(eeprom->fn, "wb"); + if (!f) return; + fwrite(eeprom->data, 1, eeprom->type ? 512 : 128, f); + fclose(f); +} + +void ati_eeprom_write(ati_eeprom_t *eeprom, int ena, int clk, int dat) +{ + int c; +// pclog("EEPROM write %i %i %i\n", ena, clk, dat); + if (!ena) + { + eeprom->out = 1; + } + if (clk && !eeprom->oldclk) + { + if (ena && !eeprom->oldena) + { + eeprom->state = EEPROM_WAIT; + eeprom->opcode = 0; + eeprom->count = 3; + eeprom->out = 1; + } + else if (ena) + { +// pclog("EEPROM receive %i %i %i\n", ena, clk, dat); + switch (eeprom->state) + { + case EEPROM_WAIT: + if (!dat) + break; + eeprom->state = EEPROM_OPCODE; + /* fall through */ + case EEPROM_OPCODE: + eeprom->opcode = (eeprom->opcode << 1) | (dat ? 1 : 0); + eeprom->count--; + if (!eeprom->count) + { +// pclog("EEPROM opcode - %i\n", eeprom->opcode); + switch (eeprom->opcode) + { + case EEPROM_OP_WRITE: + eeprom->count = eeprom->type ? 24 : 22; + eeprom->state = EEPROM_INPUT; + eeprom->dat = 0; + break; + case EEPROM_OP_READ: + eeprom->count = eeprom->type ? 8 : 6; + eeprom->state = EEPROM_INPUT; + eeprom->dat = 0; + break; + case EEPROM_OP_EW: + eeprom->count = 2; + eeprom->state = EEPROM_INPUT; + eeprom->dat = 0; + break; + case EEPROM_OP_ERASE: + eeprom->count = eeprom->type ? 8 : 6; + eeprom->state = EEPROM_INPUT; + eeprom->dat = 0; + break; + } + } + break; + + case EEPROM_INPUT: + eeprom->dat = (eeprom->dat << 1) | (dat ? 1 : 0); + eeprom->count--; + if (!eeprom->count) + { +// pclog("EEPROM dat - %02X\n", eeprom->dat); + switch (eeprom->opcode) + { + case EEPROM_OP_WRITE: +// pclog("EEPROM_OP_WRITE addr %02X eeprom_dat %04X\n", (eeprom->dat >> 16) & (eeprom->type ? 255 : 63), eeprom->dat & 0xffff); + if (!eeprom->wp) + { + eeprom->data[(eeprom->dat >> 16) & (eeprom->type ? 255 : 63)] = eeprom->dat & 0xffff; + ati_eeprom_save(eeprom); + } + eeprom->state = EEPROM_IDLE; + eeprom->out = 1; + break; + + case EEPROM_OP_READ: + eeprom->count = 17; + eeprom->state = EEPROM_OUTPUT; + eeprom->dat = eeprom->data[eeprom->dat]; +// pclog("Trigger EEPROM_OUTPUT %04X\n", eeprom->dat); + break; + case EEPROM_OP_EW: +// pclog("EEPROM_OP_EW %i\n", eeprom->dat); + switch (eeprom->dat) + { + case EEPROM_OP_EWDS: + eeprom->wp = 1; + break; + case EEPROM_OP_WRAL: + eeprom->opcode = EEPROM_OP_WRALMAIN; + eeprom->count = 20; + break; + case EEPROM_OP_ERAL: + if (!eeprom->wp) + { + memset(eeprom->data, 0xff, 128); + ati_eeprom_save(eeprom); + } + break; + case EEPROM_OP_EWEN: + eeprom->wp = 0; + break; + } + eeprom->state = EEPROM_IDLE; + eeprom->out = 1; + break; + + case EEPROM_OP_ERASE: +// pclog("EEPROM_OP_ERASE %i\n", eeprom->dat); + if (!eeprom->wp) + { + eeprom->data[eeprom->dat] = 0xffff; + ati_eeprom_save(eeprom); + } + eeprom->state = EEPROM_IDLE; + eeprom->out = 1; + break; + + case EEPROM_OP_WRALMAIN: +// pclog("EEPROM_OP_WRAL %04X\n", eeprom->dat); + if (!eeprom->wp) + { + for (c = 0; c < 256; c++) + eeprom->data[c] = eeprom->dat; + ati_eeprom_save(eeprom); + } + eeprom->state = EEPROM_IDLE; + eeprom->out = 1; + break; + } + } + break; + } + } + eeprom->oldena = ena; + } + else if (!clk && eeprom->oldclk) + { + if (ena) + { + switch (eeprom->state) + { + case EEPROM_OUTPUT: + eeprom->out = (eeprom->dat & 0x10000) ? 1 : 0; + eeprom->dat <<= 1; +// pclog("EEPROM_OUTPUT - data %i\n", eeprom->out); + eeprom->count--; + if (!eeprom->count) + { +// pclog("EEPROM_OUTPUT complete\n"); + eeprom->state = EEPROM_IDLE; + } + break; + } + } + } + eeprom->oldclk = clk; +} + +int ati_eeprom_read(ati_eeprom_t *eeprom) +{ + return eeprom->out; +} + diff --git a/src/vid_ati_eeprom.h b/src/vid_ati_eeprom.h new file mode 100644 index 000000000..63adf19ef --- /dev/null +++ b/src/vid_ati_eeprom.h @@ -0,0 +1,16 @@ +typedef struct ati_eeprom_t +{ + uint16_t data[256]; + + int oldclk, oldena; + int opcode, state, count, out; + int wp; + uint32_t dat; + int type; + + char fn[256]; +} ati_eeprom_t; + +void ati_eeprom_load(ati_eeprom_t *eeprom, char *fn, int type); +void ati_eeprom_write(ati_eeprom_t *eeprom, int ena, int clk, int dat); +int ati_eeprom_read(ati_eeprom_t *eeprom); diff --git a/src/vid_ati_mach64.c b/src/vid_ati_mach64.c new file mode 100644 index 000000000..2add828ce --- /dev/null +++ b/src/vid_ati_mach64.c @@ -0,0 +1,2731 @@ +/*ATI Mach64 emulation*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "pci.h" +#include "rom.h" +#include "thread.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_ati68860_ramdac.h" +#include "vid_ati_eeprom.h" +#include "vid_ics2595.h" + +//#define MACH64_DEBUG + +#define FIFO_SIZE 65536 +#define FIFO_MASK (FIFO_SIZE - 1) +#define FIFO_ENTRY_SIZE (1 << 31) + +#define FIFO_ENTRIES (mach64->fifo_write_idx - mach64->fifo_read_idx) +#define FIFO_FULL ((mach64->fifo_write_idx - mach64->fifo_read_idx) >= FIFO_SIZE) +#define FIFO_EMPTY (mach64->fifo_read_idx == mach64->fifo_write_idx) + +#define FIFO_TYPE 0xff000000 +#define FIFO_ADDR 0x00ffffff + +enum +{ + FIFO_INVALID = (0x00 << 24), + FIFO_WRITE_BYTE = (0x01 << 24), + FIFO_WRITE_WORD = (0x02 << 24), + FIFO_WRITE_DWORD = (0x03 << 24) +}; + +typedef struct +{ + uint32_t addr_type; + uint32_t val; +} fifo_entry_t; + +typedef struct mach64_t +{ + mem_mapping_t linear_mapping; + mem_mapping_t mmio_mapping; + mem_mapping_t mmio_linear_mapping; + + ati68860_ramdac_t ramdac; + ati_eeprom_t eeprom; + ics2595_t ics2595; + svga_t svga; + + rom_t bios_rom; + + uint8_t regs[256]; + int index; + + uint8_t pci_regs[256]; + + int bank_r[2]; + int bank_w[2]; + + uint32_t vram_size; + uint32_t vram_mask; + + uint32_t config_cntl; + + uint32_t context_load_cntl; + uint32_t context_mask; + + uint32_t crtc_gen_cntl; + uint8_t crtc_int_cntl; + uint32_t crtc_h_total_disp; + uint32_t crtc_v_sync_strt_wid; + uint32_t crtc_v_total_disp; + uint32_t crtc_off_pitch; + + uint32_t clock_cntl; + + uint32_t clr_cmp_clr; + uint32_t clr_cmp_cntl; + uint32_t clr_cmp_mask; + + uint32_t cur_horz_vert_off; + uint32_t cur_horz_vert_posn; + uint32_t cur_offset; + + uint32_t dac_cntl; + + uint32_t dp_bkgd_clr; + uint32_t dp_frgd_clr; + uint32_t dp_mix; + uint32_t dp_pix_width; + uint32_t dp_src; + + uint32_t dst_bres_lnth; + uint32_t dst_bres_dec; + uint32_t dst_bres_err; + uint32_t dst_bres_inc; + + uint32_t dst_cntl; + uint32_t dst_height_width; + uint32_t dst_off_pitch; + uint32_t dst_y_x; + + uint32_t gen_test_cntl; + + uint32_t gui_traj_cntl; + + uint32_t mem_cntl; + + uint32_t ovr_clr; + uint32_t ovr_wid_left_right; + uint32_t ovr_wid_top_bottom; + + uint32_t pat_cntl; + uint32_t pat_reg0, pat_reg1; + + uint32_t sc_left_right, sc_top_bottom; + + uint32_t scratch_reg0, scratch_reg1; + + uint32_t src_cntl; + uint32_t src_off_pitch; + uint32_t src_y_x; + uint32_t src_y_x_start; + uint32_t src_height1_width1, src_height2_width2; + + + uint32_t linear_base, old_linear_base; + + struct + { + int op; + + int dst_x, dst_y; + int dst_x_start, dst_y_start; + int src_x, src_y; + int src_x_start, src_y_start; + int xinc, yinc; + int x_count, y_count; + int src_x_count, src_y_count; + int src_width1, src_height1; + int src_width2, src_height2; + uint32_t src_offset, src_pitch; + uint32_t dst_offset, dst_pitch; + int mix_bg, mix_fg; + int source_bg, source_fg, source_mix; + int source_host; + int dst_width, dst_height; + int busy; + int pattern[8][8]; + int sc_left, sc_right, sc_top, sc_bottom; + int dst_pix_width, src_pix_width, host_pix_width; + int dst_size, src_size, host_size; + + uint32_t dp_bkgd_clr; + uint32_t dp_frgd_clr; + + uint32_t clr_cmp_clr; + uint32_t clr_cmp_mask; + int clr_cmp_fn; + int clr_cmp_src; + + int err; + int poly_draw; + } accel; + + fifo_entry_t fifo[FIFO_SIZE]; + volatile int fifo_read_idx, fifo_write_idx; + + thread_t *fifo_thread; + event_t *wake_fifo_thread; + event_t *fifo_not_full_event; + + int blitter_busy; + uint64_t blitter_time; + uint64_t status_time; +} mach64_t; + +enum +{ + SRC_BG = 0, + SRC_FG = 1, + SRC_HOST = 2, + SRC_BLITSRC = 3, + SRC_PAT = 4 +}; + +enum +{ + MONO_SRC_1 = 0, + MONO_SRC_PAT = 1, + MONO_SRC_HOST = 2, + MONO_SRC_BLITSRC = 3 +}; + +enum +{ + BPP_1 = 0, + BPP_4 = 1, + BPP_8 = 2, + BPP_15 = 3, + BPP_16 = 4, + BPP_32 = 5 +}; + +enum +{ + OP_RECT, + OP_LINE +}; + +enum +{ + SRC_PATT_EN = 1, + SRC_PATT_ROT_EN = 2, + SRC_LINEAR_EN = 4 +}; + +enum +{ + DP_BYTE_PIX_ORDER = (1 << 24) +}; + +#define WIDTH_1BIT 3 + +static int mach64_width[8] = {WIDTH_1BIT, 0, 0, 1, 1, 2, 2, 0}; + +enum +{ + DST_X_DIR = 0x01, + DST_Y_DIR = 0x02, + DST_Y_MAJOR = 0x04, + DST_X_TILE = 0x08, + DST_Y_TILE = 0x10, + DST_LAST_PEL = 0x20, + DST_POLYGON_EN = 0x40, + DST_24_ROT_EN = 0x80 +}; + +void mach64_write(uint32_t addr, uint8_t val, void *priv); +uint8_t mach64_read(uint32_t addr, void *priv); +void mach64_updatemapping(mach64_t *mach64); +void mach64_recalctimings(svga_t *svga); +void mach64_start_fill(mach64_t *mach64); +void mach64_start_line(mach64_t *mach64); +void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64); +void mach64_load_context(mach64_t *mach64); + +uint8_t mach64_ext_readb(uint32_t addr, void *priv); +uint16_t mach64_ext_readw(uint32_t addr, void *priv); +uint32_t mach64_ext_readl(uint32_t addr, void *priv); +void mach64_ext_writeb(uint32_t addr, uint8_t val, void *priv); +void mach64_ext_writew(uint32_t addr, uint16_t val, void *priv); +void mach64_ext_writel(uint32_t addr, uint32_t val, void *priv); + +void mach64_out(uint16_t addr, uint8_t val, void *p) +{ + mach64_t *mach64 = p; + svga_t *svga = &mach64->svga; + uint8_t old; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) + addr ^= 0x60; + +// pclog("mach64 out %04X %02X\n", addr, val); + + switch (addr) + { + case 0x1ce: + mach64->index = val; + break; + case 0x1cf: + mach64->regs[mach64->index & 0x3f] = val; + if ((mach64->index & 0x3f) == 0x36) + mach64_recalctimings(svga); + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + ati68860_ramdac_out((addr & 3) | ((mach64->dac_cntl & 3) << 2), val, &mach64->ramdac, svga); + return; + + case 0x3cf: + if (svga->gdcaddr == 6) + { + uint8_t old_val = svga->gdcreg[6]; + svga->gdcreg[6] = val; + if ((svga->gdcreg[6] & 0xc) != (old_val & 0xc)) + mach64_updatemapping(mach64); + return; + } + break; + + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if (svga->crtcreg <= 0x18) + val &= mask_crtc[svga->crtcreg]; + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + if (svga->crtcreg > 0x18) + return; + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + + if (old!=val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t mach64_in(uint16_t addr, void *p) +{ + mach64_t *mach64 = p; + svga_t *svga = &mach64->svga; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout&1)) + addr ^= 0x60; + +// pclog("IN mach64 %04X\n", addr); + + switch (addr) + { + case 0x1ce: + return mach64->index; + case 0x1cf: + return mach64->regs[mach64->index & 0x3f]; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + return ati68860_ramdac_in((addr & 3) | ((mach64->dac_cntl & 3) << 2), &mach64->ramdac, svga); + + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + if (svga->crtcreg > 0x18) + return 0xff; + return svga->crtc[svga->crtcreg]; + } + return svga_in(addr, svga); +} + +void mach64_recalctimings(svga_t *svga) +{ + mach64_t *mach64 = (mach64_t *)svga->p; + + if (((mach64->crtc_gen_cntl >> 24) & 3) == 3) + { + svga->vtotal = (mach64->crtc_v_total_disp & 2047) + 1; + svga->dispend = ((mach64->crtc_v_total_disp >> 16) & 2047) + 1; + svga->htotal = (mach64->crtc_h_total_disp & 255) + 1; + svga->hdisp_time = svga->hdisp = ((mach64->crtc_h_total_disp >> 16) & 255) + 1; + svga->vsyncstart = (mach64->crtc_v_sync_strt_wid & 2047) + 1; + svga->rowoffset = (mach64->crtc_off_pitch >> 22); + svga->clock = cpuclock / mach64->ics2595.output_clock; + svga->ma_latch = (mach64->crtc_off_pitch & 0x1fffff) * 2; + svga->linedbl = svga->rowcount = 0; + svga->split = 0xffffff; + svga->vblankstart = svga->dispend; +// svga_htotal <<= 1; +// svga_hdisp <<= 1; + svga->rowoffset <<= 1; + svga->render = mach64->ramdac.render; + switch ((mach64->crtc_gen_cntl >> 8) & 7) + { + case 1: +// svga->render = svga_render_4bpp_highres; + svga->hdisp *= 8; + break; + case 2: +// svga->render = svga_render_8bpp_highres; + svga->hdisp *= 8; + svga->rowoffset /= 2; + break; + case 3: +// svga->render = svga_render_15bpp_highres; + svga->hdisp *= 8; + //svga_rowoffset *= 2; + break; + case 4: +// svga->render = svga_render_16bpp_highres; + svga->hdisp *= 8; + //svga_rowoffset *= 2; + break; + case 5: +// svga->render = svga_render_24bpp_highres; + svga->hdisp *= 8; + svga->rowoffset = (svga->rowoffset * 3) / 2; + break; + case 6: +// svga->render = svga_render_32bpp_highres; + svga->hdisp *= 8; + svga->rowoffset *= 2; + break; + } + + svga->vrammask = mach64->vram_mask; +// pclog("mach64_recalctimings : frame %i,%i disp %i,%i vsync at %i rowoffset %i pixel clock %f MA %08X\n", svga->htotal, svga->vtotal, svga->hdisp, svga->dispend, svga->vsyncstart, svga->rowoffset, svga->clock, svga->ma); + } + else + { + svga->vrammask = (mach64->regs[0x36] & 0x01) ? mach64->vram_mask : 0x3ffff; + } +} + +void mach64_updatemapping(mach64_t *mach64) +{ + svga_t *svga = &mach64->svga; + + if (!(mach64->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) + { + pclog("Update mapping - PCI disabled\n"); + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&mach64->linear_mapping); + mem_mapping_disable(&mach64->mmio_mapping); + mem_mapping_disable(&mach64->mmio_linear_mapping); + return; + } + + mem_mapping_disable(&mach64->mmio_mapping); +// pclog("Write mapping %02X\n", val); + switch (svga->gdcreg[6] & 0xc) + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_handler(&mach64->svga.mapping, mach64_read, NULL, NULL, mach64_write, NULL, NULL); + mem_mapping_set_p(&mach64->svga.mapping, mach64); + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + mem_mapping_enable(&mach64->mmio_mapping); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_handler(&mach64->svga.mapping, mach64_read, NULL, NULL, mach64_write, NULL, NULL); + mem_mapping_set_p(&mach64->svga.mapping, mach64); + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_handler(&mach64->svga.mapping, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); + mem_mapping_set_p(&mach64->svga.mapping, svga); + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_handler(&mach64->svga.mapping, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel); + mem_mapping_set_p(&mach64->svga.mapping, svga); + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + if (mach64->linear_base) + { + if ((mach64->config_cntl & 3) == 2) + { + /*8 MB aperture*/ + mem_mapping_set_addr(&mach64->linear_mapping, mach64->linear_base, (8 << 20) - 0x4000); + mem_mapping_set_addr(&mach64->mmio_linear_mapping, mach64->linear_base + ((8 << 20) - 0x4000), 0x4000); + } + else + { + /*4 MB aperture*/ + mem_mapping_set_addr(&mach64->linear_mapping, mach64->linear_base, (4 << 20) - 0x4000); + mem_mapping_set_addr(&mach64->mmio_linear_mapping, mach64->linear_base + ((4 << 20) - 0x4000), 0x4000); + } + } + else + { + mem_mapping_disable(&mach64->linear_mapping); + mem_mapping_disable(&mach64->mmio_linear_mapping); + } +} + +static inline void wake_fifo_thread(mach64_t *mach64) +{ + thread_set_event(mach64->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +static void mach64_wait_fifo_idle(mach64_t *mach64) +{ + while (!FIFO_EMPTY) + { + wake_fifo_thread(mach64); + thread_wait_event(mach64->fifo_not_full_event, 1); + } +} + +#define READ8(addr, var) switch ((addr) & 3) \ + { \ + case 0: ret = (var) & 0xff; break; \ + case 1: ret = ((var) >> 8) & 0xff; break; \ + case 2: ret = ((var) >> 16) & 0xff; break; \ + case 3: ret = ((var) >> 24) & 0xff; break; \ + } + +#define WRITE8(addr, var, val) switch ((addr) & 3) \ + { \ + case 0: var = (var & 0xffffff00) | (val); break; \ + case 1: var = (var & 0xffff00ff) | ((val) << 8); break; \ + case 2: var = (var & 0xff00ffff) | ((val) << 16); break; \ + case 3: var = (var & 0x00ffffff) | ((val) << 24); break; \ + } + +static void mach64_accel_write_fifo(mach64_t *mach64, uint32_t addr, uint8_t val) +{ +// pclog("mach64_accel_write_fifo: addr=%08x val=%02x\n", addr, val); + switch (addr & 0x3ff) + { + case 0x100: case 0x101: case 0x102: case 0x103: + WRITE8(addr, mach64->dst_off_pitch, val); + break; + case 0x104: case 0x105: case 0x11c: case 0x11d: + WRITE8(addr + 2, mach64->dst_y_x, val); + break; + case 0x108: case 0x109: + WRITE8(addr, mach64->dst_y_x, val); + break; + case 0x10c: case 0x10d: case 0x10e: case 0x10f: + WRITE8(addr, mach64->dst_y_x, val); + break; + case 0x110: case 0x111: + WRITE8(addr + 2, mach64->dst_height_width, val); + break; + case 0x114: case 0x115: + case 0x118: case 0x119: case 0x11a: case 0x11b: + case 0x11e: case 0x11f: + WRITE8(addr, mach64->dst_height_width, val); + case 0x113: + if ((addr & 0x3ff) == 0x11b || (addr & 0x3ff) == 0x11f || + ((addr & 0x3ff) == 0x113) && !(val & 0x80)) + { + mach64_start_fill(mach64); +#ifdef MACH64_DEBUG + pclog("%i %i %i %i %i %08x\n", (mach64->dst_height_width & 0x7ff), (mach64->dst_height_width & 0x7ff0000), + ((mach64->dp_src & 7) != SRC_HOST), (((mach64->dp_src >> 8) & 7) != SRC_HOST), + (((mach64->dp_src >> 16) & 3) != MONO_SRC_HOST), mach64->dp_src); +#endif + if ((mach64->dst_height_width & 0x7ff) && (mach64->dst_height_width & 0x7ff0000) && + ((mach64->dp_src & 7) != SRC_HOST) && (((mach64->dp_src >> 8) & 7) != SRC_HOST) && + (((mach64->dp_src >> 16) & 3) != MONO_SRC_HOST)) + mach64_blit(0, -1, mach64); + } + break; + + case 0x120: case 0x121: case 0x122: case 0x123: + WRITE8(addr, mach64->dst_bres_lnth, val); + if ((addr & 0x3ff) == 0x123 && !(val & 0x80)) + { + mach64_start_line(mach64); + + if ((mach64->dst_bres_lnth & 0x7fff) && + ((mach64->dp_src & 7) != SRC_HOST) && (((mach64->dp_src >> 8) & 7) != SRC_HOST) && + (((mach64->dp_src >> 16) & 3) != MONO_SRC_HOST)) + mach64_blit(0, -1, mach64); + } + break; + case 0x124: case 0x125: case 0x126: case 0x127: + WRITE8(addr, mach64->dst_bres_err, val); + break; + case 0x128: case 0x129: case 0x12a: case 0x12b: + WRITE8(addr, mach64->dst_bres_inc, val); + break; + case 0x12c: case 0x12d: case 0x12e: case 0x12f: + WRITE8(addr, mach64->dst_bres_dec, val); + break; + + case 0x130: case 0x131: case 0x132: case 0x133: + WRITE8(addr, mach64->dst_cntl, val); + break; + + case 0x180: case 0x181: case 0x182: case 0x183: + WRITE8(addr, mach64->src_off_pitch, val); + break; + case 0x184: case 0x185: + WRITE8(addr, mach64->src_y_x, val); + break; + case 0x188: case 0x189: + WRITE8(addr + 2, mach64->src_y_x, val); + break; + case 0x18c: case 0x18d: case 0x18e: case 0x18f: + WRITE8(addr, mach64->src_y_x, val); + break; + case 0x190: case 0x191: + WRITE8(addr + 2, mach64->src_height1_width1, val); + break; + case 0x194: case 0x195: + WRITE8(addr, mach64->src_height1_width1, val); + break; + case 0x198: case 0x199: case 0x19a: case 0x19b: + WRITE8(addr, mach64->src_height1_width1, val); + break; + case 0x19c: case 0x19d: + WRITE8(addr, mach64->src_y_x_start, val); + break; + case 0x1a0: case 0x1a1: + WRITE8(addr + 2, mach64->src_y_x_start, val); + break; + case 0x1a4: case 0x1a5: case 0x1a6: case 0x1a7: + WRITE8(addr, mach64->src_y_x_start, val); + break; + case 0x1a8: case 0x1a9: + WRITE8(addr + 2, mach64->src_height2_width2, val); + break; + case 0x1ac: case 0x1ad: + WRITE8(addr, mach64->src_height2_width2, val); + break; + case 0x1b0: case 0x1b1: case 0x1b2: case 0x1b3: + WRITE8(addr, mach64->src_height2_width2, val); + break; + + case 0x1b4: case 0x1b5: case 0x1b6: case 0x1b7: + WRITE8(addr, mach64->src_cntl, val); + break; + + case 0x200: case 0x201: case 0x202: case 0x203: + case 0x204: case 0x205: case 0x206: case 0x207: + case 0x208: case 0x209: case 0x20a: case 0x20b: + case 0x20c: case 0x20d: case 0x20e: case 0x20f: + case 0x210: case 0x211: case 0x212: case 0x213: + case 0x214: case 0x215: case 0x216: case 0x217: + case 0x218: case 0x219: case 0x21a: case 0x21b: + case 0x21c: case 0x21d: case 0x21e: case 0x21f: + case 0x220: case 0x221: case 0x222: case 0x223: + case 0x224: case 0x225: case 0x226: case 0x227: + case 0x228: case 0x229: case 0x22a: case 0x22b: + case 0x22c: case 0x22d: case 0x22e: case 0x22f: + case 0x230: case 0x231: case 0x232: case 0x233: + case 0x234: case 0x235: case 0x236: case 0x237: + case 0x238: case 0x239: case 0x23a: case 0x23b: + case 0x23c: case 0x23d: case 0x23e: case 0x23f: + mach64_blit(val, 8, mach64); + break; + + case 0x280: case 0x281: case 0x282: case 0x283: + WRITE8(addr, mach64->pat_reg0, val); + break; + case 0x284: case 0x285: case 0x286: case 0x287: + WRITE8(addr, mach64->pat_reg1, val); + break; + + case 0x2a0: case 0x2a1: case 0x2a8: case 0x2a9: + WRITE8(addr, mach64->sc_left_right, val); + break; + case 0x2a4: case 0x2a5: + addr += 2; + case 0x2aa: case 0x2ab: + WRITE8(addr, mach64->sc_left_right, val); + break; + + case 0x2ac: case 0x2ad: case 0x2b4: case 0x2b5: + WRITE8(addr, mach64->sc_top_bottom, val); + break; + case 0x2b0: case 0x2b1: + addr += 2; + case 0x2b6: case 0x2b7: + WRITE8(addr, mach64->sc_top_bottom, val); + break; + + case 0x2c0: case 0x2c1: case 0x2c2: case 0x2c3: + WRITE8(addr, mach64->dp_bkgd_clr, val); + break; + case 0x2c4: case 0x2c5: case 0x2c6: case 0x2c7: + WRITE8(addr, mach64->dp_frgd_clr, val); + break; + + case 0x2d0: case 0x2d1: case 0x2d2: case 0x2d3: + WRITE8(addr, mach64->dp_pix_width, val); + break; + case 0x2d4: case 0x2d5: case 0x2d6: case 0x2d7: + WRITE8(addr, mach64->dp_mix, val); + break; + case 0x2d8: case 0x2d9: case 0x2da: case 0x2db: + WRITE8(addr, mach64->dp_src, val); + break; + + case 0x300: case 0x301: case 0x302: case 0x303: + WRITE8(addr, mach64->clr_cmp_clr, val); + break; + case 0x304: case 0x305: case 0x306: case 0x307: + WRITE8(addr, mach64->clr_cmp_mask, val); + break; + case 0x308: case 0x309: case 0x30a: case 0x30b: + WRITE8(addr, mach64->clr_cmp_cntl, val); + break; + + case 0x320: case 0x321: case 0x322: case 0x323: + WRITE8(addr, mach64->context_mask, val); + break; + + case 0x330: case 0x331: + WRITE8(addr, mach64->dst_cntl, val); + break; + case 0x332: + WRITE8(addr - 2, mach64->src_cntl, val); + break; + case 0x333: + WRITE8(addr - 3, mach64->pat_cntl, val & 7); + break; + } +} +static void mach64_accel_write_fifo_w(mach64_t *mach64, uint32_t addr, uint16_t val) +{ +// pclog("mach64_accel_write_fifo_w: addr=%08x val=%04x\n", addr, val); + switch (addr & 0x3fe) + { + case 0x200: case 0x202: case 0x204: case 0x206: + case 0x208: case 0x20a: case 0x20c: case 0x20e: + case 0x210: case 0x212: case 0x214: case 0x216: + case 0x218: case 0x21a: case 0x21c: case 0x21e: + case 0x220: case 0x222: case 0x224: case 0x226: + case 0x228: case 0x22a: case 0x22c: case 0x22e: + case 0x230: case 0x232: case 0x234: case 0x236: + case 0x238: case 0x23a: case 0x23c: case 0x23e: + mach64_blit(val, 16, mach64); + break; + + default: +#ifdef MACH64_DEBUG + pclog(" "); +#endif + mach64_accel_write_fifo(mach64, addr, val); +#ifdef MACH64_DEBUG + pclog(" "); +#endif + mach64_accel_write_fifo(mach64, addr + 1, val >> 8); + break; + } +} +static void mach64_accel_write_fifo_l(mach64_t *mach64, uint32_t addr, uint32_t val) +{ +// pclog("mach64_accel_write_fifo_l: addr=%08x %02x val=%08x\n", addr, addr >> 2, val); + switch (addr & 0x3fc) + { + case 0x32c: + mach64->context_load_cntl = val; + if (val & 0x30000) + mach64_load_context(mach64); + break; + + case 0x200: case 0x204: case 0x208: case 0x20c: + case 0x210: case 0x214: case 0x218: case 0x21c: + case 0x220: case 0x224: case 0x228: case 0x22c: + case 0x230: case 0x234: case 0x238: case 0x23c: + if (mach64->accel.source_host || (mach64->dp_pix_width & DP_BYTE_PIX_ORDER)) + mach64_blit(val, 32, mach64); + else + mach64_blit(((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24), 32, mach64); + break; + + default: +#ifdef MACH64_DEBUG + pclog(" "); +#endif + mach64_accel_write_fifo_w(mach64, addr, val); +#ifdef MACH64_DEBUG + pclog(" "); +#endif + mach64_accel_write_fifo_w(mach64, addr + 2, val >> 16); + break; + } +} + +static void fifo_thread(void *param) +{ + mach64_t *mach64 = (mach64_t *)param; + + while (1) + { + thread_set_event(mach64->fifo_not_full_event); + thread_wait_event(mach64->wake_fifo_thread, -1); + thread_reset_event(mach64->wake_fifo_thread); + mach64->blitter_busy = 1; + while (!FIFO_EMPTY) + { + uint64_t start_time = timer_read(); + uint64_t end_time; + fifo_entry_t *fifo = &mach64->fifo[mach64->fifo_read_idx & FIFO_MASK]; + uint32_t val = fifo->val; + + switch (fifo->addr_type & FIFO_TYPE) + { + case FIFO_WRITE_BYTE: + mach64_accel_write_fifo(mach64, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_WORD: + mach64_accel_write_fifo_w(mach64, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_DWORD: + mach64_accel_write_fifo_l(mach64, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + } + + mach64->fifo_read_idx++; + fifo->addr_type = FIFO_INVALID; + + if (FIFO_ENTRIES > 0xe000) + thread_set_event(mach64->fifo_not_full_event); + + end_time = timer_read(); + mach64->blitter_time += end_time - start_time; + } + mach64->blitter_busy = 0; + } +} + +static void mach64_queue(mach64_t *mach64, uint32_t addr, uint32_t val, uint32_t type) +{ + fifo_entry_t *fifo = &mach64->fifo[mach64->fifo_write_idx & FIFO_MASK]; + int c; + + if (FIFO_FULL) + { + thread_reset_event(mach64->fifo_not_full_event); + if (FIFO_FULL) + { + thread_wait_event(mach64->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ + } + } + + fifo->val = val; + fifo->addr_type = (addr & FIFO_ADDR) | type; + + mach64->fifo_write_idx++; + + if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8) + wake_fifo_thread(mach64); +} + +void mach64_cursor_dump(mach64_t *mach64) +{ + svga_t *svga = &mach64->svga; +/* pclog("Mach64 cursor :\n"); + pclog("Ena = %i X = %i Y = %i Addr = %05X Xoff = %i Yoff = %i\n", svga->hwcursor.ena, svga->hwcursor.x, svga->hwcursor.y, svga->hwcursor.addr, svga->hwcursor.xoff, svga->hwcursor.yoff);*/ +} + +void mach64_start_fill(mach64_t *mach64) +{ + int x, y; + + mach64->accel.dst_x = 0; + mach64->accel.dst_y = 0; + mach64->accel.dst_x_start = (mach64->dst_y_x >> 16) & 0xfff; + mach64->accel.dst_y_start = mach64->dst_y_x & 0xfff; + + mach64->accel.dst_width = (mach64->dst_height_width >> 16) & 0x1fff; + mach64->accel.dst_height = mach64->dst_height_width & 0x1fff; + mach64->accel.x_count = mach64->accel.dst_width; + + mach64->accel.src_x = 0; + mach64->accel.src_y = 0; + mach64->accel.src_x_start = (mach64->src_y_x >> 16) & 0xfff; + mach64->accel.src_y_start = mach64->src_y_x & 0xfff; + if (mach64->src_cntl & SRC_LINEAR_EN) + mach64->accel.src_x_count = 0x7ffffff; /*Essentially infinite*/ + else + mach64->accel.src_x_count = (mach64->src_height1_width1 >> 16) & 0x7fff; + if (!(mach64->src_cntl & SRC_PATT_EN)) + mach64->accel.src_y_count = 0x7ffffff; /*Essentially infinite*/ + else + mach64->accel.src_y_count = mach64->src_height1_width1 & 0x1fff; + + mach64->accel.src_width1 = (mach64->src_height1_width1 >> 16) & 0x7fff; + mach64->accel.src_height1 = mach64->src_height1_width1 & 0x1fff; + mach64->accel.src_width2 = (mach64->src_height2_width2 >> 16) & 0x7fff; + mach64->accel.src_height2 = mach64->src_height2_width2 & 0x1fff; + +#ifdef MACH64_DEBUG + pclog("src %i %i %i %i %08X %08X\n", mach64->accel.src_x_count, + mach64->accel.src_y_count, + mach64->accel.src_width1, + mach64->accel.src_height1, + mach64->src_height1_width1, + mach64->src_height2_width2); +#endif + + mach64->accel.src_pitch = (mach64->src_off_pitch >> 22) * 8; + mach64->accel.src_offset = (mach64->src_off_pitch & 0xfffff) * 8; + + mach64->accel.dst_pitch = (mach64->dst_off_pitch >> 22) * 8; + mach64->accel.dst_offset = (mach64->dst_off_pitch & 0xfffff) * 8; + + mach64->accel.mix_fg = (mach64->dp_mix >> 16) & 0x1f; + mach64->accel.mix_bg = mach64->dp_mix & 0x1f; + + mach64->accel.source_bg = mach64->dp_src & 7; + mach64->accel.source_fg = (mach64->dp_src >> 8) & 7; + mach64->accel.source_mix = (mach64->dp_src >> 16) & 7; + + mach64->accel.dst_pix_width = mach64->dp_pix_width & 7; + mach64->accel.src_pix_width = (mach64->dp_pix_width >> 8) & 7; + mach64->accel.host_pix_width = (mach64->dp_pix_width >> 16) & 7; + + mach64->accel.dst_size = mach64_width[mach64->accel.dst_pix_width]; + mach64->accel.src_size = mach64_width[mach64->accel.src_pix_width]; + mach64->accel.host_size = mach64_width[mach64->accel.host_pix_width]; + +/* mach64->accel.src_x *= mach64_inc[mach64->accel.src_pix_width]; + mach64->accel.src_pitch *= mach64_inc[mach64->accel.src_pix_width]; + mach64->accel.dst_x *= mach64_inc[mach64->accel.dst_pix_width]; + mach64->accel.dst_pitch *= mach64_inc[mach64->accel.dst_pix_width];*/ + + if (mach64->accel.src_size == WIDTH_1BIT) + mach64->accel.src_offset <<= 3; + else + mach64->accel.src_offset >>= mach64->accel.src_size; + + if (mach64->accel.dst_size == WIDTH_1BIT) + mach64->accel.dst_offset <<= 3; + else + mach64->accel.dst_offset >>= mach64->accel.dst_size; + +/* if (mach64->accel.source_fg == SRC_BLITSRC || mach64->accel.source_bg == SRC_BLITSRC) + {*/ + mach64->accel.xinc = (mach64->dst_cntl & DST_X_DIR) ? 1 : -1; + mach64->accel.yinc = (mach64->dst_cntl & DST_Y_DIR) ? 1 : -1; +/* } + else + { + mach64->accel.xinc = mach64_inc[mach64->accel.src_pix_width]; + mach64->accel.yinc = 1; + }*/ + + mach64->accel.source_host = ((mach64->dp_src & 7) == SRC_HOST) || (((mach64->dp_src >> 8) & 7) == SRC_HOST); + + +// pclog("mach64_start_fill : pattern %08X %08X\n", mach64->pat_reg0, mach64->pat_reg1); + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + uint32_t temp = (y & 4) ? mach64->pat_reg1 : mach64->pat_reg0; + mach64->accel.pattern[y][x] = (temp >> (x + ((y & 3) * 8))) & 1; +// pclog("%i ", mach64->accel.pattern[y][x]); + } +// pclog("\n"); + } + + mach64->accel.sc_left = mach64->sc_left_right & 0x1fff; + mach64->accel.sc_right = (mach64->sc_left_right >> 16) & 0x1fff; + mach64->accel.sc_top = mach64->sc_top_bottom & 0x7fff; + mach64->accel.sc_bottom = (mach64->sc_top_bottom >> 16) & 0x7fff; + +/* mach64->accel.sc_left *= mach64_inc[mach64->accel.dst_pix_width]; + mach64->accel.sc_right *= mach64_inc[mach64->accel.dst_pix_width];*/ + + mach64->accel.dp_frgd_clr = mach64->dp_frgd_clr; + mach64->accel.dp_bkgd_clr = mach64->dp_bkgd_clr; + + mach64->accel.clr_cmp_clr = mach64->clr_cmp_clr & mach64->clr_cmp_mask; + mach64->accel.clr_cmp_mask = mach64->clr_cmp_mask; + mach64->accel.clr_cmp_fn = mach64->clr_cmp_cntl & 7; + mach64->accel.clr_cmp_src = mach64->clr_cmp_cntl & (1 << 24); + + mach64->accel.poly_draw = 0; + + mach64->accel.busy = 1; +#ifdef MACH64_DEBUG + pclog("mach64_start_fill : dst %i, %i src %i, %i size %i, %i src pitch %i offset %X dst pitch %i offset %X scissor %i %i %i %i src_fg %i mix %02X %02X\n", mach64->accel.dst_x_start, mach64->accel.dst_y_start, mach64->accel.src_x_start, mach64->accel.src_y_start, mach64->accel.dst_width, mach64->accel.dst_height, mach64->accel.src_pitch, mach64->accel.src_offset, mach64->accel.dst_pitch, mach64->accel.dst_offset, mach64->accel.sc_left, mach64->accel.sc_right, mach64->accel.sc_top, mach64->accel.sc_bottom, mach64->accel.source_fg, mach64->accel.mix_fg, mach64->accel.mix_bg); +#endif + mach64->accel.op = OP_RECT; +} + +void mach64_start_line(mach64_t *mach64) +{ + int x, y; + + mach64->accel.dst_x = (mach64->dst_y_x >> 16) & 0xfff; + mach64->accel.dst_y = mach64->dst_y_x & 0xfff; + + mach64->accel.src_x = (mach64->src_y_x >> 16) & 0xfff; + mach64->accel.src_y = mach64->src_y_x & 0xfff; + + mach64->accel.src_pitch = (mach64->src_off_pitch >> 22) * 8; + mach64->accel.src_offset = (mach64->src_off_pitch & 0xfffff) * 8; + + mach64->accel.dst_pitch = (mach64->dst_off_pitch >> 22) * 8; + mach64->accel.dst_offset = (mach64->dst_off_pitch & 0xfffff) * 8; + + mach64->accel.mix_fg = (mach64->dp_mix >> 16) & 0x1f; + mach64->accel.mix_bg = mach64->dp_mix & 0x1f; + + mach64->accel.source_bg = mach64->dp_src & 7; + mach64->accel.source_fg = (mach64->dp_src >> 8) & 7; + mach64->accel.source_mix = (mach64->dp_src >> 16) & 7; + + mach64->accel.dst_pix_width = mach64->dp_pix_width & 7; + mach64->accel.src_pix_width = (mach64->dp_pix_width >> 8) & 7; + mach64->accel.host_pix_width = (mach64->dp_pix_width >> 16) & 7; + + mach64->accel.dst_size = mach64_width[mach64->accel.dst_pix_width]; + mach64->accel.src_size = mach64_width[mach64->accel.src_pix_width]; + mach64->accel.host_size = mach64_width[mach64->accel.host_pix_width]; + + if (mach64->accel.src_size == WIDTH_1BIT) + mach64->accel.src_offset <<= 3; + else + mach64->accel.src_offset >>= mach64->accel.src_size; + + if (mach64->accel.dst_size == WIDTH_1BIT) + mach64->accel.dst_offset <<= 3; + else + mach64->accel.dst_offset >>= mach64->accel.dst_size; + +/* mach64->accel.src_pitch *= mach64_inc[mach64->accel.src_pix_width]; + mach64->accel.dst_pitch *= mach64_inc[mach64->accel.dst_pix_width];*/ + + mach64->accel.source_host = ((mach64->dp_src & 7) == SRC_HOST) || (((mach64->dp_src >> 8) & 7) == SRC_HOST); + + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + uint32_t temp = (y & 4) ? mach64->pat_reg1 : mach64->pat_reg0; + mach64->accel.pattern[y][x] = (temp >> (x + ((y & 3) * 8))) & 1; + } + } + + mach64->accel.sc_left = mach64->sc_left_right & 0x1fff; + mach64->accel.sc_right = (mach64->sc_left_right >> 16) & 0x1fff; + mach64->accel.sc_top = mach64->sc_top_bottom & 0x7fff; + mach64->accel.sc_bottom = (mach64->sc_top_bottom >> 16) & 0x7fff; + + mach64->accel.dp_frgd_clr = mach64->dp_frgd_clr; + mach64->accel.dp_bkgd_clr = mach64->dp_bkgd_clr; + + mach64->accel.x_count = mach64->dst_bres_lnth & 0x7fff; + mach64->accel.err = (mach64->dst_bres_err & 0x3ffff) | ((mach64->dst_bres_err & 0x40000) ? 0xfffc0000 : 0); + + mach64->accel.clr_cmp_clr = mach64->clr_cmp_clr & mach64->clr_cmp_mask; + mach64->accel.clr_cmp_mask = mach64->clr_cmp_mask; + mach64->accel.clr_cmp_fn = mach64->clr_cmp_cntl & 7; + mach64->accel.clr_cmp_src = mach64->clr_cmp_cntl & (1 << 24); + + mach64->accel.busy = 1; +#ifdef MACH64_DEBUG + pclog("mach64_start_line\n"); +#endif + mach64->accel.op = OP_LINE; +} + +#define READ(addr, dat, width) if (width == 0) dat = svga->vram[((addr)) & mach64->vram_mask]; \ + else if (width == 1) dat = *(uint16_t *)&svga->vram[((addr) << 1) & mach64->vram_mask]; \ + else if (width == 2) dat = *(uint32_t *)&svga->vram[((addr) << 2) & mach64->vram_mask]; \ + else dat = (svga->vram[((addr) >> 3) & mach64->vram_mask] >> ((addr) & 7)) & 1; + +#define MIX switch (mix ? mach64->accel.mix_fg : mach64->accel.mix_bg) \ + { \ + case 0x0: dest_dat = ~dest_dat; break; \ + case 0x1: dest_dat = 0; break; \ + case 0x2: dest_dat = 0xffffffff; break; \ + case 0x3: dest_dat = dest_dat; break; \ + case 0x4: dest_dat = ~src_dat; break; \ + case 0x5: dest_dat = src_dat ^ dest_dat; break; \ + case 0x6: dest_dat = ~(src_dat ^ dest_dat); break; \ + case 0x7: dest_dat = src_dat; break; \ + case 0x8: dest_dat = ~(src_dat & dest_dat); break; \ + case 0x9: dest_dat = ~src_dat | dest_dat; break; \ + case 0xa: dest_dat = src_dat | ~dest_dat; break; \ + case 0xb: dest_dat = src_dat | dest_dat; break; \ + case 0xc: dest_dat = src_dat & dest_dat; break; \ + case 0xd: dest_dat = src_dat & ~dest_dat; break; \ + case 0xe: dest_dat = ~src_dat & dest_dat; break; \ + case 0xf: dest_dat = ~(src_dat | dest_dat); break; \ + } + +#define WRITE(addr, width) if (width == 0) \ + { \ + svga->vram[(addr) & mach64->vram_mask] = dest_dat; \ + svga->changedvram[((addr) & mach64->vram_mask) >> 12] = changeframecount; \ + } \ + else if (width == 1) \ + { \ + *(uint16_t *)&svga->vram[((addr) << 1) & mach64->vram_mask] = dest_dat; \ + svga->changedvram[(((addr) << 1) & mach64->vram_mask) >> 12] = changeframecount; \ + } \ + else if (width == 2) \ + { \ + *(uint32_t *)&svga->vram[((addr) << 2) & mach64->vram_mask] = dest_dat; \ + svga->changedvram[(((addr) << 2) & mach64->vram_mask) >> 12] = changeframecount; \ + } \ + else \ + { \ + if (dest_dat & 1) \ + svga->vram[((addr) >> 3) & mach64->vram_mask] |= 1 << ((addr) & 7); \ + else \ + svga->vram[((addr) >> 3) & mach64->vram_mask] &= ~(1 << ((addr) & 7)); \ + svga->changedvram[(((addr) >> 3) & mach64->vram_mask) >> 12] = changeframecount; \ + } + +void mach64_blit(uint32_t cpu_dat, int count, mach64_t *mach64) +{ + svga_t *svga = &mach64->svga; + int cmp_clr = 0; + + if (!mach64->accel.busy) + { +#ifdef MACH64_DEBUG + pclog("mach64_blit : return as not busy\n"); +#endif + return; + } + switch (mach64->accel.op) + { + case OP_RECT: + while (count) + { + uint32_t src_dat, dest_dat; + uint32_t host_dat; + int mix; + int dst_x = (mach64->accel.dst_x + mach64->accel.dst_x_start) & 0xfff; + int dst_y = (mach64->accel.dst_y + mach64->accel.dst_y_start) & 0xfff; + int src_x; + int src_y = (mach64->accel.src_y + mach64->accel.src_y_start) & 0xfff; + + if (mach64->src_cntl & SRC_LINEAR_EN) + src_x = mach64->accel.src_x; + else + src_x = (mach64->accel.src_x + mach64->accel.src_x_start) & 0xfff; + + if (mach64->accel.source_host) + { + host_dat = cpu_dat; + switch (mach64->accel.host_size) + { + case 0: + cpu_dat >>= 8; + count -= 8; + break; + case 1: + cpu_dat >>= 16; + count -= 16; + break; + case 2: + count -= 32; + break; + } + } + else + count--; + + switch (mach64->accel.source_mix) + { + case MONO_SRC_HOST: + if (mach64->dp_pix_width & DP_BYTE_PIX_ORDER) + { + mix = cpu_dat & 1; + cpu_dat >>= 1; + } + else + { + mix = cpu_dat >> 31; + cpu_dat <<= 1; + } + break; + case MONO_SRC_PAT: + mix = mach64->accel.pattern[dst_y & 7][dst_x & 7]; + break; + case MONO_SRC_1: + mix = 1; + break; + case MONO_SRC_BLITSRC: + if (mach64->src_cntl & SRC_LINEAR_EN) + { + READ(mach64->accel.src_offset + src_x, mix, WIDTH_1BIT); + } + else + { + READ(mach64->accel.src_offset + (src_y * mach64->accel.src_pitch) + src_x, mix, WIDTH_1BIT); + } + break; + } + + if (dst_x >= mach64->accel.sc_left && dst_x <= mach64->accel.sc_right && + dst_y >= mach64->accel.sc_top && dst_y <= mach64->accel.sc_bottom) + { + switch (mix ? mach64->accel.source_fg : mach64->accel.source_bg) + { + case SRC_HOST: + src_dat = host_dat; + break; + case SRC_BLITSRC: + READ(mach64->accel.src_offset + (src_y * mach64->accel.src_pitch) + src_x, src_dat, mach64->accel.src_size); + break; + case SRC_FG: + src_dat = mach64->accel.dp_frgd_clr; + break; + case SRC_BG: + src_dat = mach64->accel.dp_bkgd_clr; + break; + default: + src_dat = 0; + break; + } + if (mach64->dst_cntl & DST_POLYGON_EN) + { + int poly_src; + READ(mach64->accel.src_offset + (src_y * mach64->accel.src_pitch) + src_x, poly_src, mach64->accel.src_size); + if (poly_src) + mach64->accel.poly_draw = !mach64->accel.poly_draw; + } + if (!(mach64->dst_cntl & DST_POLYGON_EN) || mach64->accel.poly_draw) + { + READ(mach64->accel.dst_offset + (dst_y * mach64->accel.dst_pitch) + dst_x, dest_dat, mach64->accel.dst_size); + + switch (mach64->accel.clr_cmp_fn) + { + case 1: /*TRUE*/ + cmp_clr = 1; + break; + case 4: /*DST_CLR != CLR_CMP_CLR*/ + cmp_clr = (((mach64->accel.clr_cmp_src) ? src_dat : dest_dat) & mach64->accel.clr_cmp_mask) != mach64->accel.clr_cmp_clr; + break; + case 5: /*DST_CLR == CLR_CMP_CLR*/ + cmp_clr = (((mach64->accel.clr_cmp_src) ? src_dat : dest_dat) & mach64->accel.clr_cmp_mask) == mach64->accel.clr_cmp_clr; + break; + } + + if (!cmp_clr) + MIX + + WRITE(mach64->accel.dst_offset + (dst_y * mach64->accel.dst_pitch) + dst_x, mach64->accel.dst_size); + } + } + + if (mach64->dst_cntl & DST_24_ROT_EN) + { + mach64->accel.dp_frgd_clr = ((mach64->accel.dp_frgd_clr >> 8) & 0xffff) | (mach64->accel.dp_frgd_clr << 16); + mach64->accel.dp_bkgd_clr = ((mach64->accel.dp_bkgd_clr >> 8) & 0xffff) | (mach64->accel.dp_bkgd_clr << 16); + } + + mach64->accel.src_x += mach64->accel.xinc; + mach64->accel.dst_x += mach64->accel.xinc; + if (!(mach64->src_cntl & SRC_LINEAR_EN)) + { + mach64->accel.src_x_count--; + if (mach64->accel.src_x_count <= 0) + { + mach64->accel.src_x = 0; + if ((mach64->src_cntl & (SRC_PATT_ROT_EN | SRC_PATT_EN)) == (SRC_PATT_ROT_EN | SRC_PATT_EN)) + { + mach64->accel.src_x_start = (mach64->src_y_x_start >> 16) & 0xfff; + mach64->accel.src_x_count = mach64->accel.src_width2; + } + else + mach64->accel.src_x_count = mach64->accel.src_width1; + } + } + + mach64->accel.x_count--; + + if (mach64->accel.x_count <= 0) + { + mach64->accel.x_count = mach64->accel.dst_width; + mach64->accel.dst_x = 0; + mach64->accel.dst_y += mach64->accel.yinc; + mach64->accel.src_x_start = (mach64->src_y_x >> 16) & 0xfff; + mach64->accel.src_x_count = mach64->accel.src_width1; + + if (!(mach64->src_cntl & SRC_LINEAR_EN)) + { + mach64->accel.src_x = 0; + mach64->accel.src_y += mach64->accel.yinc; + mach64->accel.src_y_count--; + if (mach64->accel.src_y_count <= 0) + { + mach64->accel.src_y = 0; + if ((mach64->src_cntl & (SRC_PATT_ROT_EN | SRC_PATT_EN)) == (SRC_PATT_ROT_EN | SRC_PATT_EN)) + { + mach64->accel.src_y_start = mach64->src_y_x_start & 0xfff; + mach64->accel.src_y_count = mach64->accel.src_height2; + } + else + mach64->accel.src_y_count = mach64->accel.src_height1; + } + } + + mach64->accel.poly_draw = 0; + + mach64->accel.dst_height--; + + if (mach64->accel.dst_height <= 0) + { + /*Blit finished*/ +#ifdef MACH64_DEBUG + pclog("mach64 blit finished\n"); +#endif + mach64->accel.busy = 0; + if (mach64->dst_cntl & DST_X_TILE) + mach64->dst_y_x = (mach64->dst_y_x & 0xfff) | ((mach64->dst_y_x + (mach64->accel.dst_width << 16)) & 0xfff0000); + if (mach64->dst_cntl & DST_Y_TILE) + mach64->dst_y_x = (mach64->dst_y_x & 0xfff0000) | ((mach64->dst_y_x + (mach64->dst_height_width & 0x1fff)) & 0xfff); + return; + } + if (mach64->accel.source_host) + return; + } + } + break; + + case OP_LINE: + while (count) + { + uint32_t src_dat, dest_dat; + uint32_t host_dat; + int mix; + int draw_pixel = !(mach64->dst_cntl & DST_POLYGON_EN); + + if (mach64->accel.source_host) + { + host_dat = cpu_dat; + switch (mach64->accel.src_size) + { + case 0: + cpu_dat >>= 8; + count -= 8; + break; + case 1: + cpu_dat >>= 16; + count -= 16; + break; + case 2: + count -= 32; + break; + } + } + else + count--; + + switch (mach64->accel.source_mix) + { + case MONO_SRC_HOST: + mix = cpu_dat >> 31; + cpu_dat <<= 1; + break; + case MONO_SRC_PAT: + mix = mach64->accel.pattern[mach64->accel.dst_y & 7][mach64->accel.dst_x & 7]; + break; + case MONO_SRC_1: + default: + mix = 1; + break; + } + + if (mach64->dst_cntl & DST_POLYGON_EN) + { + if (mach64->dst_cntl & DST_Y_MAJOR) + draw_pixel = 1; + else if ((mach64->dst_cntl & DST_X_DIR) && mach64->accel.err < (mach64->dst_bres_dec + mach64->dst_bres_inc)) /*X+*/ + draw_pixel = 1; + else if (!(mach64->dst_cntl & DST_X_DIR) && mach64->accel.err >= 0) /*X-*/ + draw_pixel = 1; + } + + if (mach64->accel.x_count == 1 && !(mach64->dst_cntl & DST_LAST_PEL)) + draw_pixel = 0; + + if (mach64->accel.dst_x >= mach64->accel.sc_left && mach64->accel.dst_x <= mach64->accel.sc_right && + mach64->accel.dst_y >= mach64->accel.sc_top && mach64->accel.dst_y <= mach64->accel.sc_bottom && draw_pixel) + { + switch (mix ? mach64->accel.source_fg : mach64->accel.source_bg) + { + case SRC_HOST: + src_dat = host_dat; + break; + case SRC_BLITSRC: + READ(mach64->accel.src_offset + (mach64->accel.src_y * mach64->accel.src_pitch) + mach64->accel.src_x, src_dat, mach64->accel.src_size); + break; + case SRC_FG: + src_dat = mach64->accel.dp_frgd_clr; + break; + case SRC_BG: + src_dat = mach64->accel.dp_bkgd_clr; + break; + default: + src_dat = 0; + break; + } + + READ(mach64->accel.dst_offset + (mach64->accel.dst_y * mach64->accel.dst_pitch) + mach64->accel.dst_x, dest_dat, mach64->accel.dst_size); + +// pclog("Blit %i,%i %i,%i %X %X %i %02X %02X %i ", mach64->accel.src_x, mach64->accel.src_y, mach64->accel.dst_x, mach64->accel.dst_y, (mach64->accel.src_offset + (mach64->accel.src_y * mach64->accel.src_pitch) + mach64->accel.src_x) & 0x7fffff, (mach64->accel.dst_offset + (mach64->accel.dst_y * mach64->accel.dst_pitch) + mach64->accel.dst_x) & 0x7fffff, count, src_dat, dest_dat, mix); + + switch (mach64->accel.clr_cmp_fn) + { + case 1: /*TRUE*/ + cmp_clr = 1; + break; + case 4: /*DST_CLR != CLR_CMP_CLR*/ + cmp_clr = (((mach64->accel.clr_cmp_src) ? src_dat : dest_dat) & mach64->accel.clr_cmp_mask) != mach64->accel.clr_cmp_clr; + break; + case 5: /*DST_CLR == CLR_CMP_CLR*/ + cmp_clr = (((mach64->accel.clr_cmp_src) ? src_dat : dest_dat) & mach64->accel.clr_cmp_mask) == mach64->accel.clr_cmp_clr; + break; + } + + if (!cmp_clr) + MIX + +// pclog("%02X %i\n", dest_dat, mach64->accel.dst_height); + + WRITE(mach64->accel.dst_offset + (mach64->accel.dst_y * mach64->accel.dst_pitch) + mach64->accel.dst_x, mach64->accel.dst_size); + } + + mach64->accel.x_count--; + if (mach64->accel.x_count <= 0) + { + /*Blit finished*/ +#ifdef MACH64_DEBUG + pclog("mach64 blit finished\n"); +#endif + mach64->accel.busy = 0; + return; + } + + switch (mach64->dst_cntl & 7) + { + case 0: case 2: + mach64->accel.src_x--; + mach64->accel.dst_x--; + break; + case 1: case 3: + mach64->accel.src_x++; + mach64->accel.dst_x++; + break; + case 4: case 5: + mach64->accel.src_y--; + mach64->accel.dst_y--; + break; + case 6: case 7: + mach64->accel.src_y++; + mach64->accel.dst_y++; + break; + } +#ifdef MACH64_DEBUG + pclog("x %i y %i err %i inc %i dec %i\n", mach64->accel.dst_x, mach64->accel.dst_y, mach64->accel.err, mach64->dst_bres_inc, mach64->dst_bres_dec); +#endif + if (mach64->accel.err >= 0) + { + mach64->accel.err += mach64->dst_bres_dec; + + switch (mach64->dst_cntl & 7) + { + case 0: case 1: + mach64->accel.src_y--; + mach64->accel.dst_y--; + break; + case 2: case 3: + mach64->accel.src_y++; + mach64->accel.dst_y++; + break; + case 4: case 6: + mach64->accel.src_x--; + mach64->accel.dst_x--; + break; + case 5: case 7: + mach64->accel.src_x++; + mach64->accel.dst_x++; + break; + } + } + else + mach64->accel.err += mach64->dst_bres_inc; + } + break; + } +} + +void mach64_load_context(mach64_t *mach64) +{ + svga_t *svga = &mach64->svga; + uint32_t addr; + + while (mach64->context_load_cntl & 0x30000) + { + addr = ((0x3fff - (mach64->context_load_cntl & 0x3fff)) * 256) & mach64->vram_mask; + mach64->context_mask = *(uint32_t *)&svga->vram[addr]; +#ifdef MACH64_DEBUG + pclog("mach64_load_context %08X from %08X : mask %08X\n", mach64->context_load_cntl, addr, mach64->context_mask); +#endif + + if (mach64->context_mask & (1 << 2)) + mach64_accel_write_fifo_l(mach64, 0x100, *(uint32_t *)&svga->vram[addr + 0x08]); + if (mach64->context_mask & (1 << 3)) + mach64_accel_write_fifo_l(mach64, 0x10c, *(uint32_t *)&svga->vram[addr + 0x0c]); + if (mach64->context_mask & (1 << 4)) + mach64_accel_write_fifo_l(mach64, 0x118, *(uint32_t *)&svga->vram[addr + 0x10]); + if (mach64->context_mask & (1 << 5)) + mach64_accel_write_fifo_l(mach64, 0x124, *(uint32_t *)&svga->vram[addr + 0x14]); + if (mach64->context_mask & (1 << 6)) + mach64_accel_write_fifo_l(mach64, 0x128, *(uint32_t *)&svga->vram[addr + 0x18]); + if (mach64->context_mask & (1 << 7)) + mach64_accel_write_fifo_l(mach64, 0x12c, *(uint32_t *)&svga->vram[addr + 0x1c]); + if (mach64->context_mask & (1 << 8)) + mach64_accel_write_fifo_l(mach64, 0x180, *(uint32_t *)&svga->vram[addr + 0x20]); + if (mach64->context_mask & (1 << 9)) + mach64_accel_write_fifo_l(mach64, 0x18c, *(uint32_t *)&svga->vram[addr + 0x24]); + if (mach64->context_mask & (1 << 10)) + mach64_accel_write_fifo_l(mach64, 0x198, *(uint32_t *)&svga->vram[addr + 0x28]); + if (mach64->context_mask & (1 << 11)) + mach64_accel_write_fifo_l(mach64, 0x1a4, *(uint32_t *)&svga->vram[addr + 0x2c]); + if (mach64->context_mask & (1 << 12)) + mach64_accel_write_fifo_l(mach64, 0x1b0, *(uint32_t *)&svga->vram[addr + 0x30]); + if (mach64->context_mask & (1 << 13)) + mach64_accel_write_fifo_l(mach64, 0x280, *(uint32_t *)&svga->vram[addr + 0x34]); + if (mach64->context_mask & (1 << 14)) + mach64_accel_write_fifo_l(mach64, 0x284, *(uint32_t *)&svga->vram[addr + 0x38]); + if (mach64->context_mask & (1 << 15)) + mach64_accel_write_fifo_l(mach64, 0x2a8, *(uint32_t *)&svga->vram[addr + 0x3c]); + if (mach64->context_mask & (1 << 16)) + mach64_accel_write_fifo_l(mach64, 0x2b4, *(uint32_t *)&svga->vram[addr + 0x40]); + if (mach64->context_mask & (1 << 17)) + mach64_accel_write_fifo_l(mach64, 0x2c0, *(uint32_t *)&svga->vram[addr + 0x44]); + if (mach64->context_mask & (1 << 18)) + mach64_accel_write_fifo_l(mach64, 0x2c4, *(uint32_t *)&svga->vram[addr + 0x48]); + if (mach64->context_mask & (1 << 19)) + mach64_accel_write_fifo_l(mach64, 0x2c8, *(uint32_t *)&svga->vram[addr + 0x4c]); + if (mach64->context_mask & (1 << 20)) + mach64_accel_write_fifo_l(mach64, 0x2cc, *(uint32_t *)&svga->vram[addr + 0x50]); + if (mach64->context_mask & (1 << 21)) + mach64_accel_write_fifo_l(mach64, 0x2d0, *(uint32_t *)&svga->vram[addr + 0x54]); + if (mach64->context_mask & (1 << 22)) + mach64_accel_write_fifo_l(mach64, 0x2d4, *(uint32_t *)&svga->vram[addr + 0x58]); + if (mach64->context_mask & (1 << 23)) + mach64_accel_write_fifo_l(mach64, 0x2d8, *(uint32_t *)&svga->vram[addr + 0x5c]); + if (mach64->context_mask & (1 << 24)) + mach64_accel_write_fifo_l(mach64, 0x300, *(uint32_t *)&svga->vram[addr + 0x60]); + if (mach64->context_mask & (1 << 25)) + mach64_accel_write_fifo_l(mach64, 0x304, *(uint32_t *)&svga->vram[addr + 0x64]); + if (mach64->context_mask & (1 << 26)) + mach64_accel_write_fifo_l(mach64, 0x308, *(uint32_t *)&svga->vram[addr + 0x68]); + if (mach64->context_mask & (1 << 27)) + mach64_accel_write_fifo_l(mach64, 0x330, *(uint32_t *)&svga->vram[addr + 0x6c]); + + mach64->context_load_cntl = *(uint32_t *)&svga->vram[addr + 0x70]; + } +} + +uint8_t mach64_ext_readb(uint32_t addr, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + uint8_t ret; + switch (addr & 0x3ff) + { + case 0x00: case 0x01: case 0x02: case 0x03: + READ8(addr, mach64->crtc_h_total_disp); + break; + case 0x08: case 0x09: case 0x0a: case 0x0b: + READ8(addr, mach64->crtc_v_total_disp); + break; + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + READ8(addr, mach64->crtc_v_sync_strt_wid); + break; + + case 0x12: case 0x13: + READ8(addr - 2, mach64->svga.vc); + break; + + case 0x14: case 0x15: case 0x16: case 0x17: + READ8(addr, mach64->crtc_off_pitch); + break; + + case 0x18: + ret = mach64->crtc_int_cntl & ~1; + if (mach64->svga.cgastat & 8) + ret |= 1; + break; + + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + READ8(addr, mach64->crtc_gen_cntl); + break; + + case 0x40: case 0x41: case 0x42: case 0x43: + READ8(addr, mach64->ovr_clr); + break; + case 0x44: case 0x45: case 0x46: case 0x47: + READ8(addr, mach64->ovr_wid_left_right); + break; + case 0x48: case 0x49: case 0x4a: case 0x4b: + READ8(addr, mach64->ovr_wid_top_bottom); + break; + + case 0x68: case 0x69: case 0x6a: case 0x6b: + READ8(addr, mach64->cur_offset); + break; + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + READ8(addr, mach64->cur_horz_vert_posn); + break; + case 0x70: case 0x71: case 0x72: case 0x73: + READ8(addr, mach64->cur_horz_vert_off); + break; + + case 0x80: case 0x81: case 0x82: case 0x83: + READ8(addr, mach64->scratch_reg0); + break; + case 0x84: case 0x85: case 0x86: case 0x87: + READ8(addr, mach64->scratch_reg1); + break; + + case 0x90: case 0x91: case 0x92: case 0x93: + READ8(addr, mach64->clock_cntl); + break; + + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + READ8(addr, mach64->mem_cntl); + break; + + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + ret = ati68860_ramdac_in((addr & 3) | ((mach64->dac_cntl & 3) << 2), &mach64->ramdac, &mach64->svga); + break; + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + READ8(addr, mach64->dac_cntl); + break; + + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + READ8(addr, mach64->gen_test_cntl); + break; + + case 0xe0: case 0xe1: case 0xe2: case 0xe3: + READ8(addr, 0x020000d7); /*88800GX-2*/ + break; + + case 0x100: case 0x101: case 0x102: case 0x103: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_off_pitch); + break; + case 0x104: case 0x105: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_y_x); + break; + case 0x108: case 0x109: case 0x11c: case 0x11d: + mach64_wait_fifo_idle(mach64); + READ8(addr + 2, mach64->dst_y_x); + break; + case 0x10c: case 0x10d: case 0x10e: case 0x10f: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_y_x); + break; + case 0x110: case 0x111: + addr += 2; + case 0x114: case 0x115: + case 0x118: case 0x119: case 0x11a: case 0x11b: + case 0x11e: case 0x11f: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_height_width); + break; + + case 0x120: case 0x121: case 0x122: case 0x123: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_bres_lnth); + break; + case 0x124: case 0x125: case 0x126: case 0x127: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_bres_err); + break; + case 0x128: case 0x129: case 0x12a: case 0x12b: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_bres_inc); + break; + case 0x12c: case 0x12d: case 0x12e: case 0x12f: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_bres_dec); + break; + + case 0x130: case 0x131: case 0x132: case 0x133: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_cntl); + break; + + case 0x180: case 0x181: case 0x182: case 0x183: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_off_pitch); + break; + case 0x184: case 0x185: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_y_x); + break; + case 0x188: case 0x189: + mach64_wait_fifo_idle(mach64); + READ8(addr + 2, mach64->src_y_x); + break; + case 0x18c: case 0x18d: case 0x18e: case 0x18f: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_y_x); + break; + case 0x190: case 0x191: + mach64_wait_fifo_idle(mach64); + READ8(addr + 2, mach64->src_height1_width1); + break; + case 0x194: case 0x195: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_height1_width1); + break; + case 0x198: case 0x199: case 0x19a: case 0x19b: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_height1_width1); + break; + case 0x19c: case 0x19d: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_y_x_start); + break; + case 0x1a0: case 0x1a1: + mach64_wait_fifo_idle(mach64); + READ8(addr + 2, mach64->src_y_x_start); + break; + case 0x1a4: case 0x1a5: case 0x1a6: case 0x1a7: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_y_x_start); + break; + case 0x1a8: case 0x1a9: + mach64_wait_fifo_idle(mach64); + READ8(addr + 2, mach64->src_height2_width2); + break; + case 0x1ac: case 0x1ad: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_height2_width2); + break; + case 0x1b0: case 0x1b1: case 0x1b2: case 0x1b3: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_height2_width2); + break; + + case 0x1b4: case 0x1b5: case 0x1b6: case 0x1b7: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->src_cntl); + break; + + case 0x280: case 0x281: case 0x282: case 0x283: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->pat_reg0); + break; + case 0x284: case 0x285: case 0x286: case 0x287: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->pat_reg1); + break; + + case 0x2a0: case 0x2a1: case 0x2a8: case 0x2a9: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->sc_left_right); + break; + case 0x2a4: case 0x2a5: + addr += 2; + case 0x2aa: case 0x2ab: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->sc_left_right); + break; + + case 0x2ac: case 0x2ad: case 0x2b4: case 0x2b5: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->sc_top_bottom); + break; + case 0x2b0: case 0x2b1: + addr += 2; + case 0x2b6: case 0x2b7: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->sc_top_bottom); + break; + + case 0x2c0: case 0x2c1: case 0x2c2: case 0x2c3: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dp_bkgd_clr); + break; + case 0x2c4: case 0x2c5: case 0x2c6: case 0x2c7: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dp_frgd_clr); + break; + + case 0x2d0: case 0x2d1: case 0x2d2: case 0x2d3: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dp_pix_width); + break; + case 0x2d4: case 0x2d5: case 0x2d6: case 0x2d7: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dp_mix); + break; + case 0x2d8: case 0x2d9: case 0x2da: case 0x2db: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dp_src); + break; + + case 0x300: case 0x301: case 0x302: case 0x303: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->clr_cmp_clr); + break; + case 0x304: case 0x305: case 0x306: case 0x307: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->clr_cmp_mask); + break; + case 0x308: case 0x309: case 0x30a: case 0x30b: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->clr_cmp_cntl); + break; + + case 0x310: case 0x311: + if (!FIFO_EMPTY) + wake_fifo_thread(mach64); + ret = 0; + if (FIFO_FULL) + ret = 0xff; + break; + + case 0x320: case 0x321: case 0x322: case 0x323: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->context_mask); + break; + + case 0x330: case 0x331: + mach64_wait_fifo_idle(mach64); + READ8(addr, mach64->dst_cntl); + break; + case 0x332: + mach64_wait_fifo_idle(mach64); + READ8(addr - 2, mach64->src_cntl); + break; + case 0x333: + mach64_wait_fifo_idle(mach64); + READ8(addr - 3, mach64->pat_cntl); + break; + + case 0x338: +/* if (!FIFO_EMPTY) + wake_fifo_thread(mach64);*/ + ret = FIFO_EMPTY ? 0 : 1; + break; + + default: + ret = 0; + break; + } +#ifdef MACH64_DEBUG + if ((addr & 0x3fc) != 0x018) pclog("mach64_ext_readb : addr %08X ret %02X\n", addr, ret); +#endif + return ret; +} +uint16_t mach64_ext_readw(uint32_t addr, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + uint16_t ret; + switch (addr & 0x3ff) + { + default: +#ifdef MACH64_DEBUG + pclog(" "); +#endif + ret = mach64_ext_readb(addr, p); +#ifdef MACH64_DEBUG + pclog(" "); +#endif + ret |= mach64_ext_readb(addr + 1, p) << 8; + break; + } +#ifdef MACH64_DEBUG + if ((addr & 0x3fc) != 0x018) pclog("mach64_ext_readw : addr %08X ret %04X\n", addr, ret); +#endif + return ret; +} +uint32_t mach64_ext_readl(uint32_t addr, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + uint32_t ret; + switch (addr & 0x3ff) + { + case 0x18: + ret = mach64->crtc_int_cntl & ~1; + if (mach64->svga.cgastat & 8) + ret |= 1; + break; + + case 0xb4: + ret = (mach64->bank_w[0] >> 15) | ((mach64->bank_w[1] >> 15) << 16); + break; + case 0xb8: + ret = (mach64->bank_r[0] >> 15) | ((mach64->bank_r[1] >> 15) << 16); + break; + + default: +#ifdef MACH64_DEBUG + pclog(" "); +#endif + ret = mach64_ext_readw(addr, p); +#ifdef MACH64_DEBUG + pclog(" "); +#endif + ret |= mach64_ext_readw(addr + 2, p) << 16; + break; + } +#ifdef MACH64_DEBUG + if ((addr & 0x3fc) != 0x018) pclog("mach64_ext_readl : addr %08X ret %08X\n", addr, ret); +#endif + return ret; +} + +void mach64_ext_writeb(uint32_t addr, uint8_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + svga_t *svga = &mach64->svga; +#ifdef MACH64_DEBUG + pclog("mach64_ext_writeb : addr %08X val %02X\n", addr, val); +#endif + if (addr & 0x300) + { + mach64_queue(mach64, addr & 0x3ff, val, FIFO_WRITE_BYTE); + } + else switch (addr & 0x3ff) + { + case 0x00: case 0x01: case 0x02: case 0x03: + WRITE8(addr, mach64->crtc_h_total_disp, val); + svga_recalctimings(&mach64->svga); + break; + case 0x08: case 0x09: case 0x0a: case 0x0b: + WRITE8(addr, mach64->crtc_v_total_disp, val); + svga_recalctimings(&mach64->svga); + break; + case 0x0c: case 0x0d: case 0x0e: case 0x0f: + WRITE8(addr, mach64->crtc_v_sync_strt_wid, val); + svga_recalctimings(&mach64->svga); + break; + + case 0x14: case 0x15: case 0x16: case 0x17: + WRITE8(addr, mach64->crtc_off_pitch, val); + svga_recalctimings(&mach64->svga); + svga->fullchange = changeframecount; + break; + + case 0x18: + mach64->crtc_int_cntl = val; + break; + + case 0x1c: case 0x1d: case 0x1e: case 0x1f: + WRITE8(addr, mach64->crtc_gen_cntl, val); + if (((mach64->crtc_gen_cntl >> 24) & 3) == 3) + svga->fb_only = 1; + else + svga->fb_only = 0; + svga_recalctimings(&mach64->svga); + break; + + case 0x40: case 0x41: case 0x42: case 0x43: + WRITE8(addr, mach64->ovr_clr, val); + break; + case 0x44: case 0x45: case 0x46: case 0x47: + WRITE8(addr, mach64->ovr_wid_left_right, val); + break; + case 0x48: case 0x49: case 0x4a: case 0x4b: + WRITE8(addr, mach64->ovr_wid_top_bottom, val); + break; + + case 0x68: case 0x69: case 0x6a: case 0x6b: + WRITE8(addr, mach64->cur_offset, val); + svga->hwcursor.addr = (mach64->cur_offset & 0xfffff) * 8; + mach64_cursor_dump(mach64); + break; + case 0x6c: case 0x6d: case 0x6e: case 0x6f: + WRITE8(addr, mach64->cur_horz_vert_posn, val); + svga->hwcursor.x = mach64->cur_horz_vert_posn & 0x7ff; + svga->hwcursor.y = (mach64->cur_horz_vert_posn >> 16) & 0x7ff; + mach64_cursor_dump(mach64); + break; + case 0x70: case 0x71: case 0x72: case 0x73: + WRITE8(addr, mach64->cur_horz_vert_off, val); + svga->hwcursor.xoff = mach64->cur_horz_vert_off & 0x3f; + svga->hwcursor.yoff = (mach64->cur_horz_vert_off >> 16) & 0x3f; + mach64_cursor_dump(mach64); + break; + + case 0x80: case 0x81: case 0x82: case 0x83: + WRITE8(addr, mach64->scratch_reg0, val); + break; + case 0x84: case 0x85: case 0x86: case 0x87: + WRITE8(addr, mach64->scratch_reg1, val); + break; + + case 0x90: case 0x91: case 0x92: case 0x93: + WRITE8(addr, mach64->clock_cntl, val); + ics2595_write(&mach64->ics2595, val & 0x40, val & 0xf); + svga_recalctimings(&mach64->svga); + break; + + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + WRITE8(addr, mach64->mem_cntl, val); + break; + + case 0xb4: + mach64->bank_w[0] = val * 32768; +#ifdef MACH64_DEBUG + pclog("mach64 : write bank A0000-A7FFF set to %08X\n", mach64->bank_w[0]); +#endif + break; + case 0xb5: case 0xb6: + mach64->bank_w[1] = val * 32768; +#ifdef MACH64_DEBUG + pclog("mach64 : write bank A8000-AFFFF set to %08X\n", mach64->bank_w[1]); +#endif + break; + case 0xb8: + mach64->bank_r[0] = val * 32768; +#ifdef MACH64_DEBUG + pclog("mach64 : read bank A0000-A7FFF set to %08X\n", mach64->bank_r[0]); +#endif + break; + case 0xb9: case 0xba: + mach64->bank_r[1] = val * 32768; +#ifdef MACH64_DEBUG + pclog("mach64 : read bank A8000-AFFFF set to %08X\n", mach64->bank_r[1]); +#endif + break; + + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + ati68860_ramdac_out((addr & 3) | ((mach64->dac_cntl & 3) << 2), val, &mach64->ramdac, &mach64->svga); + break; + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + WRITE8(addr, mach64->dac_cntl, val); + svga_set_ramdac_type(svga, (mach64->dac_cntl & 0x100) ? RAMDAC_8BIT : RAMDAC_6BIT); + ati68860_set_ramdac_type(&mach64->ramdac, (mach64->dac_cntl & 0x100) ? RAMDAC_8BIT : RAMDAC_6BIT); + break; + + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + WRITE8(addr, mach64->gen_test_cntl, val); +// if (val == 2) output = 3; + ati_eeprom_write(&mach64->eeprom, mach64->gen_test_cntl & 0x10, mach64->gen_test_cntl & 2, mach64->gen_test_cntl & 1); + mach64->gen_test_cntl = (mach64->gen_test_cntl & ~8) | (ati_eeprom_read(&mach64->eeprom) ? 8 : 0); + svga->hwcursor.ena = mach64->gen_test_cntl & 0x80; + mach64_cursor_dump(mach64); + break; + } +} +void mach64_ext_writew(uint32_t addr, uint16_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; +#ifdef MACH64_DEBUG + pclog("mach64_ext_writew : addr %08X val %04X\n", addr, val); +#endif + if (addr & 0x300) + { + mach64_queue(mach64, addr & 0x3fe, val, FIFO_WRITE_WORD); + } + else switch (addr & 0x3fe) + { + default: +#ifdef MACH64_DEBUG + pclog(" "); +#endif + mach64_ext_writeb(addr, val, p); +#ifdef MACH64_DEBUG + pclog(" "); +#endif + mach64_ext_writeb(addr + 1, val >> 8, p); + break; + } +} +void mach64_ext_writel(uint32_t addr, uint32_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; +#ifdef MACH64_DEBUG + if ((addr & 0x3c0) != 0x200) + pclog("mach64_ext_writel : addr %08X val %08X\n", addr, val); +#endif + if (addr & 0x300) + { + mach64_queue(mach64, addr & 0x3fc, val, FIFO_WRITE_DWORD); + } + else switch (addr & 0x3fc) + { + default: +#ifdef MACH64_DEBUG + pclog(" "); +#endif + mach64_ext_writew(addr, val, p); +#ifdef MACH64_DEBUG + pclog(" "); +#endif + mach64_ext_writew(addr + 2, val >> 16, p); + break; + } +} + +uint8_t mach64_ext_inb(uint16_t port, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + uint8_t ret; +// if (CS == 0x2be7) output = 3; + switch (port) + { + case 0x02ec: case 0x02ed: case 0x02ee: case 0x02ef: + case 0x7eec: case 0x7eed: case 0x7eee: case 0x7eef: + ret = mach64_ext_readb(0x00 | (port & 3), p); + break; + case 0x0aec: case 0x0aed: case 0x0aee: case 0x0aef: + ret = mach64_ext_readb(0x08 | (port & 3), p); + break; + case 0x0eec: case 0x0eed: case 0x0eee: case 0x0eef: + ret = mach64_ext_readb(0x0c | (port & 3), p); + break; + + case 0x12ec: case 0x12ed: case 0x12ee: case 0x12ef: + ret = mach64_ext_readb(0x10 | (port & 3), p); + break; + + case 0x16ec: case 0x16ed: case 0x16ee: case 0x16ef: + ret = mach64_ext_readb(0x14 | (port & 3), p); + break; + + case 0x1aec: + ret = mach64_ext_readb(0x18, p); + break; + + case 0x1eec: case 0x1eed: case 0x1eee: case 0x1eef: + ret = mach64_ext_readb(0x1c | (port & 3), p); + break; + + case 0x22ec: case 0x22ed: case 0x22ee: case 0x22ef: + ret = mach64_ext_readb(0x40 | (port & 3), p); + break; + case 0x26ec: case 0x26ed: case 0x26ee: case 0x26ef: + ret = mach64_ext_readb(0x44 | (port & 3), p); + break; + case 0x2aec: case 0x2aed: case 0x2aee: case 0x2aef: + ret = mach64_ext_readb(0x48 | (port & 3), p); + break; + + case 0x36ec: case 0x36ed: case 0x36ee: case 0x36ef: + ret = mach64_ext_readb(0x68 | (port & 3), p); + break; + case 0x3aec: case 0x3aed: case 0x3aee: case 0x3aef: + ret = mach64_ext_readb(0x6c | (port & 3), p); + break; + case 0x3eec: case 0x3eed: case 0x3eee: case 0x3eef: + ret = mach64_ext_readb(0x70 | (port & 3), p); + break; + + case 0x42ec: case 0x42ed: case 0x42ee: case 0x42ef: + ret = mach64_ext_readb(0x80 | (port & 3), p); + break; + case 0x46ec: case 0x46ed: case 0x46ee: case 0x46ef: + ret = mach64_ext_readb(0x84 | (port & 3), p); + break; + case 0x4aec: case 0x4aed: case 0x4aee: case 0x4aef: + ret = mach64_ext_readb(0x90 | (port & 3), p); + break; + + case 0x52ec: case 0x52ed: case 0x52ee: case 0x52ef: + ret = mach64_ext_readb(0xb0 | (port & 3), p); + break; + + case 0x56ec: + ret = mach64_ext_readb(0xb4, p); + break; + case 0x56ed: case 0x56ee: + ret = mach64_ext_readb(0xb5, p); + break; + case 0x5aec: + ret = mach64_ext_readb(0xb8, p); + break; + case 0x5aed: case 0x5aee: + ret = mach64_ext_readb(0xb9, p); + break; + + case 0x5eec: case 0x5eed: case 0x5eee: case 0x5eef: + ret = ati68860_ramdac_in((port & 3) | ((mach64->dac_cntl & 3) << 2), &mach64->ramdac, &mach64->svga); + break; + + case 0x62ec: case 0x62ed: case 0x62ee: case 0x62ef: + ret = mach64_ext_readb(0xc4 | (port & 3), p); + break; + + case 0x66ec: case 0x66ed: case 0x66ee: case 0x66ef: + ret = mach64_ext_readb(0xd0 | (port & 3), p); + break; + + case 0x6aec: case 0x6aed: case 0x6aee: case 0x6aef: + mach64->config_cntl = (mach64->config_cntl & ~0x3ff0) | ((mach64->linear_base >> 22) << 4); + READ8(port, mach64->config_cntl); + break; + + case 0x6eec: case 0x6eed: case 0x6eee: case 0x6eef: + ret = mach64_ext_readb(0xe0 | (port & 3), p); + break; + + case 0x72ec: + if (PCI) + ret = 7 | (3 << 3); /*PCI, 256Kx16 DRAM*/ + else + ret = 6 | (3 << 3); /*VLB, 256Kx16 DRAM*/ + break; + case 0x72ed: + ret = 5 << 1; /*ATI-68860*/ + break; + + default: + ret = 0; + break; + } +#ifdef MACH64_DEBUG + pclog("mach64_ext_inb : port %04X ret %02X %04X:%04X\n", port, ret, CS,cpu_state.pc); +#endif + return ret; +} +uint16_t mach64_ext_inw(uint16_t port, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + uint16_t ret; + switch (port) + { + default: +#ifdef MACH64_DEBUG + pclog(" "); +#endif + ret = mach64_ext_inb(port, p); +#ifdef MACH64_DEBUG + pclog(" "); +#endif + ret |= (mach64_ext_inb(port + 1, p) << 8); + break; + } +#ifdef MACH64_DEBUG + pclog("mach64_ext_inw : port %04X ret %04X\n", port, ret); +#endif + return ret; +} +uint32_t mach64_ext_inl(uint16_t port, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + uint32_t ret; + switch (port) + { + case 0x56ec: + ret = mach64_ext_readl(0xb4, p); + break; + case 0x5aec: + ret = mach64_ext_readl(0xb8, p); + break; + + default: +#ifdef MACH64_DEBUG + pclog(" "); +#endif + ret = mach64_ext_inw(port, p); +#ifdef MACH64_DEBUG + pclog(" "); +#endif + ret |= (mach64_ext_inw(port + 2, p) << 16); + break; + } +#ifdef MACH64_DEBUG + pclog("mach64_ext_inl : port %04X ret %08X\n", port, ret); +#endif + return ret; +} + +void mach64_ext_outb(uint16_t port, uint8_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; +#ifdef MACH64_DEBUG + pclog("mach64_ext_outb : port %04X val %02X %04X:%04X\n", port, val, CS,cpu_state.pc); +#endif + switch (port) + { + case 0x02ec: case 0x02ed: case 0x02ee: case 0x02ef: + case 0x7eec: case 0x7eed: case 0x7eee: case 0x7eef: + mach64_ext_writeb(0x00 | (port & 3), val, p); + break; + case 0x0aec: case 0x0aed: case 0x0aee: case 0x0aef: + mach64_ext_writeb(0x08 | (port & 3), val, p); + break; + case 0x0eec: case 0x0eed: case 0x0eee: case 0x0eef: + mach64_ext_writeb(0x0c | (port & 3), val, p); + break; + + case 0x16ec: case 0x16ed: case 0x16ee: case 0x16ef: + mach64_ext_writeb(0x14 | (port & 3), val, p); + break; + + case 0x1aec: + mach64_ext_writeb(0x18, val, p); + break; + + case 0x1eec: case 0x1eed: case 0x1eee: case 0x1eef: + mach64_ext_writeb(0x1c | (port & 3), val, p); + break; + + case 0x22ec: case 0x22ed: case 0x22ee: case 0x22ef: + mach64_ext_writeb(0x40 | (port & 3), val, p); + break; + case 0x26ec: case 0x26ed: case 0x26ee: case 0x26ef: + mach64_ext_writeb(0x44 | (port & 3), val, p); + break; + case 0x2aec: case 0x2aed: case 0x2aee: case 0x2aef: + mach64_ext_writeb(0x48 | (port & 3), val, p); + break; + + case 0x36ec: case 0x36ed: case 0x36ee: case 0x36ef: + mach64_ext_writeb(0x68 | (port & 3), val, p); + break; + case 0x3aec: case 0x3aed: case 0x3aee: case 0x3aef: + mach64_ext_writeb(0x6c | (port & 3), val, p); + break; + case 0x3eec: case 0x3eed: case 0x3eee: case 0x3eef: + mach64_ext_writeb(0x70 | (port & 3), val, p); + break; + + case 0x42ec: case 0x42ed: case 0x42ee: case 0x42ef: + mach64_ext_writeb(0x80 | (port & 3), val, p); + break; + case 0x46ec: case 0x46ed: case 0x46ee: case 0x46ef: + mach64_ext_writeb(0x84 | (port & 3), val, p); + break; + case 0x4aec: case 0x4aed: case 0x4aee: case 0x4aef: + mach64_ext_writeb(0x90 | (port & 3), val, p); + break; + + case 0x52ec: case 0x52ed: case 0x52ee: case 0x52ef: + mach64_ext_writeb(0xb0 | (port & 3), val, p); + break; + + case 0x56ec: + mach64_ext_writeb(0xb4, val, p); + break; + case 0x56ed: case 0x56ee: + mach64_ext_writeb(0xb5, val, p); + break; + case 0x5aec: + mach64_ext_writeb(0xb8, val, p); + break; + case 0x5aed: case 0x5aee: + mach64_ext_writeb(0xb9, val, p); + break; + + case 0x5eec: case 0x5eed: case 0x5eee: case 0x5eef: + ati68860_ramdac_out((port & 3) | ((mach64->dac_cntl & 3) << 2), val, &mach64->ramdac, &mach64->svga); + break; + + case 0x62ec: case 0x62ed: case 0x62ee: case 0x62ef: + mach64_ext_writeb(0xc4 | (port & 3), val, p); + break; + + case 0x66ec: case 0x66ed: case 0x66ee: case 0x66ef: + mach64_ext_writeb(0xd0 | (port & 3), val, p); + break; + + case 0x6aec: case 0x6aed: case 0x6aee: case 0x6aef: + WRITE8(port, mach64->config_cntl, val); + mach64_updatemapping(mach64); + break; + } +} +void mach64_ext_outw(uint16_t port, uint16_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; +#ifdef MACH64_DEBUG + pclog("mach64_ext_outw : port %04X val %04X\n", port, val); +#endif + switch (port) + { + default: +#ifdef MACH64_DEBUG + pclog(" "); +#endif + mach64_ext_outb(port, val, p); +#ifdef MACH64_DEBUG + pclog(" "); +#endif + mach64_ext_outb(port + 1, val >> 8, p); + break; + } +} +void mach64_ext_outl(uint16_t port, uint32_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + pclog("mach64_ext_outl : port %04X val %08X\n", port, val); + switch (port) + { + default: +#ifdef MACH64_DEBUG + pclog(" "); +#endif + mach64_ext_outw(port, val, p); +#ifdef MACH64_DEBUG + pclog(" "); +#endif + mach64_ext_outw(port + 2, val >> 16, p); + break; + } +} + +void mach64_write(uint32_t addr, uint8_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + svga_t *svga = &mach64->svga; +// pclog("mach64_write : %05X %02X ", addr, val); + addr = (addr & 0x7fff) + mach64->bank_w[(addr >> 15) & 1]; +// pclog("%08X\n", addr); + svga_write_linear(addr, val, svga); +} + +uint8_t mach64_read(uint32_t addr, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + svga_t *svga = &mach64->svga; + uint8_t ret; +// pclog("mach64_read : %05X ", addr); + addr = (addr & 0x7fff) + mach64->bank_r[(addr >> 15) & 1]; + ret = svga_read_linear(addr, svga); +// pclog("%08X %02X\n", addr, ret); + return ret; +} + +void mach64_hwcursor_draw(svga_t *svga, int displine) +{ + mach64_t *mach64 = (mach64_t *)svga->p; + int x, offset; + uint8_t dat; + uint32_t col0 = mach64->ramdac.pallook[0]; + uint32_t col1 = mach64->ramdac.pallook[1]; + int y_add = enable_overscan ? 16 : 0; + int x_add = enable_overscan ? 8 : 0; + + offset = svga->hwcursor_latch.xoff; + for (x = 0; x < 64 - svga->hwcursor_latch.xoff; x += 4) + { + dat = svga->vram[svga->hwcursor_latch.addr + (offset >> 2)]; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 32 + x_add] = (dat & 1) ? col1 : col0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 32 + x_add] ^= 0xFFFFFF; + dat >>= 2; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 33 + x_add] = (dat & 1) ? col1 : col0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 33 + x_add] ^= 0xFFFFFF; + dat >>= 2; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 34 + x_add] = (dat & 1) ? col1 : col0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 34 + x_add] ^= 0xFFFFFF; + dat >>= 2; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 35 + x_add] = (dat & 1) ? col1 : col0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 35 + x_add] ^= 0xFFFFFF; + dat >>= 2; + offset += 4; + } + svga->hwcursor_latch.addr += 16; +} + +static void mach64_io_remove(mach64_t *mach64) +{ + int c; + + io_removehandler(0x03c0, 0x0020, mach64_in, NULL, NULL, mach64_out, NULL, NULL, mach64); + + for (c = 0; c < 8; c++) + { + io_removehandler((c * 0x1000) + 0x2ec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + io_removehandler((c * 0x1000) + 0x6ec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + io_removehandler((c * 0x1000) + 0xaec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + io_removehandler((c * 0x1000) + 0xeec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + } + + io_removehandler(0x01ce, 0x0002, mach64_in, NULL, NULL, mach64_out, NULL, NULL, mach64); +} + +static void mach64_io_set(mach64_t *mach64) +{ + int c; + + mach64_io_remove(mach64); + + io_sethandler(0x03c0, 0x0020, mach64_in, NULL, NULL, mach64_out, NULL, NULL, mach64); + + for (c = 0; c < 8; c++) + { + io_sethandler((c * 0x1000) + 0x2ec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + io_sethandler((c * 0x1000) + 0x6ec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + io_sethandler((c * 0x1000) + 0xaec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + io_sethandler((c * 0x1000) + 0xeec, 0x0004, mach64_ext_inb, mach64_ext_inw, mach64_ext_inl, mach64_ext_outb, mach64_ext_outw, mach64_ext_outl, mach64); + } + + io_sethandler(0x01ce, 0x0002, mach64_in, NULL, NULL, mach64_out, NULL, NULL, mach64); +} + +uint8_t mach64_pci_read(int func, int addr, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + svga_t *svga = &mach64->svga; + +// pclog("Mach64 PCI read %08X\n", addr); + + switch (addr) + { + case 0x00: return 0x02; /*ATi*/ + case 0x01: return 0x10; + + case 0x02: return 'X'; /*88800GX*/ + case 0x03: return 'G'; + + case PCI_REG_COMMAND: + return mach64->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/ + + case 0x07: return 1 << 1; /*Medium DEVSEL timing*/ + + case 0x08: return 0; /*Revision ID*/ + case 0x09: return 0; /*Programming interface*/ + + case 0x0a: return 0x01; /*Supports VGA interface, XGA compatible*/ + case 0x0b: return 0x03; + + case 0x10: return 0x00; /*Linear frame buffer address*/ + case 0x11: return 0x00; + case 0x12: return mach64->linear_base >> 16; + case 0x13: return mach64->linear_base >> 24; + + case 0x30: return mach64->pci_regs[0x30] & 0x01; /*BIOS ROM address*/ + case 0x31: return 0x00; + case 0x32: return mach64->pci_regs[0x32]; + case 0x33: return mach64->pci_regs[0x33]; + } + return 0; +} + +void mach64_pci_write(int func, int addr, uint8_t val, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + +// pclog("Mach64 PCI write %08X %02X\n", addr, val); + + switch (addr) + { + case PCI_REG_COMMAND: + if (romset == ROM_KN97) return; + mach64->pci_regs[PCI_REG_COMMAND] = val & 0x27; + if (val & PCI_COMMAND_IO) + mach64_io_set(mach64); + else + mach64_io_remove(mach64); + mach64_updatemapping(mach64); + break; + + case 0x12: + mach64->linear_base = (mach64->linear_base & 0xff000000) | ((val & 0x80) << 16); + mach64_updatemapping(mach64); + break; + case 0x13: + mach64->linear_base = (mach64->linear_base & 0x800000) | (val << 24); + mach64_updatemapping(mach64); + break; + + case 0x30: case 0x32: case 0x33: + mach64->pci_regs[addr] = val; + if (mach64->pci_regs[0x30] & 0x01) + { + uint32_t addr = (mach64->pci_regs[0x32] << 16) | (mach64->pci_regs[0x33] << 24); + pclog("Mach64 bios_rom enabled at %08x\n", addr); + mem_mapping_set_addr(&mach64->bios_rom.mapping, addr, 0x8000); + } + else + { + pclog("Mach64 bios_rom disabled\n"); + mem_mapping_disable(&mach64->bios_rom.mapping); + } + return; + } +} + +void *mach64gx_init() +{ + int c; + mach64_t *mach64 = malloc(sizeof(mach64_t)); + memset(mach64, 0, sizeof(mach64_t)); + + mach64->vram_size = device_get_config_int("memory"); + mach64->vram_mask = (mach64->vram_size << 20) - 1; + + svga_init(&mach64->svga, mach64, mach64->vram_size << 20, + mach64_recalctimings, + mach64_in, mach64_out, + mach64_hwcursor_draw, + NULL); + + rom_init(&mach64->bios_rom, "roms/mach64gx/bios.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + if (PCI) + mem_mapping_disable(&mach64->bios_rom.mapping); + + mem_mapping_add(&mach64->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL, 0, &mach64->svga); + mem_mapping_add(&mach64->mmio_linear_mapping, 0, 0, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, 0, mach64); + mem_mapping_add(&mach64->mmio_mapping, 0xbc000, 0x04000, mach64_ext_readb, mach64_ext_readw, mach64_ext_readl, mach64_ext_writeb, mach64_ext_writew, mach64_ext_writel, NULL, 0, mach64); + mem_mapping_disable(&mach64->mmio_mapping); + + mach64_io_set(mach64); + + pci_add(mach64_pci_read, mach64_pci_write, mach64); + + mach64->pci_regs[PCI_REG_COMMAND] = 3; + mach64->pci_regs[0x30] = 0x00; + mach64->pci_regs[0x32] = 0x0c; + mach64->pci_regs[0x33] = 0x00; + + ati_eeprom_load(&mach64->eeprom, "mach64.nvr", 1); + + ati68860_ramdac_init(&mach64->ramdac); + + mach64->dac_cntl = 5 << 16; /*ATI 68860 RAMDAC*/ + + mach64->dst_cntl = 3; + + mach64->wake_fifo_thread = thread_create_event(); + mach64->fifo_not_full_event = thread_create_event(); + mach64->fifo_thread = thread_create(fifo_thread, mach64); + + return mach64; +} + +int mach64gx_available() +{ + return rom_present("roms/mach64gx/bios.bin"); +} + +void mach64_close(void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + + svga_close(&mach64->svga); + + free(mach64); +} + +void mach64_speed_changed(void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + + svga_recalctimings(&mach64->svga); +} + +void mach64_force_redraw(void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + + mach64->svga.fullchange = changeframecount; +} + +void mach64_add_status_info(char *s, int max_len, void *p) +{ + mach64_t *mach64 = (mach64_t *)p; + char temps[256]; + uint64_t new_time = timer_read(); + uint64_t status_diff = new_time - mach64->status_time; + mach64->status_time = new_time; + + if (((mach64->crtc_gen_cntl >> 24) & 3) == 3) + { + svga_t *svga = &mach64->svga; + char temps[128]; + int bpp = 4; + + strncat(s, "Mach64 in native mode\n", max_len); + + switch ((mach64->crtc_gen_cntl >> 8) & 7) + { + case 1: bpp = 4; break; + case 2: bpp = 8; break; + case 3: bpp = 15; break; + case 4: bpp = 16; break; + case 5: bpp = 24; break; + case 6: bpp = 32; break; + } + + sprintf(temps, "Mach64 colour depth : %i bpp\n", bpp); + strncat(s, temps, max_len); + + sprintf(temps, "Mach64 resolution : %i x %i\n", svga->hdisp, svga->dispend); + strncat(s, temps, max_len); + + sprintf(temps, "Mach64 refresh rate : %i Hz\n\n", svga->frames); + svga->frames = 0; + strncat(s, temps, max_len); + } + else + { + strncat(s, "Mach64 in SVGA mode\n", max_len); + svga_add_status_info(s, max_len, &mach64->svga); + } + + sprintf(temps, "%f%% CPU\n%f%% CPU (real)\n\n", ((double)mach64->blitter_time * 100.0) / timer_freq, ((double)mach64->blitter_time * 100.0) / status_diff); + strncat(s, temps, max_len); + + mach64->blitter_time = 0; +} + +static device_config_t mach64gx_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } + }, + .default_int = 4 + }, + { + .type = -1 + } +}; + +device_t mach64gx_device = +{ + "ATI Mach64GX", + 0, + mach64gx_init, + mach64_close, + mach64gx_available, + mach64_speed_changed, + mach64_force_redraw, + mach64_add_status_info, + mach64gx_config +}; diff --git a/src/vid_ati_mach64.h b/src/vid_ati_mach64.h new file mode 100644 index 000000000..95a7e9744 --- /dev/null +++ b/src/vid_ati_mach64.h @@ -0,0 +1 @@ +extern device_t mach64gx_device; diff --git a/src/vid_cga.c b/src/vid_cga.c new file mode 100644 index 000000000..7e398e1bd --- /dev/null +++ b/src/vid_cga.c @@ -0,0 +1,524 @@ +/*CGA emulation*/ +#include +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "timer.h" +#include "video.h" +#include "vid_cga.h" +#include "vid_cga_comp.h" + +static int i_filt[8],q_filt[8]; + +static uint8_t tarray[65536]; + +int cga_brown; +int cga_color_burst; + +static uint8_t crtcmask[32] = +{ + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +void cga_recalctimings(cga_t *cga); + +void cga_out(uint16_t addr, uint8_t val, void *p) +{ + cga_t *cga = (cga_t *)p; + uint8_t old; +// pclog("CGA_OUT %04X %02X\n", addr, val); + switch (addr) + { + case 0x3D4: + cga->crtcreg = val & 31; + return; + case 0x3D5: + old = cga->crtc[cga->crtcreg]; + cga->crtc[cga->crtcreg] = val & crtcmask[cga->crtcreg]; + if (old != val) + { + if (cga->crtcreg < 0xe || cga->crtcreg > 0x10) + { + fullchange = changeframecount; + cga_recalctimings(cga); + } + } + return; + case 0x3D8: + if (((cga->cgamode ^ val) & 5) != 0) { + cga->cgamode = val; + update_cga16_color(cga); + } + cga->cgamode = val; + return; + case 0x3D9: + cga->cgacol = val; + return; + } +} + +uint8_t cga_in(uint16_t addr, void *p) +{ + cga_t *cga = (cga_t *)p; +// pclog("CGA_IN %04X\n", addr); + switch (addr) + { + case 0x3D4: + return cga->crtcreg; + case 0x3D5: + return cga->crtc[cga->crtcreg]; + case 0x3DA: + return cga->cgastat; + } + return 0xFF; +} + +void cga_write(uint32_t addr, uint8_t val, void *p) +{ + cga_t *cga = (cga_t *)p; +// pclog("CGA_WRITE %04X %02X\n", addr, val); + /* Horrible hack, I know, but it's the only way to fix the 440FX BIOS filling the VRAM with garbage until Tom fixes the memory emulation. */ + if ((cs == 0xE0000) && (cpu_state.pc == 0xBF2F) && (romset == ROM_440FX)) { egawrites++; return; } + if ((cs == 0xE0000) && (cpu_state.pc == 0xBF77) && (romset == ROM_440FX)) { egawrites++; return; } + cga->vram[addr & 0x3fff] = val; + cga->charbuffer[ ((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)) & 0xfc] = val; + cga->charbuffer[(((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)) & 0xfc) | 1] = val; + egawrites++; + cycles -= 4; +} + +uint8_t cga_read(uint32_t addr, void *p) +{ + cga_t *cga = (cga_t *)p; + cycles -= 4; + cga->charbuffer[ ((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)) & 0xfc] = cga->vram[addr & 0x3fff]; + cga->charbuffer[(((int)(((cga->dispontime - cga->vidtime) * 2) / CGACONST)) & 0xfc) | 1] = cga->vram[addr & 0x3fff]; + egareads++; +// pclog("CGA_READ %04X\n", addr); + return cga->vram[addr & 0x3fff]; +} + +void cga_recalctimings(cga_t *cga) +{ + double disptime; + double _dispontime, _dispofftime; + pclog("Recalc - %i %i %i\n", cga->crtc[0], cga->crtc[1], cga->cgamode & 1); + if (cga->cgamode & 1) + { + disptime = cga->crtc[0] + 1; + _dispontime = cga->crtc[1]; + } + else + { + disptime = (cga->crtc[0] + 1) << 1; + _dispontime = cga->crtc[1] << 1; + } + _dispofftime = disptime - _dispontime; +// printf("%i %f %f %f %i %i\n",cgamode&1,disptime,dispontime,dispofftime,crtc[0],crtc[1]); + _dispontime *= CGACONST; + _dispofftime *= CGACONST; +// printf("Timings - on %f off %f frame %f second %f\n",dispontime,dispofftime,(dispontime+dispofftime)*262.0,(dispontime+dispofftime)*262.0*59.92); + cga->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + cga->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + +static int ntsc_col[8][8]= +{ + {0,0,0,0,0,0,0,0}, /*Black*/ + {0,0,1,1,1,1,0,0}, /*Blue*/ + {1,0,0,0,0,1,1,1}, /*Green*/ + {0,0,0,0,1,1,1,1}, /*Cyan*/ + {1,1,1,1,0,0,0,0}, /*Red*/ + {0,1,1,1,1,0,0,0}, /*Magenta*/ + {1,1,0,0,0,0,1,1}, /*Yellow*/ + {1,1,1,1,1,1,1,1} /*White*/ +}; + +void cga_poll(void *p) +{ + cga_t *cga = (cga_t *)p; + uint16_t ca = (cga->crtc[15] | (cga->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + uint16_t dat; + int cols[4]; + int col; + int oldsc; + int y_buf[8] = {0, 0, 0, 0, 0, 0, 0, 0}, y_val, y_tot; + int i_buf[8] = {0, 0, 0, 0, 0, 0, 0, 0}, i_val, i_tot; + int q_buf[8] = {0, 0, 0, 0, 0, 0, 0, 0}, q_val, q_tot; + int r, g, b; + uint8_t *tline; + if (!cga->linepos) + { + cga->vidtime += cga->dispofftime; + cga->cgastat |= 1; + cga->linepos = 1; + oldsc = cga->sc; + if ((cga->crtc[8] & 3) == 3) + cga->sc = ((cga->sc << 1) + cga->oddeven) & 7; + if (cga->cgadispon) + { + if (cga->displine < cga->firstline) + { + cga->firstline = cga->displine; +// printf("Firstline %i\n",firstline); + } + cga->lastline = cga->displine; + for (c = 0; c < 8; c++) + { + if ((cga->cgamode & 0x12) == 0x12) + { + buffer->line[cga->displine][c] = 0; + if (cga->cgamode & 1) buffer->line[cga->displine][c + (cga->crtc[1] << 3) + 8] = 0; + else buffer->line[cga->displine][c + (cga->crtc[1] << 4) + 8] = 0; + } + else + { + buffer->line[cga->displine][c] = (cga->cgacol & 15) + 16; + if (cga->cgamode & 1) buffer->line[cga->displine][c + (cga->crtc[1] << 3) + 8] = (cga->cgacol & 15) + 16; + else buffer->line[cga->displine][c + (cga->crtc[1] << 4) + 8] = (cga->cgacol & 15) + 16; + } + } + if (cga->cgamode & 1) + { + for (x = 0; x < cga->crtc[1]; x++) + { + chr = cga->charbuffer[x << 1]; + attr = cga->charbuffer[(x << 1) + 1]; + drawcursor = ((cga->ma == ca) && cga->con && cga->cursoron); + if (cga->cgamode & 0x20) + { + cols[1] = (attr & 15) + 16; + cols[0] = ((attr >> 4) & 7) + 16; + if ((cga->cgablink & 8) && (attr & 0x80) && !cga->drawcursor) + cols[1] = cols[0]; + } + else + { + cols[1] = (attr & 15) + 16; + cols[0] = (attr >> 4) + 16; + } + if (drawcursor) + { + for (c = 0; c < 8; c++) + buffer->line[cga->displine][(x << 3) + c + 8] = cols[(fontdat[chr][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[cga->displine][(x << 3) + c + 8] = cols[(fontdat[chr][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + cga->ma++; + } + } + else if (!(cga->cgamode & 2)) + { + for (x = 0; x < cga->crtc[1]; x++) + { + chr = cga->vram[((cga->ma << 1) & 0x3fff)]; + attr = cga->vram[(((cga->ma << 1) + 1) & 0x3fff)]; + drawcursor = ((cga->ma == ca) && cga->con && cga->cursoron); + if (cga->cgamode & 0x20) + { + cols[1] = (attr & 15) + 16; + cols[0] = ((attr >> 4) & 7) + 16; + if ((cga->cgablink & 8) && (attr & 0x80)) cols[1] = cols[0]; + } + else + { + cols[1] = (attr & 15) + 16; + cols[0] = (attr >> 4) + 16; + } + cga->ma++; + if (drawcursor) + { + for (c = 0; c < 8; c++) + buffer->line[cga->displine][(x << 4)+(c << 1) + 8] = buffer->line[cga->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[cga->displine][(x << 4) + (c << 1) + 8] = buffer->line[cga->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][cga->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + } + } + else if (!(cga->cgamode & 16)) + { + cols[0] = (cga->cgacol & 15) | 16; + col = (cga->cgacol & 16) ? 24 : 16; + if (cga->cgamode & 4) + { + cols[1] = col | 3; + cols[2] = col | 4; + cols[3] = col | 7; + } + else if (cga->cgacol & 32) + { + cols[1] = col | 3; + cols[2] = col | 5; + cols[3] = col | 7; + } + else + { + cols[1] = col | 2; + cols[2] = col | 4; + cols[3] = col | 6; + } + for (x = 0; x < cga->crtc[1]; x++) + { + dat = (cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000)] << 8) | cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000) + 1]; + cga->ma++; + for (c = 0; c < 8; c++) + { + buffer->line[cga->displine][(x << 4) + (c << 1) + 8] = + buffer->line[cga->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + dat <<= 2; + } + } + } + else + { + cols[0] = 0; cols[1] = (cga->cgacol & 15) + 16; + for (x = 0; x < cga->crtc[1]; x++) + { + dat = (cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000)] << 8) | cga->vram[((cga->ma << 1) & 0x1fff) + ((cga->sc & 1) * 0x2000) + 1]; + cga->ma++; + for (c = 0; c < 16; c++) + { + buffer->line[cga->displine][(x << 4) + c + 8] = cols[dat >> 15]; + dat <<= 1; + } + } + } + } + else + { + cols[0] = ((cga->cgamode & 0x12) == 0x12) ? 0 : (cga->cgacol & 15) + 16; + if (cga->cgamode & 1) hline(buffer, 0, cga->displine, (cga->crtc[1] << 3) + 16, cols[0]); + else hline(buffer, 0, cga->displine, (cga->crtc[1] << 4) + 16, cols[0]); + } + + if (cga->cgamode & 1) x = (cga->crtc[1] << 3) + 16; + else x = (cga->crtc[1] << 4) + 16; + + if (cga_comp) + { + tline = (uint8_t *) buffer32->line[cga->displine]; + + for (c = 0; c < x; c++) + { + tarray[c] = buffer->line[cga->displine][c] & 0xf; + } + + Composite_Process(cga, 0, x >> 2, tarray); + + for (c = 0; c < x; c++) + { + ((uint32_t *) tline)[c] = ((uint32_t *) tarray)[c]; + } + } + + cga->sc = oldsc; + if (cga->vc == cga->crtc[7] && !cga->sc) + cga->cgastat |= 8; + cga->displine++; + if (cga->displine >= 360) + cga->displine = 0; + } + else + { + cga->vidtime += cga->dispontime; + cga->linepos = 0; + if (cga->vsynctime) + { + cga->vsynctime--; + if (!cga->vsynctime) + cga->cgastat &= ~8; + } + if (cga->sc == (cga->crtc[11] & 31) || ((cga->crtc[8] & 3) == 3 && cga->sc == ((cga->crtc[11] & 31) >> 1))) + { + cga->con = 0; + cga->coff = 1; + } + if ((cga->crtc[8] & 3) == 3 && cga->sc == (cga->crtc[9] >> 1)) + cga->maback = cga->ma; + if (cga->vadj) + { + cga->sc++; + cga->sc &= 31; + cga->ma = cga->maback; + cga->vadj--; + if (!cga->vadj) + { + cga->cgadispon = 1; + cga->ma = cga->maback = (cga->crtc[13] | (cga->crtc[12] << 8)) & 0x3fff; + cga->sc = 0; + } + } + else if (cga->sc == cga->crtc[9]) + { + cga->maback = cga->ma; + cga->sc = 0; + oldvc = cga->vc; + cga->vc++; + cga->vc &= 127; + + if (cga->vc == cga->crtc[6]) + cga->cgadispon = 0; + + if (oldvc == cga->crtc[4]) + { + cga->vc = 0; + cga->vadj = cga->crtc[5]; + if (!cga->vadj) cga->cgadispon = 1; + if (!cga->vadj) cga->ma = cga->maback = (cga->crtc[13] | (cga->crtc[12] << 8)) & 0x3fff; + if ((cga->crtc[10] & 0x60) == 0x20) cga->cursoron = 0; + else cga->cursoron = cga->cgablink & 8; + } + + if (cga->vc == cga->crtc[7]) + { + cga->cgadispon = 0; + cga->displine = 0; + // cga->vsynctime = (cga->crtc[3] >> 4) + 1; + cga->vsynctime = 16; + if (cga->crtc[7]) + { + if (cga->cgamode & 1) x = (cga->crtc[1] << 3) + 16; + else x = (cga->crtc[1] << 4) + 16; + cga->lastline++; + if (x != xsize || (cga->lastline - cga->firstline) != ysize) + { + xsize = x; + ysize = cga->lastline - cga->firstline; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + updatewindowsize(xsize, (ysize << 1) + 16); + } + +startblit(); + if (cga_comp) + video_blit_memtoscreen(0, cga->firstline - 4, 0, (cga->lastline - cga->firstline) + 8, xsize, (cga->lastline - cga->firstline) + 8); + else + video_blit_memtoscreen_8(0, cga->firstline - 4, xsize, (cga->lastline - cga->firstline) + 8); + frames++; +endblit(); + video_res_x = xsize - 16; + video_res_y = ysize; + if (cga->cgamode & 1) + { + video_res_x /= 8; + video_res_y /= cga->crtc[9] + 1; + video_bpp = 0; + } + else if (!(cga->cgamode & 2)) + { + video_res_x /= 16; + video_res_y /= cga->crtc[9] + 1; + video_bpp = 0; + } + else if (!(cga->cgamode & 16)) + { + video_res_x /= 2; + video_bpp = 2; + } + else + { + video_bpp = 1; + } + } + cga->firstline = 1000; + cga->lastline = 0; + cga->cgablink++; + cga->oddeven ^= 1; + } + } + else + { + cga->sc++; + cga->sc &= 31; + cga->ma = cga->maback; + } + if (cga->cgadispon) cga->cgastat &= ~1; + if ((cga->sc == (cga->crtc[10] & 31) || ((cga->crtc[8] & 3) == 3 && cga->sc == ((cga->crtc[10] & 31) >> 1)))) + cga->con = 1; + if (cga->cgadispon && (cga->cgamode & 1)) + { + for (x = 0; x < (cga->crtc[1] << 1); x++) + cga->charbuffer[x] = cga->vram[(((cga->ma << 1) + x) & 0x3fff)]; + } + } +} + +void cga_init(cga_t *cga) +{ +} + +void *cga_standalone_init() +{ + int c; + int cga_tint = -2; + cga_t *cga = malloc(sizeof(cga_t)); + memset(cga, 0, sizeof(cga_t)); + + cga->vram = malloc(0x4000); + + cga_comp_init(cga); + timer_add(cga_poll, &cga->vidtime, TIMER_ALWAYS_ENABLED, cga); + mem_mapping_add(&cga->mapping, 0xb8000, 0x08000, cga_read, NULL, NULL, cga_write, NULL, NULL, NULL, 0, cga); + io_sethandler(0x03d0, 0x0010, cga_in, NULL, NULL, cga_out, NULL, NULL, cga); + + for (c = 0; c < 8192; c++) + { + ((uint64_t *) tarray)[c] = 0; + } + + overscan_x = overscan_y = 16; + + return cga; +} + +void cga_close(void *p) +{ + cga_t *cga = (cga_t *)p; + + free(cga->vram); + free(cga); +} + +void cga_speed_changed(void *p) +{ + cga_t *cga = (cga_t *)p; + + cga_recalctimings(cga); +} + +device_t cga_device = +{ + "CGA (Old)", + 0, + cga_standalone_init, + cga_close, + NULL, + cga_speed_changed, + NULL, + NULL +}; + +device_t cga_new_device = +{ + "CGA (New)", + 0, + cga_standalone_init, + cga_close, + NULL, + cga_speed_changed, + NULL, + NULL +}; diff --git a/src/vid_cga.h b/src/vid_cga.h new file mode 100644 index 000000000..534608731 --- /dev/null +++ b/src/vid_cga.h @@ -0,0 +1,41 @@ +typedef struct cga_t +{ + mem_mapping_t mapping; + + int crtcreg; + uint8_t crtc[32]; + + uint8_t cgastat; + + uint8_t cgamode, cgacol; + + int linepos, displine; + int sc, vc; + int cgadispon; + int con, coff, cursoron, cgablink; + int vsynctime, vadj; + uint16_t ma, maback; + int oddeven; + + int dispontime, dispofftime; + int vidtime; + + int firstline, lastline; + + int drawcursor; + + uint8_t *vram; + + uint8_t charbuffer[256]; +} cga_t; + +void cga_init(cga_t *cga); +void cga_out(uint16_t addr, uint8_t val, void *p); +uint8_t cga_in(uint16_t addr, void *p); +void cga_write(uint32_t addr, uint8_t val, void *p); +uint8_t cga_read(uint32_t addr, void *p); +void cga_recalctimings(cga_t *cga); +void cga_poll(void *p); + +extern device_t cga_new_device; +extern device_t cga_device; diff --git a/src/vid_cga_comp.c b/src/vid_cga_comp.c new file mode 100644 index 000000000..7cacbedff --- /dev/null +++ b/src/vid_cga_comp.c @@ -0,0 +1,356 @@ +/* Code borrowed from DOSBox and adapted by OBattler. + Original author: reenigne. */ + +#include +#include +#include + +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "timer.h" +#include "video.h" +#include "vid_cga.h" +#include "vid_cga_comp.h" + +int CGA_Composite_Table[1024]; + +static double brightness = 0; +static double contrast = 100; +static double saturation = 100; +static double sharpness = 0; +static double hue_offset = 0; + +// New algorithm by reenigne +// Works in all CGA modes/color settings and can simulate older and newer CGA revisions + +static const double tau = 6.28318531; // == 2*pi + +static unsigned char chroma_multiplexer[256] = { + 2, 2, 2, 2, 114,174, 4, 3, 2, 1,133,135, 2,113,150, 4, + 133, 2, 1, 99, 151,152, 2, 1, 3, 2, 96,136, 151,152,151,152, + 2, 56, 62, 4, 111,250,118, 4, 0, 51,207,137, 1,171,209, 5, + 140, 50, 54,100, 133,202, 57, 4, 2, 50,153,149, 128,198,198,135, + 32, 1, 36, 81, 147,158, 1, 42, 33, 1,210,254, 34,109,169, 77, + 177, 2, 0,165, 189,154, 3, 44, 33, 0, 91,197, 178,142,144,192, + 4, 2, 61, 67, 117,151,112, 83, 4, 0,249,255, 3,107,249,117, + 147, 1, 50,162, 143,141, 52, 54, 3, 0,145,206, 124,123,192,193, + 72, 78, 2, 0, 159,208, 4, 0, 53, 58,164,159, 37,159,171, 1, + 248,117, 4, 98, 212,218, 5, 2, 54, 59, 93,121, 176,181,134,130, + 1, 61, 31, 0, 160,255, 34, 1, 1, 58,197,166, 0,177,194, 2, + 162,111, 34, 96, 205,253, 32, 1, 1, 57,123,125, 119,188,150,112, + 78, 4, 0, 75, 166,180, 20, 38, 78, 1,143,246, 42,113,156, 37, + 252, 4, 1,188, 175,129, 1, 37, 118, 4, 88,249, 202,150,145,200, + 61, 59, 60, 60, 228,252,117, 77, 60, 58,248,251, 81,212,254,107, + 198, 59, 58,169, 250,251, 81, 80, 100, 58,154,250, 251,252,252,252}; + +static double intensity[4] = { + 77.175381, 88.654656, 166.564623, 174.228438}; + +#define NEW_CGA(c,i,r,g,b) (((c)/0.72)*0.29 + ((i)/0.28)*0.32 + ((r)/0.28)*0.1 + ((g)/0.28)*0.22 + ((b)/0.28)*0.07) + +double mode_brightness; +double mode_contrast; +double mode_hue; +double min_v; +double max_v; + +double video_ri, video_rq, video_gi, video_gq, video_bi, video_bq; +int video_sharpness; +int tandy_mode_control = 0; + +static bool new_cga = 0; +static bool is_bw = 0; +static bool is_bpp1 = 0; + +static uint8_t comp_pal[256][3]; + +static Bit8u byte_clamp_other(int v) { return v < 0 ? 0 : (v > 255 ? 255 : v); } + +FILE *df; + +void update_cga16_color(cga_t *cga) { + int x; + Bit32u x2; + + if (!new_cga) { + min_v = chroma_multiplexer[0] + intensity[0]; + max_v = chroma_multiplexer[255] + intensity[3]; + } + else { + double i0 = intensity[0]; + double i3 = intensity[3]; + min_v = NEW_CGA(chroma_multiplexer[0], i0, i0, i0, i0); + max_v = NEW_CGA(chroma_multiplexer[255], i3, i3, i3, i3); + } + mode_contrast = 256/(max_v - min_v); + mode_brightness = -min_v*mode_contrast; + if ((cga->cgamode & 3) == 1) + mode_hue = 14; + else + mode_hue = 4; + + mode_contrast *= contrast * (new_cga ? 1.2 : 1)/100; // new CGA: 120% + mode_brightness += (new_cga ? brightness-10 : brightness)*5; // new CGA: -10 + double mode_saturation = (new_cga ? 4.35 : 2.9)*saturation/100; // new CGA: 150% + + for (x = 0; x < 1024; ++x) { + int phase = x & 3; + int right = (x >> 2) & 15; + int left = (x >> 6) & 15; + int rc = right; + int lc = left; + if ((cga->cgamode & 4) != 0) { + rc = (right & 8) | ((right & 7) != 0 ? 7 : 0); + lc = (left & 8) | ((left & 7) != 0 ? 7 : 0); + } + double c = + chroma_multiplexer[((lc & 7) << 5) | ((rc & 7) << 2) | phase]; + double i = intensity[(left >> 3) | ((right >> 2) & 2)]; + double v; + if (!new_cga) + v = c + i; + else { + double r = intensity[((left >> 2) & 1) | ((right >> 1) & 2)]; + double g = intensity[((left >> 1) & 1) | (right & 2)]; + double b = intensity[(left & 1) | ((right << 1) & 2)]; + v = NEW_CGA(c, i, r, g, b); + } + CGA_Composite_Table[x] = (int) (v*mode_contrast + mode_brightness); + } + + double i = CGA_Composite_Table[6*68] - CGA_Composite_Table[6*68 + 2]; + double q = CGA_Composite_Table[6*68 + 1] - CGA_Composite_Table[6*68 + 3]; + + double a = tau*(33 + 90 + hue_offset + mode_hue)/360.0; + double c = cos(a); + double s = sin(a); + double r = 256*mode_saturation/sqrt(i*i+q*q); + + double iq_adjust_i = -(i*c + q*s)*r; + double iq_adjust_q = (q*c - i*s)*r; + + static const double ri = 0.9563; + static const double rq = 0.6210; + static const double gi = -0.2721; + static const double gq = -0.6474; + static const double bi = -1.1069; + static const double bq = 1.7046; + + video_ri = (int) (ri*iq_adjust_i + rq*iq_adjust_q); + video_rq = (int) (-ri*iq_adjust_q + rq*iq_adjust_i); + video_gi = (int) (gi*iq_adjust_i + gq*iq_adjust_q); + video_gq = (int) (-gi*iq_adjust_q + gq*iq_adjust_i); + video_bi = (int) (bi*iq_adjust_i + bq*iq_adjust_q); + video_bq = (int) (-bi*iq_adjust_q + bq*iq_adjust_i); + video_sharpness = (int) (sharpness*256/100); + +#if 0 + df = fopen("CGA_Composite_Table.dmp", "wb"); + fwrite(CGA_Composite_Table, 1024, sizeof(int), df); + fclose(df); +#endif +} + +#if 0 +void configure_comp(double h, uint8_t n, uint8_t bw, uint8_t b1) +{ + hue_offset = h; + new_cga = n; + is_bw = bw; + is_bpp1 = b1; +} +#endif + +static Bit8u byte_clamp(int v) { + v >>= 13; + return v < 0 ? 0 : (v > 255 ? 255 : v); +} + +/* 2048x1536 is the maximum we can possibly support. */ +#define SCALER_MAXWIDTH 2048 + +static int temp[SCALER_MAXWIDTH + 10]={0}; +static int atemp[SCALER_MAXWIDTH + 2]={0}; +static int btemp[SCALER_MAXWIDTH + 2]={0}; + +Bit8u * Composite_Process(cga_t *cga, Bit8u border, Bit32u blocks/*, bool doublewidth*/, Bit8u *TempLine) +{ + int x; + Bit32u x2; + + int w = blocks*4; + +#define COMPOSITE_CONVERT(I, Q) do { \ + i[1] = (i[1]<<3) - ap[1]; \ + a = ap[0]; \ + b = bp[0]; \ + c = i[0]+i[0]; \ + d = i[-1]+i[1]; \ + y = ((c+d)<<8) + video_sharpness*(c-d); \ + rr = y + video_ri*(I) + video_rq*(Q); \ + gg = y + video_gi*(I) + video_gq*(Q); \ + bb = y + video_bi*(I) + video_bq*(Q); \ + ++i; \ + ++ap; \ + ++bp; \ + *srgb = (byte_clamp(rr)<<16) | (byte_clamp(gg)<<8) | byte_clamp(bb); \ + ++srgb; \ +} while (0) + +#define OUT(v) do { *o = (v); ++o; } while (0) + + // Simulate CGA composite output + int* o = temp; + Bit8u* rgbi = TempLine; + int* b = &CGA_Composite_Table[border*68]; + for (x = 0; x < 4; ++x) + OUT(b[(x+3)&3]); + OUT(CGA_Composite_Table[(border<<6) | ((*rgbi)<<2) | 3]); + for (x = 0; x < w-1; ++x) { + OUT(CGA_Composite_Table[(rgbi[0]<<6) | (rgbi[1]<<2) | (x&3)]); + ++rgbi; + } + OUT(CGA_Composite_Table[((*rgbi)<<6) | (border<<2) | 3]); + for (x = 0; x < 5; ++x) + OUT(b[x&3]); + + if ((cga->cgamode & 4) != 0 || !cga_color_burst) { + // Decode + int* i = temp + 5; + Bit32u* srgb = (Bit32u *)TempLine; + for (x2 = 0; x2 < blocks*4; ++x2) { + int c = (i[0]+i[0])<<3; + int d = (i[-1]+i[1])<<3; + int y = ((c+d)<<8) + video_sharpness*(c-d); + ++i; + *srgb = byte_clamp(y)*0x10101; + ++srgb; + } + } + else { + // Store chroma + int* i = temp + 4; + int* ap = atemp + 1; + int* bp = btemp + 1; + for (x = -1; x < w + 1; ++x) { + ap[x] = i[-4]-((i[-2]-i[0]+i[2])<<1)+i[4]; + bp[x] = (i[-3]-i[-1]+i[1]-i[3])<<1; + ++i; + } + + // Decode + i = temp + 5; + i[-1] = (i[-1]<<3) - ap[-1]; + i[0] = (i[0]<<3) - ap[0]; + Bit32u* srgb = (Bit32u *)TempLine; + for (x2 = 0; x2 < blocks; ++x2) { + int y,a,b,c,d,rr,gg,bb; + COMPOSITE_CONVERT(a, b); + COMPOSITE_CONVERT(-b, a); + COMPOSITE_CONVERT(-a, -b); + COMPOSITE_CONVERT(b, -a); + } + } +#undef COMPOSITE_CONVERT +#undef OUT + +#if 0 + df = fopen("temp.dmp", "ab"); + fwrite(temp, SCALER_MAXWIDTH + 10, sizeof(int), df); + fclose(df); + df = fopen("atemp.dmp", "ab"); + fwrite(atemp, SCALER_MAXWIDTH + 2, sizeof(int), df); + fclose(df); + df = fopen("btemp.dmp", "ab"); + fwrite(btemp, SCALER_MAXWIDTH + 2, sizeof(int), df); + fclose(df); +#endif + + return TempLine; +} + +void IncreaseHue(cga_t *cga) +{ + hue_offset += 5.0; + + update_cga16_color(cga); +} + +void DecreaseHue(cga_t *cga) +{ + hue_offset -= 5.0; + + update_cga16_color(cga); +} + +void IncreaseSaturation(cga_t *cga) +{ + saturation += 5; + + update_cga16_color(cga); +} + +void DecreaseSaturation(cga_t *cga) +{ + saturation -= 5; + + update_cga16_color(cga); +} + +void IncreaseContrast(cga_t *cga) +{ + contrast += 5; + + update_cga16_color(cga); +} + +void DecreaseContrast(cga_t *cga) +{ + contrast -= 5; + + update_cga16_color(cga); +} + +void IncreaseBrightness(cga_t *cga) +{ + brightness += 5; + + update_cga16_color(cga); +} + +void DecreaseBrightness(cga_t *cga) +{ + brightness -= 5; + + update_cga16_color(cga); +} + +void IncreaseSharpness(cga_t *cga) +{ + sharpness += 10; + + update_cga16_color(cga); +} + +void DecreaseSharpness(cga_t *cga) +{ + sharpness -= 10; + + update_cga16_color(cga); +} + +void cga_comp_init(cga_t *cga) +{ + new_cga = (gfxcard == GFX_NEW_CGA); + + /* Making sure this gets reset after reset. */ + brightness = 0; + contrast = 100; + saturation = 100; + sharpness = 0; + hue_offset = 0; + + update_cga16_color(cga); +} \ No newline at end of file diff --git a/src/vid_cga_comp.h b/src/vid_cga_comp.h new file mode 100644 index 000000000..809257bf2 --- /dev/null +++ b/src/vid_cga_comp.h @@ -0,0 +1,8 @@ +#define Bit8u uint8_t +#define Bit32u uint32_t +#define Bitu unsigned int +#define bool uint8_t + +void update_cga16_color(cga_t *cga); +void cga_comp_init(cga_t *cga); +Bit8u * Composite_Process(cga_t *cga, Bit8u border, Bit32u blocks/*, bool doublewidth*/, Bit8u *TempLine); diff --git a/src/vid_cl5429.c b/src/vid_cl5429.c new file mode 100644 index 000000000..bca9d3d7b --- /dev/null +++ b/src/vid_cl5429.c @@ -0,0 +1,915 @@ +/*Cirrus Logic CL-GD5429 emulation*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "video.h" +#include "vid_cl5429.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "vid_unk_ramdac.h" + +typedef struct gd5429_t +{ + mem_mapping_t mmio_mapping; + + svga_t svga; + + rom_t bios_rom; + + uint32_t bank[2]; + uint32_t mask; + + struct + { + uint16_t bg_col, fg_col; + uint16_t width, height; + uint16_t dst_pitch, src_pitch; + uint32_t dst_addr, src_addr; + uint8_t mask, mode, rop; + + uint32_t dst_addr_backup, src_addr_backup; + uint16_t width_backup, height_internal; + int x_count; + } blt; + +} gd5429_t; + +void gd5429_write(uint32_t addr, uint8_t val, void *p); +uint8_t gd5429_read(uint32_t addr, void *p); + +void gd5429_mmio_write(uint32_t addr, uint8_t val, void *p); +uint8_t gd5429_mmio_read(uint32_t addr, void *p); + +void gd5429_blt_write_w(uint32_t addr, uint16_t val, void *p); +void gd5429_blt_write_l(uint32_t addr, uint32_t val, void *p); + +void gd5429_recalc_banking(gd5429_t *gd5429); +void gd5429_recalc_mapping(gd5429_t *gd5429); + +void gd5429_out(uint16_t addr, uint8_t val, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + svga_t *svga = &gd5429->svga; + uint8_t old; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + +// pclog("gd5429 out %04X %02X\n", addr, val); + + switch (addr) + { + case 0x3c4: + svga->seqaddr = val; + break; + case 0x3c5: + if (svga->seqaddr > 5) + { + svga->seqregs[svga->seqaddr & 0x1f] = val; + switch (svga->seqaddr & 0x1f) + { + case 0x10: case 0x30: case 0x50: case 0x70: + case 0x90: case 0xb0: case 0xd0: case 0xf0: + svga->hwcursor.x = (val << 3) | ((svga->seqaddr >> 5) & 7); + pclog("svga->hwcursor.x = %i\n", svga->hwcursor.x); + break; + case 0x11: case 0x31: case 0x51: case 0x71: + case 0x91: case 0xb1: case 0xd1: case 0xf1: + svga->hwcursor.y = (val << 3) | ((svga->seqaddr >> 5) & 7); + pclog("svga->hwcursor.y = %i\n", svga->hwcursor.y); + break; + case 0x12: + svga->hwcursor.ena = val & 1; + pclog("svga->hwcursor.ena = %i\n", svga->hwcursor.ena); + break; + case 0x13: + svga->hwcursor.addr = 0x1fc000 + ((val & 0x3f) * 256); + pclog("svga->hwcursor.addr = %x\n", svga->hwcursor.addr); + break; + + case 0x17: + gd5429_recalc_mapping(gd5429); + break; + } + return; + } + break; + + case 0x3cf: + if (svga->gdcaddr == 5) + { + svga->gdcreg[5] = val; + if (svga->gdcreg[0xb] & 0x04) + svga->writemode = svga->gdcreg[5] & 7; + else + svga->writemode = svga->gdcreg[5] & 3; + svga->readmode = val & 8; +// pclog("writemode = %i\n", svga->writemode); + return; + } + if (svga->gdcaddr == 6) + { + if ((svga->gdcreg[6] & 0xc) != (val & 0xc)) + { + svga->gdcreg[6] = val; + gd5429_recalc_mapping(gd5429); + } + svga->gdcreg[6] = val; + return; + } + if (svga->gdcaddr > 8) + { + svga->gdcreg[svga->gdcaddr & 0x3f] = val; + switch (svga->gdcaddr) + { + case 0x09: case 0x0a: case 0x0b: + gd5429_recalc_banking(gd5429); + if (svga->gdcreg[0xb] & 0x04) + svga->writemode = svga->gdcreg[5] & 7; + else + svga->writemode = svga->gdcreg[5] & 3; + break; + } + return; + } + break; + + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if (svga->crtcreg <= 0x18) + val &= mask_crtc[svga->crtcreg]; + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t gd5429_in(uint16_t addr, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + svga_t *svga = &gd5429->svga; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + +// if (addr != 0x3da) pclog("IN gd5429 %04X\n", addr); + + switch (addr) + { + case 0x3c5: + if (svga->seqaddr > 5) + { + switch (svga->seqaddr) + { + case 6: + return ((svga->seqregs[6] & 0x17) == 0x12) ? 0x12 : 0x0f; + } + return svga->seqregs[svga->seqaddr & 0x3f]; + } + break; + + case 0x3cf: + if (svga->gdcaddr > 8) + { + return svga->gdcreg[svga->gdcaddr & 0x3f]; + } + break; + + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + switch (svga->crtcreg) + { + case 0x27: /*ID*/ + return 0x9c; /*GD5429*/ + } + return svga->crtc[svga->crtcreg]; + } + return svga_in(addr, svga); +} + +void gd5429_recalc_banking(gd5429_t *gd5429) +{ + svga_t *svga = &gd5429->svga; + + if (svga->gdcreg[0xb] & 0x20) + gd5429->bank[0] = (svga->gdcreg[0x09] & 0x7f) << 14; + else + gd5429->bank[0] = svga->gdcreg[0x09] << 12; + + if (svga->gdcreg[0xb] & 0x01) + { + if (svga->gdcreg[0xb] & 0x20) + gd5429->bank[1] = (svga->gdcreg[0x0a] & 0x7f) << 14; + else + gd5429->bank[1] = svga->gdcreg[0x0a] << 12; + } + else + gd5429->bank[1] = gd5429->bank[0] + 0x8000; +} + +void gd5429_recalc_mapping(gd5429_t *gd5429) +{ + svga_t *svga = &gd5429->svga; + + pclog("Write mapping %02X %i\n", svga->gdcreg[6], svga->seqregs[0x17] & 0x04); + switch (svga->gdcreg[6] & 0x0C) + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + mem_mapping_disable(&gd5429->mmio_mapping); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + if (svga->seqregs[0x17] & 0x04) + mem_mapping_set_addr(&gd5429->mmio_mapping, 0xb8000, 0x00100); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + mem_mapping_disable(&gd5429->mmio_mapping); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + mem_mapping_disable(&gd5429->mmio_mapping); + svga->banked_mask = 0x7fff; + break; + } +} + +void gd5429_recalctimings(svga_t *svga) +{ + gd5429_t *gd5429 = (gd5429_t *)svga->p; + + if (svga->seqregs[7] & 0x01) + { + svga->render = svga_render_8bpp_highres; + } + + svga->ma_latch |= ((svga->crtc[0x1b] & 0x01) << 16) | ((svga->crtc[0x1b] & 0xc) << 15); + pclog("MA now %05X %02X\n", svga->ma_latch, svga->crtc[0x1b]); +} + +void gd5429_hwcursor_draw(svga_t *svga, int displine) +{ + int x; + uint8_t dat[2]; + int xx; + int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; + + pclog("HWcursor %i %i %i %i %x %02X %02X\n", svga->hwcursor_latch.x, svga->hwcursor_latch.y, offset, displine, svga->hwcursor_latch.addr, vram[svga->hwcursor_latch.addr], vram[svga->hwcursor_latch.addr + 0x80]); + for (x = 0; x < 32; x += 8) + { + dat[0] = svga->vram[svga->hwcursor_latch.addr]; + dat[1] = svga->vram[svga->hwcursor_latch.addr + 0x80]; + for (xx = 0; xx < 8; xx++) + { + if (offset >= svga->hwcursor_latch.x) + { + if (dat[1] & 0x80) + ((uint32_t *)buffer32->line[displine])[offset + 32] = 0; + if (dat[0] & 0x80) + ((uint32_t *)buffer32->line[displine])[offset + 32] ^= 0xffffff; + } + + offset++; + dat[0] <<= 1; + dat[1] <<= 1; + } + svga->hwcursor_latch.addr++; + } +} + + +void gd5429_write_linear(uint32_t addr, uint8_t val, void *p); + +void gd5429_write(uint32_t addr, uint8_t val, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + svga_t *svga = &gd5429->svga; +// pclog("gd5429_write : %05X %02X ", addr, val); + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd5429->bank[(addr >> 15) & 1]; +// pclog("%08X\n", addr); + gd5429_write_linear(addr, val, p); +} + +uint8_t gd5429_read(uint32_t addr, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + svga_t *svga = &gd5429->svga; + uint8_t ret; +// pclog("gd5429_read : %05X ", addr); + addr &= svga->banked_mask; + addr = (addr & 0x7fff) + gd5429->bank[(addr >> 15) & 1]; + ret = svga_read_linear(addr, &gd5429->svga); +// pclog("%08X %02X\n", addr, ret); + return ret; +} + +void gd5429_write_linear(uint32_t addr, uint8_t val, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + svga_t *svga = &gd5429->svga; + uint8_t vala, valb, valc, vald, wm = svga->writemask; + int writemask2 = svga->writemask; + uint32_t raddr = addr; + int plane, mask; + + cycles -= video_timing_b; + cycles_lost += video_timing_b; + + egawrites++; + +// if (svga_output) pclog("Write LFB %08X %02X ", addr, val); + if (!(svga->gdcreg[6] & 1)) + svga->fullchange = 2; + if ((svga->chain4 || svga->fb_only) && (svga->writemode < 4)) + { + writemask2 = 1 << (addr & 3); + addr &= ~3; + } + else if (svga->chain2_write) + { + /* Redone because the original code caused problems when using Windows 3.1 EGA driver on (S)VGA card. */ + plane = (svga->readplane & 2) | (addr & 1); + mask = (1 << plane); + if (svga->seqregs[2] & mask) + { + addr = ((addr & ~1) << 2) | plane | (svga->oddeven_page ? 0x10000 : 0); + addr &= 0x7fffff; + if ((!svga->extvram) && (addr >= 0x10000)) return; + if (addr >= svga->vram_limit) return; + if ((raddr <= 0xA0000) || (raddr >= 0xBFFFF)) return; + svga->vram[addr] = val; + + svga->changedvram[addr >> 12] = changeframecount; + } + return; + } + else + { + addr <<= 2; + } + addr &= 0x7fffff; + if (addr >= svga->vram_limit) + return; +// if (svga_output) pclog("%08X\n", addr); + svga->changedvram[addr >> 12] = changeframecount; + + switch (svga->writemode) + { + case 4: + pclog("Writemode 4 : %X ", addr); + addr <<= 1; + svga->changedvram[addr >> 12] = changeframecount; + pclog("%X %X\n", addr, val); + if (val & 0x80) + svga->vram[addr + 0] = svga->gdcreg[1]; + if (val & 0x40) + svga->vram[addr + 1] = svga->gdcreg[1]; + if (val & 0x20) + svga->vram[addr + 2] = svga->gdcreg[1]; + if (val & 0x10) + svga->vram[addr + 3] = svga->gdcreg[1]; + if (val & 0x08) + svga->vram[addr + 4] = svga->gdcreg[1]; + if (val & 0x04) + svga->vram[addr + 5] = svga->gdcreg[1]; + if (val & 0x02) + svga->vram[addr + 6] = svga->gdcreg[1]; + if (val & 0x01) + svga->vram[addr + 7] = svga->gdcreg[1]; + break; + + case 5: + pclog("Writemode 5 : %X ", addr); + addr <<= 1; + svga->changedvram[addr >> 12] = changeframecount; + pclog("%X %X\n", addr, val); + svga->vram[addr + 0] = (val & 0x80) ? svga->gdcreg[1] : svga->gdcreg[0]; + svga->vram[addr + 1] = (val & 0x40) ? svga->gdcreg[1] : svga->gdcreg[0]; + svga->vram[addr + 2] = (val & 0x20) ? svga->gdcreg[1] : svga->gdcreg[0]; + svga->vram[addr + 3] = (val & 0x10) ? svga->gdcreg[1] : svga->gdcreg[0]; + svga->vram[addr + 4] = (val & 0x08) ? svga->gdcreg[1] : svga->gdcreg[0]; + svga->vram[addr + 5] = (val & 0x04) ? svga->gdcreg[1] : svga->gdcreg[0]; + svga->vram[addr + 6] = (val & 0x02) ? svga->gdcreg[1] : svga->gdcreg[0]; + svga->vram[addr + 7] = (val & 0x01) ? svga->gdcreg[1] : svga->gdcreg[0]; + break; + + case 1: + if (writemask2 & 1) svga->vram[addr] = svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = svga->ld; + break; + case 0: + if (svga->gdcreg[3] & 7) + val = svga_rotate[svga->gdcreg[3] & 7][val]; + if (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) + { + if (writemask2 & 1) svga->vram[addr] = val; + if (writemask2 & 2) svga->vram[addr | 0x1] = val; + if (writemask2 & 4) svga->vram[addr | 0x2] = val; + if (writemask2 & 8) svga->vram[addr | 0x3] = val; + } + else + { + if (svga->gdcreg[1] & 1) vala = (svga->gdcreg[0] & 1) ? 0xff : 0; + else vala = val; + if (svga->gdcreg[1] & 2) valb = (svga->gdcreg[0] & 2) ? 0xff : 0; + else valb = val; + if (svga->gdcreg[1] & 4) valc = (svga->gdcreg[0] & 4) ? 0xff : 0; + else valc = val; + if (svga->gdcreg[1] & 8) vald = (svga->gdcreg[0] & 8) ? 0xff : 0; + else vald = val; + + switch (svga->gdcreg[3] & 0x18) + { + case 0: /*Set*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; + break; + } +// pclog("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); + } + break; + case 2: + if (!(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) + { + if (writemask2 & 1) svga->vram[addr] = (((val & 1) ? 0xff : 0) & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (((val & 2) ? 0xff : 0) & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (((val & 4) ? 0xff : 0) & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (((val & 8) ? 0xff : 0) & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); + } + else + { + vala = ((val & 1) ? 0xff : 0); + valb = ((val & 2) ? 0xff : 0); + valc = ((val & 4) ? 0xff : 0); + vald = ((val & 8) ? 0xff : 0); + switch (svga->gdcreg[3] & 0x18) + { + case 0: /*Set*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; + break; + } + } + break; + case 3: + if (svga->gdcreg[3] & 7) + val = svga_rotate[svga->gdcreg[3] & 7][val]; + wm = svga->gdcreg[8]; + svga->gdcreg[8] &= val; + + vala = (svga->gdcreg[0] & 1) ? 0xff : 0; + valb = (svga->gdcreg[0] & 2) ? 0xff : 0; + valc = (svga->gdcreg[0] & 4) ? 0xff : 0; + vald = (svga->gdcreg[0] & 8) ? 0xff : 0; + switch (svga->gdcreg[3] & 0x18) + { + case 0: /*Set*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; + break; + } + svga->gdcreg[8] = wm; + break; + } +} + +void gd5429_start_blit(uint32_t cpu_dat, int count, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + svga_t *svga = &gd5429->svga; + + pclog("gd5429_start_blit %i\n", count); + if (count == -1) + { + gd5429->blt.dst_addr_backup = gd5429->blt.dst_addr; + gd5429->blt.src_addr_backup = gd5429->blt.src_addr; + gd5429->blt.width_backup = gd5429->blt.width; + gd5429->blt.height_internal = gd5429->blt.height; + gd5429->blt.x_count = gd5429->blt.mask & 7; + pclog("gd5429_start_blit : size %i, %i\n", gd5429->blt.width, gd5429->blt.height); + + if (gd5429->blt.mode & 0x04) + { +// pclog("blt.mode & 0x04\n"); + mem_mapping_set_handler(&svga->mapping, NULL, NULL, NULL, NULL, gd5429_blt_write_w, gd5429_blt_write_l); + mem_mapping_set_p(&svga->mapping, gd5429); + return; + } + else + { + mem_mapping_set_handler(&gd5429->svga.mapping, gd5429_read, NULL, NULL, gd5429_write, NULL, NULL); + mem_mapping_set_p(&gd5429->svga.mapping, gd5429); + gd5429_recalc_mapping(gd5429); + } + } + + while (count) + { + uint8_t src, dst; + int mask; + + if (gd5429->blt.mode & 0x04) + { + if (gd5429->blt.mode & 0x80) + { + src = (cpu_dat & 0x80) ? gd5429->blt.fg_col : gd5429->blt.bg_col; + mask = cpu_dat & 0x80; + cpu_dat <<= 1; + count--; + } + else + { + src = cpu_dat & 0xff; + cpu_dat >>= 8; + count -= 8; + mask = 1; + } + } + else + { + switch (gd5429->blt.mode & 0xc0) + { + case 0x00: + src = svga->vram[gd5429->blt.src_addr & svga->vrammask]; + gd5429->blt.src_addr += ((gd5429->blt.mode & 0x01) ? -1 : 1); + mask = 1; + break; + case 0x40: + src = svga->vram[(gd5429->blt.src_addr & (svga->vrammask & ~7)) | (gd5429->blt.dst_addr & 7)]; + mask = 1; + break; + case 0x80: + mask = svga->vram[gd5429->blt.src_addr & svga->vrammask] & (0x80 >> gd5429->blt.x_count); + src = mask ? gd5429->blt.fg_col : gd5429->blt.bg_col; + gd5429->blt.x_count++; + if (gd5429->blt.x_count == 8) + { + gd5429->blt.x_count = 0; + gd5429->blt.src_addr++; + } + break; + case 0xc0: + mask = svga->vram[gd5429->blt.src_addr & svga->vrammask] & (0x80 >> (gd5429->blt.dst_addr & 7)); + src = mask ? gd5429->blt.fg_col : gd5429->blt.bg_col; + break; + } + count--; + } + dst = svga->vram[gd5429->blt.dst_addr & svga->vrammask]; + svga->changedvram[(gd5429->blt.dst_addr & svga->vrammask) >> 12] = changeframecount; + + pclog("Blit %i,%i %06X %06X %06X %02X %02X %02X %02X ", gd5429->blt.width, gd5429->blt.height_internal, gd5429->blt.src_addr, gd5429->blt.dst_addr, gd5429->blt.src_addr & svga->vrammask, svga->vram[gd5429->blt.src_addr & svga->vrammask], 0x80 >> (gd5429->blt.dst_addr & 7), src, dst); + switch (gd5429->blt.rop) + { + case 0x00: dst = 0; break; + case 0x05: dst = src & dst; break; + case 0x06: dst = dst; break; + case 0x09: dst = src & ~dst; break; + case 0x0b: dst = ~ dst; break; + case 0x0d: dst = src; break; + case 0x0e: dst = 0xff; break; + case 0x50: dst = ~ src & dst; break; + case 0x59: dst = src ^ dst; break; + case 0x6d: dst = src | dst; break; + case 0x90: dst = ~(src | dst); break; + case 0x95: dst = ~(src ^ dst); break; + case 0xad: dst = src | ~dst; break; + case 0xd0: dst = ~src; break; + case 0xd6: dst = ~src | dst; break; + case 0xda: dst = ~(src & dst); break; + } + pclog("%02X %02X\n", dst, mask); + + if ((gd5429->blt.width_backup - gd5429->blt.width) >= (gd5429->blt.mask & 7) && + !((gd5429->blt.mode & 0x08) && !mask)) + svga->vram[gd5429->blt.dst_addr & svga->vrammask] = dst; + + gd5429->blt.dst_addr += ((gd5429->blt.mode & 0x01) ? -1 : 1); + + gd5429->blt.width--; + + if (gd5429->blt.width == 0xffff) + { + gd5429->blt.width = gd5429->blt.width_backup; + + gd5429->blt.dst_addr = gd5429->blt.dst_addr_backup = gd5429->blt.dst_addr_backup + ((gd5429->blt.mode & 0x01) ? -gd5429->blt.dst_pitch : gd5429->blt.dst_pitch); + + switch (gd5429->blt.mode & 0xc0) + { + case 0x00: + gd5429->blt.src_addr = gd5429->blt.src_addr_backup = gd5429->blt.src_addr_backup + ((gd5429->blt.mode & 0x01) ? -gd5429->blt.src_pitch : gd5429->blt.src_pitch); + break; + case 0x40: + gd5429->blt.src_addr = ((gd5429->blt.src_addr + ((gd5429->blt.mode & 0x01) ? -8 : 8)) & 0x38) | (gd5429->blt.src_addr & ~0x38); + break; + case 0x80: + if (gd5429->blt.x_count != 0) + { + gd5429->blt.x_count = 0; + gd5429->blt.src_addr++; + } + break; + case 0xc0: + gd5429->blt.src_addr = ((gd5429->blt.src_addr + ((gd5429->blt.mode & 0x01) ? -1 : 1)) & 7) | (gd5429->blt.src_addr & ~7); + break; + } + + gd5429->blt.height_internal--; + if (gd5429->blt.height_internal == 0xffff) + { + if (gd5429->blt.mode & 0x04) + { + mem_mapping_set_handler(&gd5429->svga.mapping, gd5429_read, NULL, NULL, gd5429_write, NULL, NULL); + mem_mapping_set_p(&gd5429->svga.mapping, gd5429); + gd5429_recalc_mapping(gd5429); + } + return; + } + + if (gd5429->blt.mode & 0x04) + return; + } + } +} + +void gd5429_mmio_write(uint32_t addr, uint8_t val, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + + pclog("MMIO write %08X %02X\n", addr, val); + switch (addr & 0xff) + { + case 0x00: + gd5429->blt.bg_col = (gd5429->blt.bg_col & 0xff00) | val; + break; + case 0x01: + gd5429->blt.bg_col = (gd5429->blt.bg_col & 0x00ff) | (val << 8); + break; + + case 0x04: + gd5429->blt.fg_col = (gd5429->blt.fg_col & 0xff00) | val; + break; + case 0x05: + gd5429->blt.fg_col = (gd5429->blt.fg_col & 0x00ff) | (val << 8); + break; + + case 0x08: + gd5429->blt.width = (gd5429->blt.width & 0xff00) | val; + break; + case 0x09: + gd5429->blt.width = (gd5429->blt.width & 0x00ff) | (val << 8); + break; + case 0x0a: + gd5429->blt.height = (gd5429->blt.height & 0xff00) | val; + break; + case 0x0b: + gd5429->blt.height = (gd5429->blt.height & 0x00ff) | (val << 8); + break; + case 0x0c: + gd5429->blt.dst_pitch = (gd5429->blt.dst_pitch & 0xff00) | val; + break; + case 0x0d: + gd5429->blt.dst_pitch = (gd5429->blt.dst_pitch & 0x00ff) | (val << 8); + break; + case 0x0e: + gd5429->blt.src_pitch = (gd5429->blt.src_pitch & 0xff00) | val; + break; + case 0x0f: + gd5429->blt.src_pitch = (gd5429->blt.src_pitch & 0x00ff) | (val << 8); + break; + + case 0x10: + gd5429->blt.dst_addr = (gd5429->blt.dst_addr & 0xffff00) | val; + break; + case 0x11: + gd5429->blt.dst_addr = (gd5429->blt.dst_addr & 0xff00ff) | (val << 8); + break; + case 0x12: + gd5429->blt.dst_addr = (gd5429->blt.dst_addr & 0x00ffff) | (val << 16); + break; + + case 0x14: + gd5429->blt.src_addr = (gd5429->blt.src_addr & 0xffff00) | val; + break; + case 0x15: + gd5429->blt.src_addr = (gd5429->blt.src_addr & 0xff00ff) | (val << 8); + break; + case 0x16: + gd5429->blt.src_addr = (gd5429->blt.src_addr & 0x00ffff) | (val << 16); + break; + + case 0x17: + gd5429->blt.mask = val; + break; + case 0x18: + gd5429->blt.mode = val; + break; + + case 0x1a: + gd5429->blt.rop = val; + break; + + case 0x40: + if (val & 0x02) + gd5429_start_blit(0, -1, gd5429); + break; + } +} + +uint8_t gd5429_mmio_read(uint32_t addr, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + + pclog("MMIO read %08X\n", addr); + switch (addr & 0xff) + { + case 0x40: /*BLT status*/ + return 0; + } + return 0xff; /*All other registers read-only*/ +} + +void gd5429_blt_write_w(uint32_t addr, uint16_t val, void *p) +{ + pclog("gd5429_blt_write_w %08X %08X\n", addr, val); + gd5429_start_blit(val, 16, p); +} + +void gd5429_blt_write_l(uint32_t addr, uint32_t val, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + + pclog("gd5429_blt_write_l %08X %08X %04X %04X\n", addr, val, ((val >> 8) & 0x00ff) | ((val << 8) & 0xff00), ((val >> 24) & 0x00ff) | ((val >> 8) & 0xff00)); + if ((gd5429->blt.mode & 0x84) == 0x84) + { + gd5429_start_blit( val & 0xff, 8, p); + gd5429_start_blit((val >> 8) & 0xff, 8, p); + gd5429_start_blit((val >> 16) & 0xff, 8, p); + gd5429_start_blit((val >> 24) & 0xff, 8, p); + } + else + gd5429_start_blit(val, 32, p); +} + +void *gd5429_init() +{ + gd5429_t *gd5429 = malloc(sizeof(gd5429_t)); + svga_t *svga = &gd5429->svga; + memset(gd5429, 0, sizeof(gd5429_t)); + + rom_init(&gd5429->bios_rom, "roms/5429.vbi", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + svga_init(&gd5429->svga, gd5429, 1 << 21, /*2mb*/ + gd5429_recalctimings, + gd5429_in, gd5429_out, + gd5429_hwcursor_draw, + NULL); + + mem_mapping_set_handler(&gd5429->svga.mapping, gd5429_read, NULL, NULL, gd5429_write, NULL, NULL); + mem_mapping_set_p(&gd5429->svga.mapping, gd5429); + + mem_mapping_add(&gd5429->mmio_mapping, 0, 0, gd5429_mmio_read, NULL, NULL, gd5429_mmio_write, NULL, NULL, NULL, 0, gd5429); + + io_sethandler(0x03c0, 0x0020, gd5429_in, NULL, NULL, gd5429_out, NULL, NULL, gd5429); + + svga->hwcursor.yoff = 32; + svga->hwcursor.xoff = 0; + + gd5429->bank[1] = 0x8000; + + return gd5429; +} + +static int gd5429_available() +{ + return rom_present("roms/5429.vbi"); +} + +void gd5429_close(void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + + svga_close(&gd5429->svga); + + free(gd5429); +} + +void gd5429_speed_changed(void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + + svga_recalctimings(&gd5429->svga); +} + +void gd5429_force_redraw(void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + + gd5429->svga.fullchange = changeframecount; +} + +void gd5429_add_status_info(char *s, int max_len, void *p) +{ + gd5429_t *gd5429 = (gd5429_t *)p; + + svga_add_status_info(s, max_len, &gd5429->svga); +} + +device_t gd5429_device = +{ + "Cirrus Logic GD5429", + DEVICE_NOT_WORKING, + gd5429_init, + gd5429_close, + gd5429_available, + gd5429_speed_changed, + gd5429_force_redraw, + gd5429_add_status_info +}; diff --git a/src/vid_cl5429.h b/src/vid_cl5429.h new file mode 100644 index 000000000..588590c1b --- /dev/null +++ b/src/vid_cl5429.h @@ -0,0 +1 @@ +extern device_t gd5429_device; diff --git a/src/vid_ega.c b/src/vid_ega.c new file mode 100644 index 000000000..397b56b7e --- /dev/null +++ b/src/vid_ega.c @@ -0,0 +1,1141 @@ +/*EGA emulation*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "timer.h" +#include "video.h" +#include "vid_ega.h" + +extern uint8_t edatlookup[4][4]; + +static uint8_t ega_rotate[8][256]; + +static uint32_t pallook16[256], pallook64[256]; + +/*3C2 controls default mode on EGA. On VGA, it determines monitor type (mono or colour)*/ +int egaswitchread,egaswitches=9; /*7=CGA mode (200 lines), 9=EGA mode (350 lines), 8=EGA mode (200 lines)*/ + +static uint8_t mask_gdc[9] = {0x0F, 0x0F, 0x0F, 0x1F, 0x03, 0x3B, 0x0F, 0x0F, 0xFF}; +static uint8_t ega_mask_crtc[0x19] = {0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0x1F, 0x1F, 0x1F, 0x1F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0x1F, 0xFF, 0x1F, 0x7F, 0xFF}; +static uint8_t mask_seq[5] = {0x03, 0x1F, 0x0F, 0x0F, 0x06}; + +static int old_overscan_color = 0; + +void ega_out(uint16_t addr, uint8_t val, void *p) +{ + ega_t *ega = (ega_t *)p; + int c; + uint8_t o, old; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c0: + if (!ega->attrff) + { + ega->attraddr = val & 31; + if ((val & 0x20) != ega->attr_palette_enable) + { + fullchange = 3; + ega->attr_palette_enable = val & 0x20; + ega_recalctimings(ega); + } + } + else + { + o = ega->attrregs[ega->attraddr & 31]; + ega->attrregs[ega->attraddr & 31] = val; + ega->attrregs[0x11] &= 0x3F; + if (ega->attraddr < 16) + fullchange = changeframecount; + if (ega->attraddr == 0x10 || ega->attraddr == 0x14 || ega->attraddr < 0x10) + { + for (c = 0; c < 16; c++) + { + /* if (ega->attrregs[0x10] & 0x80) ega->egapal[c] = (ega->attrregs[c] & 0xf) | ((ega->attrregs[0x14] & 0xf) << 4); + else ega->egapal[c] = (ega->attrregs[c] & 0x3f) | ((ega->attrregs[0x14] & 0xc) << 4); */ + + if (ega->attrregs[0x10] & 0x80) ega->egapal[c] = (ega->attrregs[c] & 0xf) | ((ega->attrregs[0x14] & 0x3) << 4); + else ega->egapal[c] = (ega->attrregs[c] & 0x3f); + + // if ((ega->attrregs[0x10] & 0x40) && gfxcard != GFX_EGA) ega->egapal[c] |= ((ega->attrregs[0x14] & 0xc) << 4); + if (gfxcard != GFX_EGA) ega->egapal[c] |= ((ega->attrregs[0x14] & 0xc) << 4); + } + } + if ((ega->attraddr == 0x10) || (ega->attraddr == 0x11)) + { + if (o != val) ega_recalctimings(ega); + } + } + ega->attrff ^= 1; + break; + case 0x3c2: + egaswitchread = val & 0xc; + ega->vres = !(val & 0x80); + if (gfxcard == GFX_EGA) + ega->pallook = ega->vres ? pallook16 : pallook64; + else + ega->pallook = pallook64; + ega->vidclock = val & 4; /*printf("3C2 write %02X\n",val);*/ + ega->enablevram = (val & 2) ? 1 : 0; + ega->oddeven_page = (val & 0x20) ? 0 : 1; + ega->miscout=val; + if (val & 1) + { +// pclog("Remove mono handler\n"); + io_removehandler(0x03a0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); + } + else + { +// pclog("Set mono handler\n"); + io_sethandler(0x03a0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); + } + ega_recalctimings(ega); + break; + case 0x3c4: + ega->seqaddr = val; + break; + case 0x3c5: + if (ega->seqaddr <= 4) val &= mask_seq[ega->seqaddr]; + o = ega->seqregs[ega->seqaddr & 0xf]; + ega->seqregs[ega->seqaddr & 0xf] = val; + if (o != val && (ega->seqaddr & 0xf) == 1) + ega_recalctimings(ega); + switch (ega->seqaddr & 0xf) + { + case 1: + if (ega->scrblank && !(val & 0x20)) + fullchange = 3; + ega->scrblank = (ega->scrblank & ~0x20) | (val & 0x20); + break; + case 2: + ega->writemask = val & 0xf; + break; + case 3: + ega->charsetb = (((val >> 2) & 3) * 0x10000) + 2; + ega->charseta = ((val & 3) * 0x10000) + 2; + break; + case 4: + ega->chain2_write = !(val & 4); + break; + } + break; + case 0x3ce: + ega->gdcaddr = val; + break; + case 0x3cf: + if (ega->seqaddr <= 8) val &= mask_gdc[ega->gdcaddr]; + ega->gdcreg[ega->gdcaddr & 15] = val; + switch (ega->gdcaddr & 15) + { + case 2: + ega->colourcompare = val; + break; + case 4: + ega->readplane = val & 3; + break; + case 5: + ega->writemode = val & 3; + ega->readmode = val & 8; + ega->chain2_read = val & 0x10; + break; + case 6: +// pclog("Write mapping %02X\n", val); + switch (val & 0xc) + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&ega->mapping, 0xa0000, 0x20000); + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&ega->mapping, 0xa0000, 0x10000); + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&ega->mapping, 0xb0000, 0x08000); + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&ega->mapping, 0xb8000, 0x08000); + break; + } + break; + case 7: + ega->colournocare = val; + break; + } + break; + case 0x3d4: + // pclog("Write 3d4 %02X %04X:%04X\n", val, CS, cpu_state.pc); + ega->crtcreg = val & 31; + return; + case 0x3d5: + // pclog("Write 3d5 %02X %02X %02X\n", ega->crtcreg, val, ega->crtc[0x11]); +// if (ega->crtcreg == 1 && val == 0x14) +// fatal("Here\n"); + if (ega->crtcreg <= 0x18) val &= ega_mask_crtc[ega->crtcreg]; + if (ega->crtcreg <= 7 && ega->crtc[0x11] & 0x80) return; + old = ega->crtc[ega->crtcreg]; + ega->crtc[ega->crtcreg] = val; + if (old != val) + { + if (ega->crtcreg < 0xe || ega->crtcreg > 0x10) + { + fullchange = changeframecount; + ega_recalctimings(ega); + } + } + break; + } +} + +uint8_t ega_in(uint16_t addr, void *p) +{ + ega_t *ega = (ega_t *)p; + +/* if (addr != 0x3da && addr != 0x3ba) + pclog("ega_in %04X\n", addr); */ + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(ega->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3c0: + return ega->attraddr; + case 0x3c1: + if (ega->attraddr == 0x10) return ((ega->attrregs[ega->attraddr] & 0x7F) | (ega->attrff << 7)); + return ega->attrregs[ega->attraddr]; + case 0x3c2: +// printf("Read egaswitch %02X %02X %i\n",egaswitchread,egaswitches,VGA); + switch (egaswitchread) + { + case 0xc: return (egaswitches & 1) ? 0x10 : 0; + case 0x8: return (egaswitches & 2) ? 0x10 : 0; + case 0x4: return (egaswitches & 4) ? 0x10 : 0; + case 0x0: return (egaswitches & 8) ? 0x10 : 0; + } + break; + case 0x3c4: + return ega->seqaddr; + case 0x3c5: + return ega->seqregs[ega->seqaddr & 0xf]; + case 0x3ce: + return ega->gdcaddr; + case 0x3cf: + if (ega->gdcaddr == 0xF8) return ega->la; + if (ega->gdcaddr == 0xF9) return ega->lb; + if (ega->gdcaddr == 0xFA) return ega->lc; + if (ega->gdcaddr == 0xFB) return ega->ld; + return ega->gdcreg[ega->gdcaddr & 0xf]; + case 0x3d4: + return ega->crtcreg; + case 0x3d5: + return ega->crtc[ega->crtcreg]; + case 0x3da: + ega->attrff = 0; + // ega->stat ^= 0x30; /*Fools IBM EGA video BIOS self-test*/ + if (ega->stat & 0x01) + ega->stat &= ~0x30; + else + ega->stat ^= 0x30; + return ega->stat; + } +// printf("Bad EGA read %04X %04X:%04X\n",addr,cs>>4,cpu_state.pc); + return 0xff; +} + +void ega_recalctimings(ega_t *ega) +{ + double _dispontime, _dispofftime, disptime; + double crtcconst; + + ega->vtotal = ega->crtc[6]; + ega->dispend = ega->crtc[0x12]; + ega->vsyncstart = ega->crtc[0x10]; + ega->split = ega->crtc[0x18]; + ega->vblankstart = ega->crtc[0x15]; + + if (ega->crtc[7] & 1) ega->vtotal |= 0x100; + ega->vtotal++; + + if (ega->crtc[7] & 2) ega->dispend |= 0x100; + ega->dispend++; + + if (ega->crtc[7] & 4) ega->vsyncstart |= 0x100; + ega->vsyncstart++; + + if (ega->crtc[7] & 0x10) ega->split |= 0x100; + ega->split+=2; + + if (ega->crtc[7] & 0x08) ega->vblankstart |= 0x100; + ega->vblankstart++; + + ega->hdisp = ega->crtc[1]; + ega->hdisp++; + + ega->rowoffset = ega->crtc[0x13]; + + // printf("Recalc! %i %i %i %i %i %02X\n", ega->vtotal, ega->dispend, ega->vsyncstart, ega->split, ega->hdisp, ega->attrregs[0x16]); + + if (ega->vblankstart < ega->dispend) + ega->dispend = ega->vblankstart; + + if (ega->vidclock) crtcconst = (ega->seqregs[1] & 1) ? MDACONST : (MDACONST * (9.0 / 8.0)); + else crtcconst = (ega->seqregs[1] & 1) ? CGACONST : (CGACONST * (9.0 / 8.0)); + + disptime = ega->crtc[0] + 2; + _dispontime = ega->hdisp; + +// printf("Disptime %f dispontime %f hdisp %i\n",disptime,dispontime,crtc[1]*8); + if (ega->seqregs[1] & 8) { disptime *= 2; _dispontime *= 2; } + _dispofftime = disptime - _dispontime; + _dispontime *= crtcconst; + _dispofftime *= crtcconst; + + ega->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + ega->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); + + /* pclog("dispontime %i (%f) dispofftime %i (%f)\n", ega->dispontime, (float)ega->dispontime / (1 << TIMER_SHIFT), + ega->dispofftime, (float)ega->dispofftime / (1 << TIMER_SHIFT)); */ +// printf("EGA horiz total %i display end %i clock rate %i vidclock %i %i\n",crtc[0],crtc[1],egaswitchread,vidclock,((ega3c2>>2)&3) | ((tridentnewctrl2<<2)&4)); +// printf("EGA vert total %i display end %i max row %i vsync %i\n",ega_vtotal,ega_dispend,(crtc[9]&31)+1,ega_vsyncstart); +// printf("total %f on %f cycles off %f cycles frame %f sec %f %02X\n",disptime*crtcconst,dispontime,dispofftime,(dispontime+dispofftime)*ega_vtotal,(dispontime+dispofftime)*ega_vtotal*70,seqregs[1]); +} + +void ega_poll(void *p) +{ + ega_t *ega = (ega_t *)p; + uint8_t chr, dat, attr; + uint32_t charaddr; + int x, xx; + uint32_t fg, bg; + int offset; + uint8_t edat[4]; + int drawcursor = 0; + uint32_t addr_ex = 0; + int y_add = enable_overscan ? 14 : 0; + int x_add = enable_overscan ? 8 : 0; + int y_add_ex = enable_overscan ? 28 : 0; + int x_add_ex = enable_overscan ? 16 : 0; + uint32_t *q, *r, i, j; + + if (!ega->linepos) + { + ega->vidtime += ega->dispofftime; + + ega->stat |= 1; + ega->linepos = 1; + + if (ega->dispon) + { + if (ega->firstline == 2000) + ega->firstline = ega->displine; + + if (ega->scrblank) + { + for (x = 0; x < ega->hdisp; x++) + { + switch (ega->seqregs[1] & 9) + { + case 0: + for (xx = 0; xx < 9; xx++) ((uint32_t *)buffer32->line[ega->displine + y_add])[(x * 9) + xx + 32 + x_add] = 0; + break; + case 1: + for (xx = 0; xx < 8; xx++) ((uint32_t *)buffer32->line[ega->displine + y_add])[(x * 8) + xx + 32 + x_add] = 0; + break; + case 8: + for (xx = 0; xx < 18; xx++) ((uint32_t *)buffer32->line[ega->displine + y_add])[(x * 18) + xx + 32 + x_add] = 0; + break; + case 9: + for (xx = 0; xx < 16; xx++) ((uint32_t *)buffer32->line[ega->displine + y_add])[(x * 16) + xx + 32 + x_add] = 0; + break; + } + } + } + else if (!ega->scrblank && ega->attr_palette_enable) + { + if (!(ega->gdcreg[6] & 1)) + { + if (fullchange) + { + for (x = 0; x < ega->hdisp; x++) + { + drawcursor = ((ega->ma == ega->ca) && ega->con && ega->cursoron); + addr_ex = (ega->oddeven_page ? 0x10000 : 0); + chr = ega->vram[(ega->ma << 1) | addr_ex]; + attr = ega->vram[((ega->ma << 1) + 1) | addr_ex]; + + if (attr & 8) charaddr = ega->charsetb + (chr * 128); + else charaddr = ega->charseta + (chr * 128); + + if (drawcursor) + { + bg = ega->pallook[ega->egapal[attr & 15]]; + fg = ega->pallook[ega->egapal[attr >> 4]]; + } + else + { + fg = ega->pallook[ega->egapal[attr & 15]]; + bg = ega->pallook[ega->egapal[attr >> 4]]; + if (attr & 0x80 && ega->attrregs[0x10] & 8) + { + bg = ega->pallook[ega->egapal[(attr >> 4) & 7]]; + if (ega->blink & 16) + fg = bg; + } + } + + dat = ega->vram[charaddr + (ega->sc << 2)]; + if (ega->seqregs[1] & 8) + { + if (ega->seqregs[1] & 1) + { + for (xx = 0; xx < 8; xx++) + ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x << 4) + 32 + (xx << 1)) & 2047) + x_add] = + ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x << 4) + 33 + (xx << 1)) & 2047) + x_add] = (dat & (0x80 >> xx)) ? fg : bg; + } + else + { + for (xx = 0; xx < 8; xx++) + ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x * 18) + 32 + (xx << 1)) & 2047) + x_add] = + ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x * 18) + 33 + (xx << 1)) & 2047) + x_add] = (dat & (0x80 >> xx)) ? fg : bg; + if ((chr & ~0x1f) != 0xc0 || !(ega->attrregs[0x10] & 4)) + ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x * 18) + 32 + 16) & 2047) + x_add] = + ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x * 18) + 32 + 17) & 2047) + x_add] = bg; + else + ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x * 18) + 32 + 16) & 2047) + x_add] = + ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x * 18) + 32 + 17) & 2047) + x_add] = (dat & 1) ? fg : bg; + } + } + else + { + if (ega->seqregs[1] & 1) + { + for (xx = 0; xx < 8; xx++) + ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x << 3) + 32 + xx) & 2047) + x_add] = (dat & (0x80 >> xx)) ? fg : bg; + } + else + { + for (xx = 0; xx < 8; xx++) + ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x * 9) + 32 + xx) & 2047) + x_add] = (dat & (0x80 >> xx)) ? fg : bg; + if ((chr & ~0x1f) != 0xc0 || !(ega->attrregs[0x10] & 4)) + ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x * 9) + 32 + 8) & 2047) + x_add] = bg; + else + ((uint32_t *)buffer32->line[ega->displine + y_add])[(((x * 9) + 32 + 8) & 2047) + x_add] = (dat & 1) ? fg : bg; + } + } + ega->ma += 4; + ega->ma &= ega->vrammask; + } + } + } + else + { + switch (ega->gdcreg[5] & 0x20) + { + case 0x00: + if (ega->seqregs[1] & 8) + { + offset = ((8 - ega->scrollcache) << 1) + 16; + for (x = 0; x <= ega->hdisp; x++) + { + if (ega->sc & 1 && !(ega->crtc[0x17] & 1)) + { + edat[0] = ega->vram[ega->ma | 0x8000]; + edat[1] = ega->vram[ega->ma | 0x8001]; + edat[2] = ega->vram[ega->ma | 0x8002]; + edat[3] = ega->vram[ega->ma | 0x8003]; + } + else + { + edat[0] = ega->vram[ega->ma]; + edat[1] = ega->vram[ega->ma | 0x1]; + edat[2] = ega->vram[ega->ma | 0x2]; + edat[3] = ega->vram[ega->ma | 0x3]; + } + ega->ma += 4; + ega->ma &= ega->vrammask; + + dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 14 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 15 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 12 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 13 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 10 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 11 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 8 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 9 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 6 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 7 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 4 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 5 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 2 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 3 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 1 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + } + } + else + { + offset = (8 - ega->scrollcache) + 24; + for (x = 0; x <= ega->hdisp; x++) + { + if (ega->sc & 1 && !(ega->crtc[0x17] & 1)) + { + edat[0] = ega->vram[ega->ma | 0x8000]; + edat[1] = ega->vram[ega->ma | 0x8001]; + edat[2] = ega->vram[ega->ma | 0x8002]; + edat[3] = ega->vram[ega->ma | 0x8003]; + } + else + { + edat[0] = ega->vram[ega->ma]; + edat[1] = ega->vram[ega->ma | 0x1]; + edat[2] = ega->vram[ega->ma | 0x2]; + edat[3] = ega->vram[ega->ma | 0x3]; + } + ega->ma += 4; + ega->ma &= ega->vrammask; + + dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 3) + 7 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 3) + 6 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 3) + 5 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 3) + 4 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 3) + 3 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 3) + 2 + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 3) + 1 + offset + x_add] = ega->pallook[ega->egapal[(dat & 0xf) & ega->attrregs[0x12]]]; + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 3) + offset + x_add] = ega->pallook[ega->egapal[(dat >> 4) & ega->attrregs[0x12]]]; + } + } + break; + case 0x20: + offset = ((8 - ega->scrollcache) << 1) + 16; + for (x = 0; x <= ega->hdisp; x++) + { + if (ega->sc & 1 && !(ega->crtc[0x17] & 1)) + { + edat[0] = ega->vram[(ega->ma << 1) + 0x8000]; + edat[1] = ega->vram[(ega->ma << 1) + 0x8001]; + } + else + { + edat[0] = ega->vram[(ega->ma << 1)]; + edat[1] = ega->vram[(ega->ma << 1) + 1]; + } + ega->ma += 4; + ega->ma &= ega->vrammask; + + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 14 + offset + x_add]= ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 15 + offset + x_add] = ega->pallook[ega->egapal[edat[1] & 3]]; + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 12 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 13 + offset + x_add] = ega->pallook[ega->egapal[(edat[1] >> 2) & 3]]; + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 10 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 11 + offset + x_add] = ega->pallook[ega->egapal[(edat[1] >> 4) & 3]]; + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 8 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 9 + offset + x_add] = ega->pallook[ega->egapal[(edat[1] >> 6) & 3]]; + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 6 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 7 + offset + x_add] = ega->pallook[ega->egapal[(edat[0] >> 0) & 3]]; + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 4 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 5 + offset + x_add] = ega->pallook[ega->egapal[(edat[0] >> 2) & 3]]; + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 2 + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 3 + offset + x_add] = ega->pallook[ega->egapal[(edat[0] >> 4) & 3]]; + ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + offset + x_add] = ((uint32_t *)buffer32->line[ega->displine + y_add])[(x << 4) + 1 + offset + x_add] = ega->pallook[ega->egapal[(edat[0] >> 6) & 3]]; + } + break; + } + } + } + if (ega->lastline < ega->displine) + ega->lastline = ega->displine; + } + + ega->displine++; + if ((ega->stat & 8) && ((ega->displine & 15) == (ega->crtc[0x11] & 15)) && ega->vslines) + ega->stat &= ~8; + ega->vslines++; + if (ega->displine > 500) + ega->displine = 0; + } + else + { + ega->vidtime += ega->dispontime; +// if (output) printf("Display on %f\n",vidtime); + if (ega->dispon) + ega->stat &= ~1; + ega->linepos = 0; + if (ega->sc == (ega->crtc[11] & 31)) + ega->con = 0; + if (ega->dispon) + { + if (ega->sc == (ega->crtc[9] & 31)) + { + ega->sc = 0; + + ega->maback += (ega->rowoffset << 3); + ega->maback &= ega->vrammask; + ega->ma = ega->maback; + } + else + { + ega->sc++; + ega->sc &= 31; + ega->ma = ega->maback; + } + } + ega->vc++; + ega->vc &= 1023; +// printf("Line now %i %i ma %05X\n",vc,displine,ma); + if (ega->vc == ega->split) + { +// printf("Split at line %i %i\n",displine,vc); + ega->ma = ega->maback = 0; + if (ega->attrregs[0x10] & 0x20) + ega->scrollcache = 0; + } + if (ega->vc == ega->dispend) + { +// printf("Display over at line %i %i\n",displine,vc); + ega->dispon=0; + if (ega->crtc[10] & 0x20) ega->cursoron = 0; + else ega->cursoron = ega->blink & 16; + if (!(ega->gdcreg[6] & 1) && !(ega->blink & 15)) + fullchange = 2; + ega->blink++; + + if (fullchange) + fullchange--; + } + if (ega->vc == ega->vsyncstart) + { + int wx = 0; + int wy = 0; + ega->dispon = 0; +// printf("Vsync on at line %i %i\n",displine,vc); + ega->stat |= 8; + if (ega->seqregs[1] & 8) x = ega->hdisp * ((ega->seqregs[1] & 1) ? 8 : 9) * 2; + else x = ega->hdisp * ((ega->seqregs[1] & 1) ? 8 : 9); +// pclog("Cursor %02X %02X\n",crtc[10],crtc[11]); +// pclog("Firstline %i Lastline %i wx %i %i\n",firstline,lastline,wx,oddeven); +// doblit(); + if (x != xsize || (ega->lastline - ega->firstline) != ysize) + { + xsize = x; + ysize = ega->lastline - ega->firstline; + if (xsize < 64) xsize = 640; + if (ysize < 32) ysize = 200; + if (ega->vres) + updatewindowsize(xsize + x_add_ex, (ysize << 1) + y_add_ex); + else + updatewindowsize(xsize + x_add_ex, ysize + y_add_ex); + } + +startblit(); + if (enable_overscan) + { + if ((x >= 160) && ((ega->lastline - ega->firstline) >= 120)) + { + for (i = 0; i < 14; i++) + { + q = &((uint32_t *)buffer32->line[i])[32]; + r = &((uint32_t *)buffer32->line[ysize + y_add_ex - 1 - i])[32]; + + for (j = 0; j < (xsize + x_add_ex); j++) + { + q[j] = ega->pallook[ega->attrregs[0x11]]; + r[j] = ega->pallook[ega->attrregs[0x11]]; + } + } + + for (i = 14; i < (ysize + 14); i ++) + { + q = &((uint32_t *)buffer32->line[i])[32]; + + for (j = 0; j < 8; j++) + { + q[j] = ega->pallook[ega->attrregs[0x11]]; + q[xsize + x_add_ex - 1 - j] = ega->pallook[ega->attrregs[0x11]]; + } + } + } + } + + video_blit_memtoscreen(32, 0, ega->firstline, ega->lastline + y_add_ex, xsize + x_add_ex, ega->lastline - ega->firstline + y_add_ex); + endblit(); + + frames++; + + ega->video_res_x = wx; + ega->video_res_y = wy + 1; + if (!(ega->gdcreg[6] & 1)) /*Text mode*/ + { + ega->video_res_x /= (ega->seqregs[1] & 1) ? 8 : 9; + ega->video_res_y /= (ega->crtc[9] & 31) + 1; + ega->video_bpp = 0; + } + else + { + if (ega->crtc[9] & 0x80) + ega->video_res_y /= 2; + if (!(ega->crtc[0x17] & 1)) + ega->video_res_y *= 2; + ega->video_res_y /= (ega->crtc[9] & 31) + 1; + if (ega->seqregs[1] & 8) + ega->video_res_x /= 2; + ega->video_bpp = (ega->gdcreg[5] & 0x20) ? 2 : 4; + } + +// wakeupblit(); + readflash=0; + //framecount++; + ega->firstline = 2000; + ega->lastline = 0; + + ega->maback = ega->ma = (ega->crtc[0xc] << 8)| ega->crtc[0xd]; + ega->ca = (ega->crtc[0xe] << 8) | ega->crtc[0xf]; + ega->ma <<= 2; + ega->maback <<= 2; + ega->ca <<= 2; + changeframecount = 2; + ega->vslines = 0; + } + if (ega->vc == ega->vtotal) + { + ega->vc = 0; + ega->sc = 0; + ega->dispon = 1; + ega->displine = 0; + ega->scrollcache = ega->attrregs[0x13] & 7; + } + if (ega->sc == (ega->crtc[10] & 31)) + ega->con = 1; + } +} + +void ega_write(uint32_t addr, uint8_t val, void *p) +{ + ega_t *ega = (ega_t *)p; + uint8_t vala, valb, valc, vald; + int writemask2 = ega->writemask; + uint32_t raddr = addr; + int plane, mask; + + egawrites++; + cycles -= video_timing_b; + cycles_lost += video_timing_b; + + /* Horrible hack, I know, but it's the only way to fix the 440FX BIOS filling the VRAM with garbage until Tom fixes the memory emulation. */ + if ((cs == 0xE0000) && (cpu_state.pc == 0xBF2F) && (romset == ROM_440FX)) return; + if ((cs == 0xE0000) && (cpu_state.pc == 0xBF77) && (romset == ROM_440FX)) return; + + if (addr >= 0xB0000) addr &= 0x7fff; + else addr &= 0xffff; + + if (ega->chain2_write) + { + plane = (ega->readplane & 2) | (addr & 1); + mask = (1 << plane); + if (ega->seqregs[2] & mask) + { + addr = ((addr & ~1) << 2) | plane | (ega->oddeven_page ? 0x10000 : 0); + if ((!ega->extvram) && (addr >= 0x10000)) return; + if (addr >= 0x40000) return; + if ((raddr <= 0xA0000) || (raddr >= 0xBFFFF)) return; + ega->vram[addr] = val; + } + return; + } + + addr <<= 2; + + if (!(ega->gdcreg[6] & 1)) + fullchange = 2; + +// pclog("%i %08X %i %i %02X %02X %02X %02X %02X\n",chain4,addr,writemode,writemask,gdcreg[8],vram[0],vram[1],vram[2],vram[3]); + switch (ega->writemode) + { + case 1: + if (writemask2 & 1) ega->vram[addr] = ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = ega->ld; + break; + case 0: + if (ega->gdcreg[3] & 7) + val = ega_rotate[ega->gdcreg[3] & 7][val]; + + if (ega->gdcreg[8] == 0xff && !(ega->gdcreg[3] & 0x18) && !ega->gdcreg[1]) + { + if (writemask2 & 1) ega->vram[addr] = val; + if (writemask2 & 2) ega->vram[addr | 0x1] = val; + if (writemask2 & 4) ega->vram[addr | 0x2] = val; + if (writemask2 & 8) ega->vram[addr | 0x3] = val; + } + else + { + if (ega->gdcreg[1] & 1) vala = (ega->gdcreg[0] & 1) ? 0xff : 0; + else vala = val; + if (ega->gdcreg[1] & 2) valb = (ega->gdcreg[0] & 2) ? 0xff : 0; + else valb = val; + if (ega->gdcreg[1] & 4) valc = (ega->gdcreg[0] & 4) ? 0xff : 0; + else valc = val; + if (ega->gdcreg[1] & 8) vald = (ega->gdcreg[0] & 8) ? 0xff : 0; + else vald = val; +// pclog("Write %02X %01X %02X %02X %02X %02X %02X\n",gdcreg[3]&0x18,writemask,vala,valb,valc,vald,gdcreg[8]); + switch (ega->gdcreg[3] & 0x18) + { + case 0: /*Set*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | (ega->la & ~ega->gdcreg[8]); + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | (ega->lb & ~ega->gdcreg[8]); + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | (ega->lc & ~ega->gdcreg[8]); + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | (ega->ld & ~ega->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) ega->vram[addr] = (vala | ~ega->gdcreg[8]) & ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb | ~ega->gdcreg[8]) & ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc | ~ega->gdcreg[8]) & ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald | ~ega->gdcreg[8]) & ega->ld; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | ega->ld; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) ^ ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) ^ ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) ^ ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) ^ ega->ld; + break; + } +// pclog("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); + } + break; + case 2: + if (!(ega->gdcreg[3] & 0x18) && !ega->gdcreg[1]) + { + if (writemask2 & 1) ega->vram[addr] = (((val & 1) ? 0xff : 0) & ega->gdcreg[8]) | (ega->la & ~ega->gdcreg[8]); + if (writemask2 & 2) ega->vram[addr | 0x1] = (((val & 2) ? 0xff : 0) & ega->gdcreg[8]) | (ega->lb & ~ega->gdcreg[8]); + if (writemask2 & 4) ega->vram[addr | 0x2] = (((val & 4) ? 0xff : 0) & ega->gdcreg[8]) | (ega->lc & ~ega->gdcreg[8]); + if (writemask2 & 8) ega->vram[addr | 0x3] = (((val & 8) ? 0xff : 0) & ega->gdcreg[8]) | (ega->ld & ~ega->gdcreg[8]); + } + else + { + vala = ((val & 1) ? 0xff : 0); + valb = ((val & 2) ? 0xff : 0); + valc = ((val & 4) ? 0xff : 0); + vald = ((val & 8) ? 0xff : 0); + switch (ega->gdcreg[3] & 0x18) + { + case 0: /*Set*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | (ega->la & ~ega->gdcreg[8]); + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | (ega->lb & ~ega->gdcreg[8]); + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | (ega->lc & ~ega->gdcreg[8]); + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | (ega->ld & ~ega->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) ega->vram[addr] = (vala | ~ega->gdcreg[8]) & ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb | ~ega->gdcreg[8]) & ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc | ~ega->gdcreg[8]) & ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald | ~ega->gdcreg[8]) & ega->ld; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) | ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) | ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) | ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) | ega->ld; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) ega->vram[addr] = (vala & ega->gdcreg[8]) ^ ega->la; + if (writemask2 & 2) ega->vram[addr | 0x1] = (valb & ega->gdcreg[8]) ^ ega->lb; + if (writemask2 & 4) ega->vram[addr | 0x2] = (valc & ega->gdcreg[8]) ^ ega->lc; + if (writemask2 & 8) ega->vram[addr | 0x3] = (vald & ega->gdcreg[8]) ^ ega->ld; + break; + } + } + break; + } +} + +uint8_t ega_read(uint32_t addr, void *p) +{ + ega_t *ega = (ega_t *)p; + uint8_t temp, temp2, temp3, temp4; + int readplane = ega->readplane; + int plane; + + egareads++; + cycles -= video_timing_b; + cycles_lost += video_timing_b; +// pclog("Readega %06X ",addr); + if (addr >= 0xb0000) addr &= 0x7fff; + else addr &= 0xffff; + + if (ega->chain2_read) + { + plane = (ega->readplane & 2) | (addr & 1); + addr = ((addr & ~1) << 2) | plane | (ega->oddeven_page ? 0x10000 : 0); + if ((!ega->extvram) && (addr >= 0x10000)) return 0xff; + if (addr >= 0x40000) return 0xff; + return ega->vram[addr]; + } + + addr <<= 2; + + ega->la = ega->vram[addr]; + ega->lb = ega->vram[addr | 0x1]; + ega->lc = ega->vram[addr | 0x2]; + ega->ld = ega->vram[addr | 0x3]; + if (ega->readmode) + { + temp = (ega->colournocare & 1) ? 0xff : 0; + temp &= ega->la; + temp ^= (ega->colourcompare & 1) ? 0xff : 0; + temp2 = (ega->colournocare & 2) ? 0xff : 0; + temp2 &= ega->lb; + temp2 ^= (ega->colourcompare & 2) ? 0xff : 0; + temp3 = (ega->colournocare & 4) ? 0xff : 0; + temp3 &= ega->lc; + temp3 ^= (ega->colourcompare & 4) ? 0xff : 0; + temp4 = (ega->colournocare & 8) ? 0xff : 0; + temp4 &= ega->ld; + temp4 ^= (ega->colourcompare & 8) ? 0xff : 0; + return ~(temp | temp2 | temp3 | temp4); + } + return ega->vram[addr | readplane]; +} + +void ega_init(ega_t *ega) +{ + int c, d, e; + + ega->vram = malloc(0x40000); + ega->vrammask = 0x3ffff; + + for (c = 0; c < 256; c++) + { + e = c; + for (d = 0; d < 8; d++) + { + ega_rotate[d][c] = e; + e = (e >> 1) | ((e & 1) ? 0x80 : 0); + } + } + + for (c = 0; c < 4; c++) + { + for (d = 0; d < 4; d++) + { + edatlookup[c][d] = 0; + if (c & 1) edatlookup[c][d] |= 1; + if (d & 1) edatlookup[c][d] |= 2; + if (c & 2) edatlookup[c][d] |= 0x10; + if (d & 2) edatlookup[c][d] |= 0x20; + } + } + + for (c = 0; c < 256; c++) + { + pallook64[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa); + pallook64[c] += makecol32(((c >> 5) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 3) & 1) * 0x55); + pallook16[c] = makecol32(((c >> 2) & 1) * 0xaa, ((c >> 1) & 1) * 0xaa, (c & 1) * 0xaa); + pallook16[c] += makecol32(((c >> 4) & 1) * 0x55, ((c >> 4) & 1) * 0x55, ((c >> 4) & 1) * 0x55); + if ((c & 0x17) == 6) + pallook16[c] = makecol32(0xaa, 0x55, 0); + } + ega->pallook = pallook16; +} + +void ega_common_defaults(ega_t *ega) +{ + ega->miscout |= 0x22; + ega->enablevram = 1; + ega->oddeven_page = 0; + + ega->seqregs[4] |= 2; + ega->extvram = 1; +} + +void *ega_standalone_init() +{ + int c, d, e; + ega_t *ega = malloc(sizeof(ega_t)); + memset(ega, 0, sizeof(ega_t)); + + overscan_x = 16; + overscan_y = 28; + + rom_init(&ega->bios_rom, "roms/ibm_6277356_ega_card_u44_27128.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + if (ega->bios_rom.rom[0x3ffe] == 0xaa && ega->bios_rom.rom[0x3fff] == 0x55) + { + int c; + + for (c = 0; c < 0x2000; c++) + { + uint8_t temp = ega->bios_rom.rom[c]; + ega->bios_rom.rom[c] = ega->bios_rom.rom[0x3fff - c]; + ega->bios_rom.rom[0x3fff - c] = temp; + } + } + + ega->crtc[0] = 63; + ega->dispontime = 1000 * (1 << TIMER_SHIFT); + ega->dispofftime = 1000 * (1 << TIMER_SHIFT); + ega->dispontime <<= 1; + ega->dispofftime <<= 1; + + ega_init(ega); + + ega_common_defaults(ega); + + mem_mapping_add(&ega->mapping, 0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, 0, ega); + timer_add(ega_poll, &ega->vidtime, TIMER_ALWAYS_ENABLED, ega); + vramp = ega->vram; + io_sethandler(0x03c0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); + return ega; +} + +void *cpqega_standalone_init() +{ + int c, d, e; + ega_t *ega = malloc(sizeof(ega_t)); + memset(ega, 0, sizeof(ega_t)); + + overscan_x = 16; + overscan_y = 28; + + rom_init(&ega->bios_rom, "roms/108281-001.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + if (ega->bios_rom.rom[0x3ffe] == 0xaa && ega->bios_rom.rom[0x3fff] == 0x55) + { + int c; + // pclog("Read EGA ROM in reverse\n"); + + for (c = 0; c < 0x2000; c++) + { + uint8_t temp = ega->bios_rom.rom[c]; + ega->bios_rom.rom[c] = ega->bios_rom.rom[0x3fff - c]; + ega->bios_rom.rom[0x3fff - c] = temp; + } + } + + ega->crtc[0] = 63; + // ega->crtc[6] = 255; + ega->dispontime = 1000 * (1 << TIMER_SHIFT); + ega->dispofftime = 1000 * (1 << TIMER_SHIFT); + + ega_init(ega); + // ega->attrregs[0x10] |= 0xF7; + + ega_common_defaults(ega); + + mem_mapping_add(&ega->mapping, 0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, 0, ega); + timer_add(ega_poll, &ega->vidtime, TIMER_ALWAYS_ENABLED, ega); + vramp = ega->vram; + // io_sethandler(0x03a0, 0x0040, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); + io_sethandler(0x03c0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); + return ega; +} + +void *sega_standalone_init() +{ + int c, d, e; + ega_t *ega = malloc(sizeof(ega_t)); + memset(ega, 0, sizeof(ega_t)); + + overscan_x = 16; + overscan_y = 28; + + rom_init(&ega->bios_rom, "roms/lega.vbi", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + if (ega->bios_rom.rom[0x3ffe] == 0xaa && ega->bios_rom.rom[0x3fff] == 0x55) + { + int c; + // pclog("Read EGA ROM in reverse\n"); + + for (c = 0; c < 0x2000; c++) + { + uint8_t temp = ega->bios_rom.rom[c]; + ega->bios_rom.rom[c] = ega->bios_rom.rom[0x3fff - c]; + ega->bios_rom.rom[0x3fff - c] = temp; + } + } + + ega->crtc[0] = 63; + // ega->crtc[6] = 255; + ega->dispontime = 1000 * (1 << TIMER_SHIFT); + ega->dispofftime = 1000 * (1 << TIMER_SHIFT); + + ega_init(ega); + // ega->attrregs[0x10] |= 0xF7; + + ega_common_defaults(ega); + + mem_mapping_add(&ega->mapping, 0xa0000, 0x20000, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, 0, ega); + timer_add(ega_poll, &ega->vidtime, TIMER_ALWAYS_ENABLED, ega); + vramp = ega->vram; + // io_sethandler(0x03a0, 0x0040, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); + io_sethandler(0x03c0, 0x0020, ega_in, NULL, NULL, ega_out, NULL, NULL, ega); + return ega; +} + +static int ega_standalone_available() +{ + return rom_present("roms/ibm_6277356_ega_card_u44_27128.bin"); +} + +static int cpqega_standalone_available() +{ + return rom_present("roms/108281-001.bin"); +} + +static int sega_standalone_available() +{ + return rom_present("roms/lega.vbi"); +} + +void ega_close(void *p) +{ + ega_t *ega = (ega_t *)p; + + free(ega->vram); + free(ega); +} + +void ega_speed_changed(void *p) +{ + ega_t *ega = (ega_t *)p; + + ega_recalctimings(ega); +} + +device_t ega_device = +{ + "EGA", + 0, + ega_standalone_init, + ega_close, + ega_standalone_available, + ega_speed_changed, + NULL, + NULL +}; + +device_t cpqega_device = +{ + "Compaq EGA", + 0, + cpqega_standalone_init, + ega_close, + cpqega_standalone_available, + ega_speed_changed, + NULL, + NULL +}; + +device_t sega_device = +{ + "SuperEGA", + 0, + sega_standalone_init, + ega_close, + sega_standalone_available, + ega_speed_changed, + NULL, + NULL +}; diff --git a/src/vid_ega.h b/src/vid_ega.h new file mode 100644 index 000000000..efab56379 --- /dev/null +++ b/src/vid_ega.h @@ -0,0 +1,80 @@ +typedef struct ega_t +{ + mem_mapping_t mapping; + + rom_t bios_rom; + + uint8_t crtcreg; + uint8_t crtc[32]; + uint8_t gdcreg[16]; + int gdcaddr; + uint8_t attrregs[32]; + int attraddr, attrff; + int attr_palette_enable; + uint8_t seqregs[64]; + int seqaddr; + + uint8_t miscout; + int vidclock; + + uint8_t la, lb, lc, ld; + + uint8_t stat; + + int fast; + uint8_t colourcompare, colournocare; + int readmode, writemode, readplane; + int chain4, chain2_read, chain2_write; + int oddeven_page; + int enablevram, extvram; + uint8_t writemask; + uint32_t charseta, charsetb; + + uint8_t egapal[16]; + uint32_t *pallook; + + int vtotal, dispend, vsyncstart, split, vblankstart; + int hdisp, htotal, hdisp_time, rowoffset; + int lowres, interlace; + int linedbl, rowcount; + double clock; + uint32_t ma_latch; + + int vres; + + int dispontime, dispofftime; + int vidtime; + + uint8_t scrblank; + + int dispon; + int hdisp_on; + + uint32_t ma, maback, ca; + int vc; + int sc; + int linepos, vslines, linecountff, oddeven; + int con, cursoron, blink; + int scrollcache; + + int firstline, lastline; + int firstline_draw, lastline_draw; + int displine; + + uint8_t *vram; + int vrammask; + + int video_res_x, video_res_y, video_bpp; +} ega_t; + +void *ega_standalone_init(); +void ega_out(uint16_t addr, uint8_t val, void *p); +uint8_t ega_in(uint16_t addr, void *p); +void ega_poll(void *p); +void ega_recalctimings(struct ega_t *ega); +void ega_write(uint32_t addr, uint8_t val, void *p); +uint8_t ega_read(uint32_t addr, void *p); + +extern device_t ega_device; +extern device_t cpqega_device; +extern device_t sega_device; diff --git a/src/vid_et4000.c b/src/vid_et4000.c new file mode 100644 index 000000000..7b0583531 --- /dev/null +++ b/src/vid_et4000.c @@ -0,0 +1,211 @@ +/*ET4000 emulation*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_unk_ramdac.h" + +#include "vid_et4000.h" + +typedef struct et4000_t +{ + svga_t svga; + unk_ramdac_t ramdac; + + rom_t bios_rom; + + uint8_t banking; +} et4000_t; + +static uint8_t crtc_mask[0x40] = +{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0xff, 0xff, 0xff, 0x0f, 0xff, 0xff, 0xff, 0xff, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +void et4000_out(uint16_t addr, uint8_t val, void *p) +{ + et4000_t *et4000 = (et4000_t *)p; + svga_t *svga = &et4000->svga; + + uint8_t old; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) + addr ^= 0x60; + +// pclog("ET4000 out %04X %02X\n", addr, val); + + switch (addr) + { + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + unk_ramdac_out(addr, val, &et4000->ramdac, svga); + return; + + case 0x3CD: /*Banking*/ + svga->write_bank = (val & 0xf) * 0x10000; + svga->read_bank = ((val >> 4) & 0xf) * 0x10000; + et4000->banking = val; +// pclog("Banking write %08X %08X %02X\n", svga->write_bank, svga->read_bank, val); + return; + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + // pclog("ET4000 Write: CRTC %02X = %02X\n", svga->crtcreg, val); + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + val &= crtc_mask[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) + { + if (svga->crtcreg < 0xE || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t et4000_in(uint16_t addr, void *p) +{ + et4000_t *et4000 = (et4000_t *)p; + svga_t *svga = &et4000->svga; + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) + addr ^= 0x60; + +// if (addr != 0x3da) pclog("IN ET4000 %04X\n", addr); + + switch (addr) + { + case 0x3C5: + if ((svga->seqaddr & 0xf) == 7) return svga->seqregs[svga->seqaddr & 0xf] | 4; + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + return unk_ramdac_in(addr, &et4000->ramdac, svga); + + case 0x3CD: /*Banking*/ + return et4000->banking; + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + return svga->crtc[svga->crtcreg]; + } + return svga_in(addr, svga); +} + +void et4000_recalctimings(svga_t *svga) +{ + et4000_t *et4000 = (et4000_t *)svga->p; + + svga->ma_latch |= (svga->crtc[0x33]&3)<<16; + if (svga->crtc[0x35] & 2) svga->vtotal += 0x400; + if (svga->crtc[0x35] & 4) svga->dispend += 0x400; + if (svga->crtc[0x35] & 8) svga->vsyncstart += 0x400; + if (svga->crtc[0x35] & 0x10) svga->split += 0x400; + if (!svga->rowoffset) svga->rowoffset = 0x100; + if (svga->crtc[0x3f] & 1) svga->htotal += 256; + if (svga->attrregs[0x16] & 0x20) svga->hdisp <<= 1; + +// pclog("Rowoffset %i\n",svga_rowoffset); + + switch (((svga->miscout >> 2) & 3) | ((svga->crtc[0x34] << 1) & 4)) + { + case 0: case 1: break; + case 3: svga->clock = cpuclock / 40000000.0; break; + case 5: svga->clock = cpuclock / 65000000.0; break; + default: svga->clock = cpuclock / 36000000.0; break; + } + + switch (svga->bpp) + { + case 15: case 16: + svga->hdisp /= 2; + break; + case 24: + svga->hdisp /= 3; + break; + } +} + +void *et4000_init() +{ + et4000_t *et4000 = malloc(sizeof(et4000_t)); + memset(et4000, 0, sizeof(et4000_t)); + + rom_init(&et4000->bios_rom, "roms/et4000.BIN", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + io_sethandler(0x03c0, 0x0020, et4000_in, NULL, NULL, et4000_out, NULL, NULL, et4000); + + svga_init(&et4000->svga, et4000, 1 << 20, /*1mb*/ + et4000_recalctimings, + et4000_in, et4000_out, + NULL, + NULL); + + return et4000; +} + +static int et4000_available() +{ + return rom_present("roms/et4000.BIN"); +} + +void et4000_close(void *p) +{ + et4000_t *et4000 = (et4000_t *)p; + + svga_close(&et4000->svga); + + free(et4000); +} + +void et4000_speed_changed(void *p) +{ + et4000_t *et4000 = (et4000_t *)p; + + svga_recalctimings(&et4000->svga); +} + +void et4000_force_redraw(void *p) +{ + et4000_t *et4000 = (et4000_t *)p; + + et4000->svga.fullchange = changeframecount; +} + +void et4000_add_status_info(char *s, int max_len, void *p) +{ + et4000_t *et4000 = (et4000_t *)p; + + svga_add_status_info(s, max_len, &et4000->svga); +} + +device_t et4000_device = +{ + "Tseng Labs ET4000AX", + 0, + et4000_init, + et4000_close, + et4000_available, + et4000_speed_changed, + et4000_force_redraw, + et4000_add_status_info +}; diff --git a/src/vid_et4000.h b/src/vid_et4000.h new file mode 100644 index 000000000..a20f8820d --- /dev/null +++ b/src/vid_et4000.h @@ -0,0 +1 @@ +extern device_t et4000_device; diff --git a/src/vid_et4000w32.c b/src/vid_et4000w32.c new file mode 100644 index 000000000..a46a040dc --- /dev/null +++ b/src/vid_et4000w32.c @@ -0,0 +1,1451 @@ +/*ET4000/W32p emulation (Diamond Stealth 32)*/ +/*Known bugs : + + - Accelerator doesn't work in planar modes +*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "pci.h" +#include "rom.h" +#include "thread.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_icd2061.h" +#include "vid_stg_ramdac.h" + +#define FIFO_SIZE 65536 +#define FIFO_MASK (FIFO_SIZE - 1) +#define FIFO_ENTRY_SIZE (1 << 31) + +#define FIFO_ENTRIES (et4000->fifo_write_idx - et4000->fifo_read_idx) +#define FIFO_FULL ((et4000->fifo_write_idx - et4000->fifo_read_idx) >= FIFO_SIZE) +#define FIFO_EMPTY (et4000->fifo_read_idx == et4000->fifo_write_idx) + +#define FIFO_TYPE 0xff000000 +#define FIFO_ADDR 0x00ffffff + +enum +{ + FIFO_INVALID = (0x00 << 24), + FIFO_WRITE_BYTE = (0x01 << 24), + FIFO_WRITE_MMU = (0x02 << 24) +}; + +typedef struct +{ + uint32_t addr_type; + uint32_t val; +} fifo_entry_t; + +typedef struct et4000w32p_t +{ + mem_mapping_t linear_mapping; + mem_mapping_t mmu_mapping; + + rom_t bios_rom; + + svga_t svga; + stg_ramdac_t ramdac; + icd2061_t icd2061; + + int index; + uint8_t regs[256]; + uint32_t linearbase, linearbase_old; + + uint8_t banking, banking2; + + uint8_t pci_regs[256]; + + int vram_size; + int interleaved; + int max_ram_mask; + int revision; + + /*Accelerator*/ + struct + { + struct + { + uint32_t pattern_addr,source_addr,dest_addr,mix_addr; + uint16_t pattern_off,source_off,dest_off,mix_off; + uint8_t pixel_depth,xy_dir; + uint8_t pattern_wrap,source_wrap; + uint16_t count_x,count_y; + uint8_t ctrl_routing,ctrl_reload; + uint8_t rop_fg,rop_bg; + uint16_t pos_x,pos_y; + uint16_t error; + uint16_t dmin,dmaj; + } queued,internal; + uint32_t pattern_addr,source_addr,dest_addr,mix_addr; + uint32_t pattern_back,source_back,dest_back,mix_back; + int pattern_x,source_x; + int pattern_x_back,source_x_back; + int pattern_y,source_y; + uint8_t status; + uint64_t cpu_dat; + int cpu_dat_pos; + int pix_pos; + } acl; + + struct + { + uint32_t base[3]; + uint8_t ctrl; + } mmu; + + fifo_entry_t fifo[FIFO_SIZE]; + volatile int fifo_read_idx, fifo_write_idx; + + thread_t *fifo_thread; + event_t *wake_fifo_thread; + event_t *fifo_not_full_event; + + int blitter_busy; + uint64_t blitter_time; + uint64_t status_time; +} et4000w32p_t; + +void et4000w32p_recalcmapping(et4000w32p_t *et4000); + +uint8_t et4000w32p_mmu_read(uint32_t addr, void *p); +void et4000w32p_mmu_write(uint32_t addr, uint8_t val, void *p); + +void et4000w32_blit_start(et4000w32p_t *et4000); +void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input, et4000w32p_t *et4000); + +void et4000w32p_out(uint16_t addr, uint8_t val, void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + svga_t *svga = &et4000->svga; + uint8_t old; + +// pclog("et4000w32p_out: addr %04X val %02X %04X:%04X %02X %02X\n", addr, val, CS, pc, ram[0x487], ram[0x488]); + +/* if (ram[0x487] == 0x62) + fatal("mono\n");*/ +// if (!(addr==0x3D4 && (val&~1)==0xE) && !(addr==0x3D5 && (crtcreg&~1)==0xE)) pclog("ET4000W32p out %04X %02X %04X:%04X ",addr,val,CS,pc); + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + +// if (!(addr==0x3D4 && (val&~1)==0xE) && !(addr==0x3D5 && (crtcreg&~1)==0xE)) pclog("%04X\n",addr); + + switch (addr) + { + case 0x3c2: + if (gfxcard == GFX_ET4000W32) + icd2061_write(&et4000->icd2061, (val >> 2) & 3); + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + stg_ramdac_out(addr, val, &et4000->ramdac, svga); + return; + + case 0x3CB: /*Banking extension*/ + svga->write_bank = (svga->write_bank & 0xfffff) | ((val & 1) << 20); + svga->read_bank = (svga->read_bank & 0xfffff) | ((val & 0x10) << 16); + et4000->banking2 = val; + return; + case 0x3CD: /*Banking*/ + svga->write_bank = (svga->write_bank & 0x100000) | ((val & 0xf) * 65536); + svga->read_bank = (svga->read_bank & 0x100000) | (((val >> 4) & 0xf) * 65536); + et4000->banking = val; + return; + case 0x3CF: + switch (svga->gdcaddr & 15) + { + case 6: + svga->gdcreg[svga->gdcaddr & 15] = val; + //et4k_b8000=((crtc[0x36]&0x38)==0x28) && ((gdcreg[6]&0xC)==4); + et4000w32p_recalcmapping(et4000); + return; + } + break; + case 0x3D4: + svga->crtcreg = val & 63; + return; + case 0x3D5: +// pclog("Write CRTC R%02X %02X\n", crtcreg, val); + if (svga->crtcreg <= 0x18) + val &= mask_crtc[svga->crtcreg]; + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + if (svga->crtcreg == 0x30) + { + et4000->linearbase = val * 0x400000; +// pclog("Linear base now at %08X %02X\n", et4000w32p_linearbase, val); + et4000w32p_recalcmapping(et4000); + } + if (svga->crtcreg == 0x32 || svga->crtcreg == 0x36) + et4000w32p_recalcmapping(et4000); + break; + + case 0x210A: case 0x211A: case 0x212A: case 0x213A: + case 0x214A: case 0x215A: case 0x216A: case 0x217A: + et4000->index=val; + return; + case 0x210B: case 0x211B: case 0x212B: case 0x213B: + case 0x214B: case 0x215B: case 0x216B: case 0x217B: + et4000->regs[et4000->index] = val; + svga->hwcursor.x = et4000->regs[0xE0] | ((et4000->regs[0xE1] & 7) << 8); + svga->hwcursor.y = et4000->regs[0xE4] | ((et4000->regs[0xE5] & 7) << 8); + svga->hwcursor.addr = (et4000->regs[0xE8] | (et4000->regs[0xE9] << 8) | ((et4000->regs[0xEA] & 7) << 16)) << 2; + svga->hwcursor.addr += (et4000->regs[0xE6] & 63) * 16; + svga->hwcursor.ena = et4000->regs[0xF7] & 0x80; + svga->hwcursor.xoff = et4000->regs[0xE2] & 63; + svga->hwcursor.yoff = et4000->regs[0xE6] & 63; +// pclog("HWCURSOR X %i Y %i\n",svga->hwcursor_x,svga->hwcursor_y); + return; + + } + svga_out(addr, val, svga); +} + +uint8_t et4000w32p_in(uint16_t addr, void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + svga_t *svga = &et4000->svga; + uint8_t temp; +// if (addr==0x3DA) pclog("In 3DA %04X(%06X):%04X\n",CS,cs,pc); + +// pclog("ET4000W32p in %04X %04X:%04X ",addr,CS,pc); + +// if (addr != 0x3da && addr != 0x3ba) +// pclog("et4000w32p_in: addr %04X %04X:%04X %02X %02X\n", addr, CS, pc, ram[0x487], ram[0x488]); + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + +// pclog("%04X\n",addr); + + switch (addr) + { + case 0x3c5: + if ((svga->seqaddr & 0xf) == 7) + return svga->seqregs[svga->seqaddr & 0xf] | 4; + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + return stg_ramdac_in(addr, &et4000->ramdac, svga); + + case 0x3CB: + return et4000->banking2; + case 0x3CD: + return et4000->banking; + case 0x3D4: + return svga->crtcreg; + case 0x3D5: +// pclog("Read CRTC R%02X %02X\n", crtcreg, crtc[crtcreg]); + return svga->crtc[svga->crtcreg]; + + case 0x3DA: + if (gfxcard == GFX_ET4000W32C) break; + svga->attrff = 0; + svga->cgastat ^= 0x30; + temp = svga->cgastat & 0x39; + if (svga->hdisp_on) temp |= 2; + if (!(svga->cgastat & 8)) temp |= 0x80; +// pclog("3DA in %02X\n",temp); + return temp; + + case 0x210A: case 0x211A: case 0x212A: case 0x213A: + case 0x214A: case 0x215A: case 0x216A: case 0x217A: + return et4000->index; + case 0x210B: case 0x211B: case 0x212B: case 0x213B: + case 0x214B: case 0x215B: case 0x216B: case 0x217B: + if (et4000->index==0xec) + return (et4000->regs[0xec] & 0xf) | 0x60; /*ET4000/W32p rev D*/ + if (et4000->index == 0xef) + { + if (PCI) return et4000->regs[0xef] | 0xe0; /*PCI*/ + else return et4000->regs[0xef] | 0x60; /*VESA local bus*/ + } + return et4000->regs[et4000->index]; + } + return svga_in(addr, svga); +} + +void et4000w32p_recalctimings(svga_t *svga) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)svga->p; +// pclog("Recalc %08X ",svga_ma); + svga->ma_latch |= (svga->crtc[0x33] & 0x7) << 16; +// pclog("SVGA_MA %08X %i\n", svga_ma, (svga_miscout >> 2) & 3); + if (svga->crtc[0x35] & 0x01) svga->vblankstart += 0x400; + if (svga->crtc[0x35] & 0x02) svga->vtotal += 0x400; + if (svga->crtc[0x35] & 0x04) svga->dispend += 0x400; + if (svga->crtc[0x35] & 0x08) svga->vsyncstart += 0x400; + if (svga->crtc[0x35] & 0x10) svga->split += 0x400; + if (svga->crtc[0x3F] & 0x80) svga->rowoffset += 0x100; + if (svga->crtc[0x3F] & 0x01) svga->htotal += 256; + if (svga->attrregs[0x16] & 0x20) svga->hdisp <<= 1; + + if (gfxcard == GFX_ET4000W32) + { + switch ((svga->miscout >> 2) & 3) + { + case 0: case 1: break; + case 2: case 3: svga->clock = cpuclock / icd2061_getfreq(&et4000->icd2061, 2); break; + } + } + else + { + svga->clock = cpuclock / stg_getclock((svga->miscout >> 2) & 3, &et4000->ramdac); + } + + switch (svga->bpp) + { + case 15: case 16: + svga->hdisp >>= 1; + break; + case 24: + svga->hdisp /= 3; + break; + } +} + +void et4000w32p_recalcmapping(et4000w32p_t *et4000) +{ + svga_t *svga = &et4000->svga; + + if (!(et4000->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) + { + pclog("Update mapping - PCI disabled\n"); + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&et4000->linear_mapping); + mem_mapping_disable(&et4000->mmu_mapping); + return; + } + + pclog("recalcmapping %p\n", svga); + if (svga->crtc[0x36] & 0x10) /*Linear frame buffer*/ + { + mem_mapping_set_addr(&et4000->linear_mapping, et4000->linearbase, 0x200000); + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&et4000->mmu_mapping); + } + else + { + int map = (svga->gdcreg[6] & 0xc) >> 2; + if (svga->crtc[0x36] & 0x20) map |= 4; + if (svga->crtc[0x36] & 0x08) map |= 8; + switch (map) + { + case 0x0: case 0x4: case 0x8: case 0xC: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + mem_mapping_disable(&et4000->mmu_mapping); + svga->banked_mask = 0xffff; + break; + case 0x1: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + mem_mapping_disable(&et4000->mmu_mapping); + svga->banked_mask = 0xffff; + break; + case 0x2: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + mem_mapping_disable(&et4000->mmu_mapping); + svga->banked_mask = 0x7fff; + break; + case 0x3: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + mem_mapping_disable(&et4000->mmu_mapping); + svga->banked_mask = 0x7fff; + break; + case 0x5: case 0x9: case 0xD: /*64k at A0000, MMU at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + mem_mapping_set_addr(&et4000->mmu_mapping, 0xb8000, 0x08000); + svga->banked_mask = 0xffff; + break; + case 0x6: case 0xA: case 0xE: /*32k at B0000, MMU at A8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + mem_mapping_set_addr(&et4000->mmu_mapping, 0xa8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0x7: case 0xB: case 0xF: /*32k at B8000, MMU at A8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + mem_mapping_set_addr(&et4000->mmu_mapping, 0xa8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + + mem_mapping_disable(&et4000->linear_mapping); +// pclog("ET4K map %02X\n", map); + } + et4000->linearbase_old = et4000->linearbase; + + if (!et4000->interleaved && (et4000->svga.crtc[0x32] & 0x80)) + mem_mapping_disable(&svga->mapping); +} + +#define ACL_WRST 1 +#define ACL_RDST 2 +#define ACL_XYST 4 +#define ACL_SSO 8 + +static void et4000w32p_accel_write_fifo(et4000w32p_t *et4000, uint32_t addr, uint8_t val) +{ + switch (addr & 0x7fff) + { + case 0x7f80: et4000->acl.queued.pattern_addr = (et4000->acl.queued.pattern_addr & 0xFFFFFF00) | val; break; + case 0x7f81: et4000->acl.queued.pattern_addr = (et4000->acl.queued.pattern_addr & 0xFFFF00FF) | (val << 8); break; + case 0x7f82: et4000->acl.queued.pattern_addr = (et4000->acl.queued.pattern_addr & 0xFF00FFFF) | (val << 16); break; + case 0x7f83: et4000->acl.queued.pattern_addr = (et4000->acl.queued.pattern_addr & 0x00FFFFFF) | (val << 24); break; + case 0x7f84: et4000->acl.queued.source_addr = (et4000->acl.queued.source_addr & 0xFFFFFF00) | val; break; + case 0x7f85: et4000->acl.queued.source_addr = (et4000->acl.queued.source_addr & 0xFFFF00FF) | (val << 8); break; + case 0x7f86: et4000->acl.queued.source_addr = (et4000->acl.queued.source_addr & 0xFF00FFFF) | (val << 16); break; + case 0x7f87: et4000->acl.queued.source_addr = (et4000->acl.queued.source_addr & 0x00FFFFFF) | (val << 24); break; + case 0x7f88: et4000->acl.queued.pattern_off = (et4000->acl.queued.pattern_off & 0xFF00) | val; break; + case 0x7f89: et4000->acl.queued.pattern_off = (et4000->acl.queued.pattern_off & 0x00FF) | (val << 8); break; + case 0x7f8a: et4000->acl.queued.source_off = (et4000->acl.queued.source_off & 0xFF00) | val; break; + case 0x7f8b: et4000->acl.queued.source_off = (et4000->acl.queued.source_off & 0x00FF) | (val << 8); break; + case 0x7f8c: et4000->acl.queued.dest_off = (et4000->acl.queued.dest_off & 0xFF00) | val; break; + case 0x7f8d: et4000->acl.queued.dest_off = (et4000->acl.queued.dest_off & 0x00FF) | (val << 8); break; + case 0x7f8e: et4000->acl.queued.pixel_depth = val; break; + case 0x7f8f: et4000->acl.queued.xy_dir = val; break; + case 0x7f90: et4000->acl.queued.pattern_wrap = val; break; + case 0x7f92: et4000->acl.queued.source_wrap = val; break; + case 0x7f98: et4000->acl.queued.count_x = (et4000->acl.queued.count_x & 0xFF00) | val; break; + case 0x7f99: et4000->acl.queued.count_x = (et4000->acl.queued.count_x & 0x00FF) | (val << 8); break; + case 0x7f9a: et4000->acl.queued.count_y = (et4000->acl.queued.count_y & 0xFF00) | val; break; + case 0x7f9b: et4000->acl.queued.count_y = (et4000->acl.queued.count_y & 0x00FF) | (val << 8); break; + case 0x7f9c: et4000->acl.queued.ctrl_routing = val; break; + case 0x7f9d: et4000->acl.queued.ctrl_reload = val; break; + case 0x7f9e: et4000->acl.queued.rop_bg = val; break; + case 0x7f9f: et4000->acl.queued.rop_fg = val; break; + case 0x7fa0: et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0xFFFFFF00) | val; break; + case 0x7fa1: et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0xFFFF00FF) | (val << 8); break; + case 0x7fa2: et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0xFF00FFFF) | (val << 16); break; + case 0x7fa3: et4000->acl.queued.dest_addr = (et4000->acl.queued.dest_addr & 0x00FFFFFF) | (val << 24); + et4000->acl.internal = et4000->acl.queued; + et4000w32_blit_start(et4000); + if (!(et4000->acl.queued.ctrl_routing & 0x43)) + { + et4000w32_blit(0xFFFFFF, ~0, 0, 0, et4000); + } + if ((et4000->acl.queued.ctrl_routing & 0x40) && !(et4000->acl.internal.ctrl_routing & 3)) + et4000w32_blit(4, ~0, 0, 0, et4000); + break; + case 0x7fa4: et4000->acl.queued.mix_addr = (et4000->acl.queued.mix_addr & 0xFFFFFF00) | val; break; + case 0x7fa5: et4000->acl.queued.mix_addr = (et4000->acl.queued.mix_addr & 0xFFFF00FF) | (val << 8); break; + case 0x7fa6: et4000->acl.queued.mix_addr = (et4000->acl.queued.mix_addr & 0xFF00FFFF) | (val << 16); break; + case 0x7fa7: et4000->acl.queued.mix_addr = (et4000->acl.queued.mix_addr & 0x00FFFFFF) | (val << 24); break; + case 0x7fa8: et4000->acl.queued.mix_off = (et4000->acl.queued.mix_off & 0xFF00) | val; break; + case 0x7fa9: et4000->acl.queued.mix_off = (et4000->acl.queued.mix_off & 0x00FF) | (val << 8); break; + case 0x7faa: et4000->acl.queued.error = (et4000->acl.queued.error & 0xFF00) | val; break; + case 0x7fab: et4000->acl.queued.error = (et4000->acl.queued.error & 0x00FF) | (val << 8); break; + case 0x7fac: et4000->acl.queued.dmin = (et4000->acl.queued.dmin & 0xFF00) | val; break; + case 0x7fad: et4000->acl.queued.dmin = (et4000->acl.queued.dmin & 0x00FF) | (val << 8); break; + case 0x7fae: et4000->acl.queued.dmaj = (et4000->acl.queued.dmaj & 0xFF00) | val; break; + case 0x7faf: et4000->acl.queued.dmaj = (et4000->acl.queued.dmaj & 0x00FF) | (val << 8); break; + } +} + +static void et4000w32p_accel_write_mmu(et4000w32p_t *et4000, uint32_t addr, uint8_t val) +{ + if (!(et4000->acl.status & ACL_XYST)) return; + if (et4000->acl.internal.ctrl_routing & 3) + { + if ((et4000->acl.internal.ctrl_routing & 3) == 2) + { + if (et4000->acl.mix_addr & 7) + et4000w32_blit(8 - (et4000->acl.mix_addr & 7), val >> (et4000->acl.mix_addr & 7), 0, 1, et4000); + else + et4000w32_blit(8, val, 0, 1, et4000); + } + else if ((et4000->acl.internal.ctrl_routing & 3) == 1) + et4000w32_blit(1, ~0, val, 2, et4000); + } +} + +static void fifo_thread(void *param) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)param; + + while (1) + { + thread_set_event(et4000->fifo_not_full_event); + thread_wait_event(et4000->wake_fifo_thread, -1); + thread_reset_event(et4000->wake_fifo_thread); + et4000->blitter_busy = 1; + while (!FIFO_EMPTY) + { + uint64_t start_time = timer_read(); + uint64_t end_time; + fifo_entry_t *fifo = &et4000->fifo[et4000->fifo_read_idx & FIFO_MASK]; + uint32_t val = fifo->val; + + switch (fifo->addr_type & FIFO_TYPE) + { + case FIFO_WRITE_BYTE: + et4000w32p_accel_write_fifo(et4000, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_MMU: + et4000w32p_accel_write_mmu(et4000, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + } + + et4000->fifo_read_idx++; + fifo->addr_type = FIFO_INVALID; + + if (FIFO_ENTRIES > 0xe000) + thread_set_event(et4000->fifo_not_full_event); + + end_time = timer_read(); + et4000->blitter_time += end_time - start_time; + } + et4000->blitter_busy = 0; + } +} + +static inline void wake_fifo_thread(et4000w32p_t *et4000) +{ + thread_set_event(et4000->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +static void et4000w32p_wait_fifo_idle(et4000w32p_t *et4000) +{ + while (!FIFO_EMPTY) + { + wake_fifo_thread(et4000); + thread_wait_event(et4000->fifo_not_full_event, 1); + } +} + +static void et4000w32p_queue(et4000w32p_t *et4000, uint32_t addr, uint32_t val, uint32_t type) +{ + fifo_entry_t *fifo = &et4000->fifo[et4000->fifo_write_idx & FIFO_MASK]; + int c; + + if (FIFO_FULL) + { + thread_reset_event(et4000->fifo_not_full_event); + if (FIFO_FULL) + { + thread_wait_event(et4000->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ + } + } + + fifo->val = val; + fifo->addr_type = (addr & FIFO_ADDR) | type; + + et4000->fifo_write_idx++; + + if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8) + wake_fifo_thread(et4000); +} + +void et4000w32p_mmu_write(uint32_t addr, uint8_t val, void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + svga_t *svga = &et4000->svga; + int bank; +// pclog("ET4K write %08X %02X %02X %04X(%08X):%08X\n",addr,val,et4000->acl.status,et4000->acl.internal.ctrl_routing,CS,cs,pc); +// et4000->acl.status |= ACL_RDST; + switch (addr & 0x6000) + { + case 0x0000: /*MMU 0*/ + case 0x2000: /*MMU 1*/ + case 0x4000: /*MMU 2*/ + bank = (addr >> 13) & 3; + if (et4000->mmu.ctrl & (1 << bank)) + { + et4000w32p_queue(et4000, addr & 0x7fff, val, FIFO_WRITE_MMU); + } + else + { + if ((addr&0x1fff) + et4000->mmu.base[bank] < svga->vram_limit) + { + svga->vram[(addr & 0x1fff) + et4000->mmu.base[bank]] = val; + svga->changedvram[((addr & 0x1fff) + et4000->mmu.base[bank]) >> 12] = changeframecount; + } + } + break; + case 0x6000: + if ((addr & 0x7fff) >= 0x7f80) + { + et4000w32p_queue(et4000, addr & 0x7fff, val, FIFO_WRITE_BYTE); + } + else switch (addr & 0x7fff) + { + case 0x7f00: et4000->mmu.base[0] = (et4000->mmu.base[0] & 0xFFFFFF00) | val; break; + case 0x7f01: et4000->mmu.base[0] = (et4000->mmu.base[0] & 0xFFFF00FF) | (val << 8); break; + case 0x7f02: et4000->mmu.base[0] = (et4000->mmu.base[0] & 0xFF00FFFF) | (val << 16); break; + case 0x7f03: et4000->mmu.base[0] = (et4000->mmu.base[0] & 0x00FFFFFF) | (val << 24); break; + case 0x7f04: et4000->mmu.base[1] = (et4000->mmu.base[1] & 0xFFFFFF00) | val; break; + case 0x7f05: et4000->mmu.base[1] = (et4000->mmu.base[1] & 0xFFFF00FF) | (val << 8); break; + case 0x7f06: et4000->mmu.base[1] = (et4000->mmu.base[1] & 0xFF00FFFF) | (val << 16); break; + case 0x7f07: et4000->mmu.base[1] = (et4000->mmu.base[1] & 0x00FFFFFF) | (val << 24); break; + case 0x7f08: et4000->mmu.base[2] = (et4000->mmu.base[2] & 0xFFFFFF00) | val; break; + case 0x7f09: et4000->mmu.base[2] = (et4000->mmu.base[2] & 0xFFFF00FF) | (val << 8); break; + case 0x7f0a: et4000->mmu.base[2] = (et4000->mmu.base[2] & 0xFF00FFFF) | (val << 16); break; + case 0x7f0d: et4000->mmu.base[2] = (et4000->mmu.base[2] & 0x00FFFFFF) | (val << 24); break; + case 0x7f13: et4000->mmu.ctrl=val; break; + } + break; + } +} + +uint8_t et4000w32p_mmu_read(uint32_t addr, void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + svga_t *svga = &et4000->svga; + int bank; + uint8_t temp; +// pclog("ET4K read %08X %04X(%08X):%08X\n",addr,CS,cs,pc); + switch (addr & 0x6000) + { + case 0x0000: /*MMU 0*/ + case 0x2000: /*MMU 1*/ + case 0x4000: /*MMU 2*/ + bank = (addr >> 13) & 3; + if (et4000->mmu.ctrl & (1 << bank)) + { + et4000w32p_wait_fifo_idle(et4000); + temp = 0xff; + if (et4000->acl.cpu_dat_pos) + { + et4000->acl.cpu_dat_pos--; + temp = et4000->acl.cpu_dat & 0xff; + et4000->acl.cpu_dat >>= 8; + } + if ((et4000->acl.queued.ctrl_routing & 0x40) && !et4000->acl.cpu_dat_pos && !(et4000->acl.internal.ctrl_routing & 3)) + et4000w32_blit(4, ~0, 0, 0, et4000); + /*???*/ + return temp; + } + if ((addr&0x1fff) + et4000->mmu.base[bank] >= svga->vram_limit) + return 0xff; + return svga->vram[(addr&0x1fff) + et4000->mmu.base[bank]]; + + case 0x6000: + if ((addr & 0x7fff) >= 0x7f80) + et4000w32p_wait_fifo_idle(et4000); + switch (addr&0x7fff) + { + case 0x7f00: return et4000->mmu.base[0]; + case 0x7f01: return et4000->mmu.base[0] >> 8; + case 0x7f02: return et4000->mmu.base[0] >> 16; + case 0x7f03: return et4000->mmu.base[0] >> 24; + case 0x7f04: return et4000->mmu.base[1]; + case 0x7f05: return et4000->mmu.base[1] >> 8; + case 0x7f06: return et4000->mmu.base[1] >> 16; + case 0x7f07: return et4000->mmu.base[1] >> 24; + case 0x7f08: return et4000->mmu.base[2]; + case 0x7f09: return et4000->mmu.base[2] >> 8; + case 0x7f0a: return et4000->mmu.base[2] >> 16; + case 0x7f0b: return et4000->mmu.base[2] >> 24; + case 0x7f13: return et4000->mmu.ctrl; + + case 0x7f36: + temp = et4000->acl.status; +// et4000->acl.status &= ~ACL_RDST; + temp &= ~0x03; + if (!FIFO_EMPTY) + temp |= 0x02; + if (FIFO_FULL) + temp |= 0x01; +// if (et4000->acl.internal.pos_x!=et4000->acl.internal.count_x || et4000->acl.internal.pos_y!=et4000->acl.internal.count_y) return et4000->acl.status | ACL_XYST; + return temp; + case 0x7f80: return et4000->acl.internal.pattern_addr; + case 0x7f81: return et4000->acl.internal.pattern_addr >> 8; + case 0x7f82: return et4000->acl.internal.pattern_addr >> 16; + case 0x7f83: return et4000->acl.internal.pattern_addr >> 24; + case 0x7f84: return et4000->acl.internal.source_addr; + case 0x7f85: return et4000->acl.internal.source_addr >> 8; + case 0x7f86: return et4000->acl.internal.source_addr >> 16; + case 0x7f87: return et4000->acl.internal.source_addr >> 24; + case 0x7f88: return et4000->acl.internal.pattern_off; + case 0x7f89: return et4000->acl.internal.pattern_off >> 8; + case 0x7f8a: return et4000->acl.internal.source_off; + case 0x7f8b: return et4000->acl.internal.source_off >> 8; + case 0x7f8c: return et4000->acl.internal.dest_off; + case 0x7f8d: return et4000->acl.internal.dest_off >> 8; + case 0x7f8e: return et4000->acl.internal.pixel_depth; + case 0x7f8f: return et4000->acl.internal.xy_dir; + case 0x7f90: return et4000->acl.internal.pattern_wrap; + case 0x7f92: return et4000->acl.internal.source_wrap; + case 0x7f98: return et4000->acl.internal.count_x; + case 0x7f99: return et4000->acl.internal.count_x >> 8; + case 0x7f9a: return et4000->acl.internal.count_y; + case 0x7f9b: return et4000->acl.internal.count_y >> 8; + case 0x7f9c: return et4000->acl.internal.ctrl_routing; + case 0x7f9d: return et4000->acl.internal.ctrl_reload; + case 0x7f9e: return et4000->acl.internal.rop_bg; + case 0x7f9f: return et4000->acl.internal.rop_fg; + case 0x7fa0: return et4000->acl.internal.dest_addr; + case 0x7fa1: return et4000->acl.internal.dest_addr >> 8; + case 0x7fa2: return et4000->acl.internal.dest_addr >> 16; + case 0x7fa3: return et4000->acl.internal.dest_addr >> 24; + } + return 0xff; + } + return 0xff; +} + +static int et4000w32_max_x[8]={0,0,4,8,16,32,64,0x70000000}; +static int et4000w32_wrap_x[8]={0,0,3,7,15,31,63,0xFFFFFFFF}; +static int et4000w32_wrap_y[8]={1,2,4,8,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF}; + +int bltout=0; +void et4000w32_blit_start(et4000w32p_t *et4000) +{ +// if (et4000->acl.queued.xy_dir&0x80) +// pclog("Blit - %02X %08X (%i,%i) %08X (%i,%i) %08X (%i,%i) %i %i %i %02X %02X %02X\n",et4000->acl.queued.xy_dir,et4000->acl.internal.pattern_addr,(et4000->acl.internal.pattern_addr/3)%640,(et4000->acl.internal.pattern_addr/3)/640,et4000->acl.internal.source_addr,(et4000->acl.internal.source_addr/3)%640,(et4000->acl.internal.source_addr/3)/640,et4000->acl.internal.dest_addr,(et4000->acl.internal.dest_addr/3)%640,(et4000->acl.internal.dest_addr/3)/640,et4000->acl.internal.xy_dir,et4000->acl.internal.count_x,et4000->acl.internal.count_y,et4000->acl.internal.rop_fg,et4000->acl.internal.rop_bg, et4000->acl.internal.ctrl_routing); +// bltout=1; +// bltout=(et4000->acl.internal.count_x==1541); + if (!(et4000->acl.queued.xy_dir & 0x20)) + et4000->acl.internal.error = et4000->acl.internal.dmaj / 2; + et4000->acl.pattern_addr= et4000->acl.internal.pattern_addr; + et4000->acl.source_addr = et4000->acl.internal.source_addr; + et4000->acl.mix_addr = et4000->acl.internal.mix_addr; + et4000->acl.mix_back = et4000->acl.mix_addr; + et4000->acl.dest_addr = et4000->acl.internal.dest_addr; + et4000->acl.dest_back = et4000->acl.dest_addr; + et4000->acl.internal.pos_x = et4000->acl.internal.pos_y = 0; + et4000->acl.pattern_x = et4000->acl.source_x = et4000->acl.pattern_y = et4000->acl.source_y = 0; + et4000->acl.status |= ACL_XYST; + if ((!(et4000->acl.internal.ctrl_routing & 7) || (et4000->acl.internal.ctrl_routing & 4)) && !(et4000->acl.internal.ctrl_routing & 0x40)) + et4000->acl.status |= ACL_SSO; + + if (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7]) + { + et4000->acl.pattern_x = et4000->acl.pattern_addr & et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7]; + et4000->acl.pattern_addr &= ~et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7]; + } + et4000->acl.pattern_back = et4000->acl.pattern_addr; + if (!(et4000->acl.internal.pattern_wrap & 0x40)) + { + et4000->acl.pattern_y = (et4000->acl.pattern_addr / (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1); + et4000->acl.pattern_back &= ~(((et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] + 1) * et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7]) - 1); + } + et4000->acl.pattern_x_back = et4000->acl.pattern_x; + + if (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7]) + { + et4000->acl.source_x = et4000->acl.source_addr & et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7]; + et4000->acl.source_addr &= ~et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7]; + } + et4000->acl.source_back = et4000->acl.source_addr; + if (!(et4000->acl.internal.source_wrap & 0x40)) + { + et4000->acl.source_y = (et4000->acl.source_addr / (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] + 1)) & (et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1); + et4000->acl.source_back &= ~(((et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] + 1) * et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7]) - 1); + } + et4000->acl.source_x_back = et4000->acl.source_x; + + et4000w32_max_x[2] = ((et4000->acl.internal.pixel_depth & 0x30) == 0x20) ? 3 : 4; + + et4000->acl.internal.count_x += (et4000->acl.internal.pixel_depth >> 4) & 3; + et4000->acl.cpu_dat_pos = 0; + et4000->acl.cpu_dat = 0; + + et4000->acl.pix_pos = 0; +} + +void et4000w32_incx(int c, et4000w32p_t *et4000) +{ + et4000->acl.dest_addr += c; + et4000->acl.pattern_x += c; + et4000->acl.source_x += c; + et4000->acl.mix_addr += c; + if (et4000->acl.pattern_x >= et4000w32_max_x[et4000->acl.internal.pattern_wrap & 7]) + et4000->acl.pattern_x -= et4000w32_max_x[et4000->acl.internal.pattern_wrap & 7]; + if (et4000->acl.source_x >= et4000w32_max_x[et4000->acl.internal.source_wrap & 7]) + et4000->acl.source_x -= et4000w32_max_x[et4000->acl.internal.source_wrap & 7]; +} +void et4000w32_decx(int c, et4000w32p_t *et4000) +{ + et4000->acl.dest_addr -= c; + et4000->acl.pattern_x -= c; + et4000->acl.source_x -= c; + et4000->acl.mix_addr -= c; + if (et4000->acl.pattern_x < 0) + et4000->acl.pattern_x += et4000w32_max_x[et4000->acl.internal.pattern_wrap & 7]; + if (et4000->acl.source_x < 0) + et4000->acl.source_x += et4000w32_max_x[et4000->acl.internal.source_wrap & 7]; +} +void et4000w32_incy(et4000w32p_t *et4000) +{ + et4000->acl.pattern_addr += et4000->acl.internal.pattern_off + 1; + et4000->acl.source_addr += et4000->acl.internal.source_off + 1; + et4000->acl.mix_addr += et4000->acl.internal.mix_off + 1; + et4000->acl.dest_addr += et4000->acl.internal.dest_off + 1; + et4000->acl.pattern_y++; + if (et4000->acl.pattern_y == et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7]) + { + et4000->acl.pattern_y = 0; + et4000->acl.pattern_addr = et4000->acl.pattern_back; + } + et4000->acl.source_y++; + if (et4000->acl.source_y == et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7]) + { + et4000->acl.source_y = 0; + et4000->acl.source_addr = et4000->acl.source_back; + } +} +void et4000w32_decy(et4000w32p_t *et4000) +{ + et4000->acl.pattern_addr -= et4000->acl.internal.pattern_off + 1; + et4000->acl.source_addr -= et4000->acl.internal.source_off + 1; + et4000->acl.mix_addr -= et4000->acl.internal.mix_off + 1; + et4000->acl.dest_addr -= et4000->acl.internal.dest_off + 1; + et4000->acl.pattern_y--; + if (et4000->acl.pattern_y < 0 && !(et4000->acl.internal.pattern_wrap & 0x40)) + { + et4000->acl.pattern_y = et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1; + et4000->acl.pattern_addr = et4000->acl.pattern_back + (et4000w32_wrap_x[et4000->acl.internal.pattern_wrap & 7] * (et4000w32_wrap_y[(et4000->acl.internal.pattern_wrap >> 4) & 7] - 1)); + } + et4000->acl.source_y--; + if (et4000->acl.source_y < 0 && !(et4000->acl.internal.source_wrap & 0x40)) + { + et4000->acl.source_y = et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1; + et4000->acl.source_addr = et4000->acl.source_back + (et4000w32_wrap_x[et4000->acl.internal.source_wrap & 7] *(et4000w32_wrap_y[(et4000->acl.internal.source_wrap >> 4) & 7] - 1));; + } +} + +void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input, et4000w32p_t *et4000) +{ + svga_t *svga = &et4000->svga; + int c,d; + uint8_t pattern, source, dest, out; + uint8_t rop; + int mixdat; + + if (!(et4000->acl.status & ACL_XYST)) return; +// if (count>400) pclog("New blit - %i,%i %06X (%i,%i) %06X %06X\n",et4000->acl.internal.count_x,et4000->acl.internal.count_y,et4000->acl.dest_addr,et4000->acl.dest_addr%640,et4000->acl.dest_addr/640,et4000->acl.source_addr,et4000->acl.pattern_addr); + //pclog("Blit exec - %i %i %i\n",count,et4000->acl.internal.pos_x,et4000->acl.internal.pos_y); + if (et4000->acl.internal.xy_dir & 0x80) /*Line draw*/ + { + while (count--) + { + if (bltout) pclog("%i,%i : ", et4000->acl.internal.pos_x, et4000->acl.internal.pos_y); + pattern = svga->vram[(et4000->acl.pattern_addr + et4000->acl.pattern_x) & 0x1fffff]; + source = svga->vram[(et4000->acl.source_addr + et4000->acl.source_x) & 0x1fffff]; + if (bltout) pclog("%06X %06X ", (et4000->acl.pattern_addr + et4000->acl.pattern_x) & 0x1fffff, (et4000->acl.source_addr + et4000->acl.source_x) & 0x1fffff); + if (cpu_input == 2) + { + source = sdat & 0xff; + sdat >>= 8; + } + dest = svga->vram[et4000->acl.dest_addr & 0x1fffff]; + out = 0; + if (bltout) pclog("%06X ", et4000->acl.dest_addr); + if ((et4000->acl.internal.ctrl_routing & 0xa) == 8) + { + mixdat = svga->vram[(et4000->acl.mix_addr >> 3) & 0x1fffff] & (1 << (et4000->acl.mix_addr & 7)); + if (bltout) pclog("%06X %02X ", et4000->acl.mix_addr, svga->vram[(et4000->acl.mix_addr >> 3) & 0x1fffff]); + } + else + { + mixdat = mix & 1; + mix >>= 1; + mix |= 0x80000000; + } + et4000->acl.mix_addr++; + rop = mixdat ? et4000->acl.internal.rop_fg : et4000->acl.internal.rop_bg; + for (c = 0; c < 8; c++) + { + d = (dest & (1 << c)) ? 1 : 0; + if (source & (1 << c)) d |= 2; + if (pattern & (1 << c)) d |= 4; + if (rop & (1 << d)) out |= (1 << c); + } + if (bltout) pclog("%06X = %02X\n", et4000->acl.dest_addr & 0x1fffff, out); + if (!(et4000->acl.internal.ctrl_routing & 0x40)) + { + svga->vram[et4000->acl.dest_addr & 0x1fffff] = out; + svga->changedvram[(et4000->acl.dest_addr & 0x1fffff) >> 12] = changeframecount; + } + else + { + et4000->acl.cpu_dat |= ((uint64_t)out << (et4000->acl.cpu_dat_pos * 8)); + et4000->acl.cpu_dat_pos++; + } + +// pclog("%i %i\n",et4000->acl.pix_pos,(et4000->acl.internal.pixel_depth>>4)&3); + et4000->acl.pix_pos++; + et4000->acl.internal.pos_x++; + if (et4000->acl.pix_pos <= ((et4000->acl.internal.pixel_depth >> 4) & 3)) + { + if (et4000->acl.internal.xy_dir & 1) et4000w32_decx(1, et4000); + else et4000w32_incx(1, et4000); + } + else + { + if (et4000->acl.internal.xy_dir & 1) + et4000w32_incx((et4000->acl.internal.pixel_depth >> 4) & 3, et4000); + else + et4000w32_decx((et4000->acl.internal.pixel_depth >> 4) & 3, et4000); + et4000->acl.pix_pos = 0; + /*Next pixel*/ + switch (et4000->acl.internal.xy_dir & 7) + { + case 0: case 1: /*Y+*/ + et4000w32_incy(et4000); + et4000->acl.internal.pos_y++; + et4000->acl.internal.pos_x -= ((et4000->acl.internal.pixel_depth >> 4) & 3) + 1; + break; + case 2: case 3: /*Y-*/ + et4000w32_decy(et4000); + et4000->acl.internal.pos_y++; + et4000->acl.internal.pos_x -= ((et4000->acl.internal.pixel_depth >> 4) & 3) + 1; + break; + case 4: case 6: /*X+*/ + et4000w32_incx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000); + //et4000->acl.internal.pos_x++; + break; + case 5: case 7: /*X-*/ + et4000w32_decx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000); + //et4000->acl.internal.pos_x++; + break; + } + et4000->acl.internal.error += et4000->acl.internal.dmin; + if (et4000->acl.internal.error > et4000->acl.internal.dmaj) + { + et4000->acl.internal.error -= et4000->acl.internal.dmaj; + switch (et4000->acl.internal.xy_dir & 7) + { + case 0: case 2: /*X+*/ + et4000w32_incx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000); + et4000->acl.internal.pos_x++; + break; + case 1: case 3: /*X-*/ + et4000w32_decx(((et4000->acl.internal.pixel_depth >> 4) & 3) + 1, et4000); + et4000->acl.internal.pos_x++; + break; + case 4: case 5: /*Y+*/ + et4000w32_incy(et4000); + et4000->acl.internal.pos_y++; + break; + case 6: case 7: /*Y-*/ + et4000w32_decy(et4000); + et4000->acl.internal.pos_y++; + break; + } + } + if (et4000->acl.internal.pos_x > et4000->acl.internal.count_x || + et4000->acl.internal.pos_y > et4000->acl.internal.count_y) + { + et4000->acl.status &= ~(ACL_XYST | ACL_SSO); +// pclog("Blit line over\n"); + return; + } + } + } + } + else + { + while (count--) + { + if (bltout) pclog("%i,%i : ", et4000->acl.internal.pos_x, et4000->acl.internal.pos_y); + + pattern = svga->vram[(et4000->acl.pattern_addr + et4000->acl.pattern_x) & 0x1fffff]; + source = svga->vram[(et4000->acl.source_addr + et4000->acl.source_x) & 0x1fffff]; + if (bltout) pclog("%i %06X %06X %02X %02X ", et4000->acl.pattern_y, (et4000->acl.pattern_addr + et4000->acl.pattern_x) & 0x1fffff, (et4000->acl.source_addr + et4000->acl.source_x) & 0x1fffff, pattern, source); + + if (cpu_input == 2) + { + source = sdat & 0xff; + sdat >>= 8; + } + dest = svga->vram[et4000->acl.dest_addr & 0x1fffff]; + out = 0; + if (bltout) pclog("%06X %02X %i %08X %08X ", dest, et4000->acl.dest_addr, mix & 1, mix, et4000->acl.mix_addr); + if ((et4000->acl.internal.ctrl_routing & 0xa) == 8) + { + mixdat = svga->vram[(et4000->acl.mix_addr >> 3) & 0x1fffff] & (1 << (et4000->acl.mix_addr & 7)); + if (bltout) pclog("%06X %02X ", et4000->acl.mix_addr, svga->vram[(et4000->acl.mix_addr >> 3) & 0x1fffff]); + } + else + { + mixdat = mix & 1; + mix >>= 1; + mix |= 0x80000000; + } + + rop = mixdat ? et4000->acl.internal.rop_fg : et4000->acl.internal.rop_bg; + for (c = 0; c < 8; c++) + { + d = (dest & (1 << c)) ? 1 : 0; + if (source & (1 << c)) d |= 2; + if (pattern & (1 << c)) d |= 4; + if (rop & (1 << d)) out |= (1 << c); + } + if (bltout) pclog("%06X = %02X\n", et4000->acl.dest_addr & 0x1fffff, out); + if (!(et4000->acl.internal.ctrl_routing & 0x40)) + { + svga->vram[et4000->acl.dest_addr & 0x1fffff] = out; + svga->changedvram[(et4000->acl.dest_addr & 0x1fffff) >> 12] = changeframecount; + } + else + { + et4000->acl.cpu_dat |= ((uint64_t)out << (et4000->acl.cpu_dat_pos * 8)); + et4000->acl.cpu_dat_pos++; + } + + if (et4000->acl.internal.xy_dir & 1) et4000w32_decx(1, et4000); + else et4000w32_incx(1, et4000); + + et4000->acl.internal.pos_x++; + if (et4000->acl.internal.pos_x > et4000->acl.internal.count_x) + { + if (et4000->acl.internal.xy_dir & 2) + { + et4000w32_decy(et4000); + et4000->acl.mix_back = et4000->acl.mix_addr = et4000->acl.mix_back - (et4000->acl.internal.mix_off + 1); + et4000->acl.dest_back = et4000->acl.dest_addr = et4000->acl.dest_back - (et4000->acl.internal.dest_off + 1); + } + else + { + et4000w32_incy(et4000); + et4000->acl.mix_back = et4000->acl.mix_addr = et4000->acl.mix_back + et4000->acl.internal.mix_off + 1; + et4000->acl.dest_back = et4000->acl.dest_addr = et4000->acl.dest_back + et4000->acl.internal.dest_off + 1; + } + + et4000->acl.pattern_x = et4000->acl.pattern_x_back; + et4000->acl.source_x = et4000->acl.source_x_back; + + et4000->acl.internal.pos_y++; + et4000->acl.internal.pos_x = 0; + if (et4000->acl.internal.pos_y > et4000->acl.internal.count_y) + { + et4000->acl.status &= ~(ACL_XYST | ACL_SSO); +// pclog("Blit over\n"); + return; + } + if (cpu_input) return; + if (et4000->acl.internal.ctrl_routing & 0x40) + { + if (et4000->acl.cpu_dat_pos & 3) + et4000->acl.cpu_dat_pos += 4 - (et4000->acl.cpu_dat_pos & 3); + return; + } + } + } + } +} + + +void et4000w32p_hwcursor_draw(svga_t *svga, int displine) +{ + int x, offset; + uint8_t dat; + offset = svga->hwcursor_latch.xoff; + int y_add = enable_overscan ? 16 : 0; + int x_add = enable_overscan ? 8 : 0; + for (x = 0; x < 64 - svga->hwcursor_latch.xoff; x += 4) + { + dat = svga->vram[svga->hwcursor_latch.addr + (offset >> 2)]; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 32 + x_add] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 32 + x_add] ^= 0xFFFFFF; + dat >>= 2; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 33 + x_add] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 33 + x_add] ^= 0xFFFFFF; + dat >>= 2; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 34 + x_add] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 34 + x_add] ^= 0xFFFFFF; + dat >>= 2; + if (!(dat & 2)) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 35 + x_add] = (dat & 1) ? 0xFFFFFF : 0; + else if ((dat & 3) == 3) ((uint32_t *)buffer32->line[displine + y_add])[svga->hwcursor_latch.x + x + 35 + x_add] ^= 0xFFFFFF; + dat >>= 2; + offset += 4; + } + svga->hwcursor_latch.addr += 16; +} + +static void et4000w32p_io_remove(et4000w32p_t *et4000) +{ + io_removehandler(0x03c0, 0x0020, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + + io_removehandler(0x210A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x211A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x212A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x213A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x214A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x215A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x216A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_removehandler(0x217A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); +} + +static void et4000w32p_io_set(et4000w32p_t *et4000) +{ + et4000w32p_io_remove(et4000); + + io_sethandler(0x03c0, 0x0020, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + + io_sethandler(0x210A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x211A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x212A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x213A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x214A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x215A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x216A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); + io_sethandler(0x217A, 0x0002, et4000w32p_in, NULL, NULL, et4000w32p_out, NULL, NULL, et4000); +} + +uint8_t et4000w32p_pci_read(int func, int addr, void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + svga_t *svga = &et4000->svga; + +// pclog("ET4000 PCI read %08X\n", addr); + + switch (addr) + { + case 0x00: return 0x0c; /*Tseng Labs*/ + case 0x01: return 0x10; + + case 0x02: return 0x06; /*ET4000W32p Rev D*/ + case 0x03: return 0x32; + + case PCI_REG_COMMAND: + return et4000->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/ + + case 0x07: return 1 << 1; /*Medium DEVSEL timing*/ + + case 0x08: return 0; /*Revision ID*/ + case 0x09: return 0; /*Programming interface*/ + + case 0x0a: return 0x01; /*Supports VGA interface, XGA compatible*/ + case 0x0b: return 0x03; + + case 0x10: return 0x00; /*Linear frame buffer address*/ + case 0x11: return 0x00; + case 0x12: return svga->crtc[0x5a] & 0x80; + case 0x13: return svga->crtc[0x59]; + + case 0x30: return et4000->pci_regs[0x30] & 0x01; /*BIOS ROM address*/ + case 0x31: return 0x00; + case 0x32: return et4000->pci_regs[0x32]; + case 0x33: return et4000->pci_regs[0x33]; + } + return 0; +} + +void et4000w32p_pci_write(int func, int addr, uint8_t val, void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + + switch (addr) + { + case PCI_REG_COMMAND: + if (romset == ROM_KN97) return; + et4000->pci_regs[PCI_REG_COMMAND] = val & 0x27; + if (val & PCI_COMMAND_IO) + et4000w32p_io_set(et4000); + else + et4000w32p_io_remove(et4000); + et4000w32p_recalcmapping(et4000); + break; + + case 0x13: + et4000->linearbase = val << 24; + et4000w32p_recalcmapping(et4000); + break; + + case 0x30: case 0x32: case 0x33: + et4000->pci_regs[addr] = val; + if (et4000->pci_regs[0x30] & 0x01) + { + uint32_t addr = (et4000->pci_regs[0x32] << 16) | (et4000->pci_regs[0x33] << 24); + // pclog("ET4000 bios_rom enabled at %08x\n", addr); + mem_mapping_set_addr(&et4000->bios_rom.mapping, addr, 0x8000); + } + else + { + // pclog("ET4000 bios_rom disabled\n"); + mem_mapping_disable(&et4000->bios_rom.mapping); + } + return; + } +} + +void *et4000w32p_common_init(char *biosfile) +{ + int vram_size; + int bios_offset = 0; + int checksum_diff = 0; + et4000w32p_t *et4000 = malloc(sizeof(et4000w32p_t)); + memset(et4000, 0, sizeof(et4000w32p_t)); + + vram_size = device_get_config_int("memory"); + et4000->vram_size = vram_size; + + et4000->revision = device_get_config_int("revision"); + + et4000->interleaved = (vram_size == 2) ? 1 : 0; + + et4000->max_ram_mask = (gfxcard == GFX_ET4000W32) ? 0x1fffff : 0x3fffff; + // et4000->max_ram_mask = 0x1fffff; + + svga_init(&et4000->svga, et4000, vram_size << 20, + et4000w32p_recalctimings, + et4000w32p_in, et4000w32p_out, + et4000w32p_hwcursor_draw, + NULL); + + rom_init(&et4000->bios_rom, biosfile, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + if (vram_size == 4) + { + /* The ROM is hardcoded to 256k sticks, so let's patch it for 1M. */ + if (memcmp(&((&et4000->bios_rom)->rom[0x008f]), "04/28/95 V2.10N", 15) == 0) + { + bios_offset = 0x0244; + } + if (memcmp(&((&et4000->bios_rom)->rom[0x008f]), "05/15/95 V8.00N", 15) == 0) + { + bios_offset = 0x027f; + } + if (bios_offset) + { + checksum_diff = (&et4000->bios_rom)->rom[bios_offset] - 0x03; + if (checksum_diff) + { + (&et4000->bios_rom)->rom[bios_offset] = 0x03; + (&et4000->bios_rom)->rom[0x7fff] += checksum_diff; + pclog("BIOS patched: %08X: %02X 03\n", bios_offset, checksum_diff + 0x03); + } + } + else + { + pclog("No known BIOS detected or BIOS already set to 1 MB DRAM modules, maximum VRAM is 2 MB\n"); + vram_size == 2; + } + } + if (PCI) + mem_mapping_disable(&et4000->bios_rom.mapping); + + mem_mapping_add(&et4000->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL, 0, &et4000->svga); + mem_mapping_add(&et4000->mmu_mapping, 0, 0, et4000w32p_mmu_read, NULL, NULL, et4000w32p_mmu_write, NULL, NULL, NULL, 0, et4000); + + et4000w32p_io_set(et4000); + + pci_add(et4000w32p_pci_read, et4000w32p_pci_write, et4000); + + et4000->pci_regs[0x04] = 7; + + et4000->pci_regs[0x30] = 0x00; + et4000->pci_regs[0x32] = 0x0c; + et4000->pci_regs[0x33] = 0x00; + + et4000->wake_fifo_thread = thread_create_event(); + et4000->fifo_not_full_event = thread_create_event(); + et4000->fifo_thread = thread_create(fifo_thread, et4000); + + return et4000; +} + +void *et4000w32p_init() +{ + return et4000w32p_common_init("roms/et4000w32.bin"); +} + +void *et4000w32pc_init() +{ + return et4000w32p_common_init("roms/cardex.vbi"); +} + +int et4000w32p_available() +{ + return rom_present("roms/et4000w32.bin"); +} + +int et4000w32pc_available() +{ + return rom_present("roms/cardex.vbi"); +} + +void et4000w32p_close(void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + + svga_close(&et4000->svga); + + free(et4000); +} + +void et4000w32p_speed_changed(void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + + svga_recalctimings(&et4000->svga); +} + +void et4000w32p_force_redraw(void *p) +{ + et4000w32p_t *et4000w32p = (et4000w32p_t *)p; + + et4000w32p->svga.fullchange = changeframecount; +} + +void et4000w32p_add_status_info(char *s, int max_len, void *p) +{ + et4000w32p_t *et4000 = (et4000w32p_t *)p; + char temps[256]; + uint64_t new_time = timer_read(); + uint64_t status_diff = new_time - et4000->status_time; + et4000->status_time = new_time; + + svga_add_status_info(s, max_len, &et4000->svga); + + sprintf(temps, "%f%% CPU\n%f%% CPU (real)\n\n", ((double)et4000->blitter_time * 100.0) / timer_freq, ((double)et4000->blitter_time * 100.0) / status_diff); + strncat(s, temps, max_len); + + et4000->blitter_time = 0; +} + +static device_config_t et4000w32p_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "" + } + }, + .default_int = 2 + }, + { + .name = "revision", + .description = "Revision", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "Rev. A", + .value = 2 + }, + { + .description = "Rev. B", + .value = 5 + }, + { + .description = "Rev. D", + .value = 6 + }, + { + .description = "Rev. C", + .value = 7 + }, + { + .description = "" + } + }, + .default_int = 6 + }, + { + .type = -1 + } +}; + +static device_config_t et4000w32pc_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } + }, + .default_int = 2 + }, + { + .name = "revision", + .description = "Revision", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "Rev. A", + .value = 2 + }, + { + .description = "Rev. B", + .value = 5 + }, + { + .description = "Rev. D", + .value = 6 + }, + { + .description = "Rev. C", + .value = 7 + }, + { + .description = "" + } + }, + .default_int = 6 + }, + { + .type = -1 + } +}; + +device_t et4000w32p_device = +{ + "Tseng Labs ET4000/w32p", + 0, + et4000w32p_init, + et4000w32p_close, + et4000w32p_available, + et4000w32p_speed_changed, + et4000w32p_force_redraw, + et4000w32p_add_status_info, + et4000w32p_config +}; + +device_t et4000w32pc_device = +{ + "Cardex Tseng Labs ET4000/w32p", + 0, + et4000w32pc_init, + et4000w32p_close, + et4000w32pc_available, + et4000w32p_speed_changed, + et4000w32p_force_redraw, + et4000w32p_add_status_info, + et4000w32pc_config +}; diff --git a/src/vid_et4000w32.h b/src/vid_et4000w32.h new file mode 100644 index 000000000..1b91ff09d --- /dev/null +++ b/src/vid_et4000w32.h @@ -0,0 +1,2 @@ +extern device_t et4000w32p_device; +extern device_t et4000w32pc_device; diff --git a/src/vid_et4000w32i.c b/src/vid_et4000w32i.c new file mode 100644 index 000000000..5aec84b1f --- /dev/null +++ b/src/vid_et4000w32i.c @@ -0,0 +1,407 @@ +/*The below is (with some removals) a reasonable emulation of the ET4000/W32i blitter. + Unfortunately the Diamond Stealth 32 is actually an ET4000/W32p! Which has a different + blitter. If only I'd dug out and looked at the card before trying to emulate it. + + This might be of use for an attempt at emulating an ET4000/W32i. + */ +#if 0 + +#include "ibm.h" + +int et4k_b8000; + +struct +{ + struct + { + uint32_t pattern_addr,source_addr,dest_addr; + uint16_t pattern_off,source_off,dest_off; + uint8_t vbus,xy_dir; + uint8_t pattern_wrap,source_wrap; + uint16_t count_x,count_y; + uint8_t ctrl_routing,ctrl_reload; + uint8_t rop_fg,rop_bg; + uint16_t pos_x,pos_y; + } queued,internal; + uint32_t pattern_addr,source_addr,dest_addr; + uint32_t pattern_back,dest_back; + int pattern_x,source_x; + int pattern_x_back; + int pattern_y,source_y; + uint8_t status; + uint32_t cpu_input; + int cpu_input_num; +} acl; + +#define ACL_WRST 1 +#define ACL_RDST 2 +#define ACL_XYST 4 +#define ACL_SSO 8 + +struct +{ + uint32_t base[3]; + uint8_t ctrl; +} mmu; + +void et4000w32_reset() +{ + acl.status=0; + acl.cpu_input_num=0; +} + +void et4000w32_blit_start(); +void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input); + +int et4000w32_vbus[4]={1,2,4,4}; + +void et4000w32_mmu_write(uint32_t addr, uint8_t val) +{ + int bank; + pclog("ET4K write %08X %02X %i %02X %02X %04X(%08X):%08X %04X %04X %02X %08X\n",addr,val,acl.cpu_input_num,acl.status,acl.internal.ctrl_routing,CS,cs,pc,CS,DI,mmu.ctrl,mmu.base[2]); + switch (addr&0x6000) + { + case 0x0000: /*MMU 0*/ + case 0x2000: /*MMU 1*/ + case 0x4000: /*MMU 2*/ + bank=(addr>>13)&3; + if (mmu.ctrl&(1<>12]=changeframecount; + } + break; + case 0x6000: + switch (addr&0x7FFF) + { + case 0x7F00: mmu.base[0]=(mmu.base[0]&0xFFFFFF00)|val; break; + case 0x7F01: mmu.base[0]=(mmu.base[0]&0xFFFF00FF)|(val<<8); break; + case 0x7F02: mmu.base[0]=(mmu.base[0]&0xFF00FFFF)|(val<<16); break; + case 0x7F03: mmu.base[0]=(mmu.base[0]&0x00FFFFFF)|(val<<24); break; + case 0x7F04: mmu.base[1]=(mmu.base[1]&0xFFFFFF00)|val; break; + case 0x7F05: mmu.base[1]=(mmu.base[1]&0xFFFF00FF)|(val<<8); break; + case 0x7F06: mmu.base[1]=(mmu.base[1]&0xFF00FFFF)|(val<<16); break; + case 0x7F07: mmu.base[1]=(mmu.base[1]&0x00FFFFFF)|(val<<24); break; + case 0x7F08: mmu.base[2]=(mmu.base[2]&0xFFFFFF00)|val; break; + case 0x7F09: mmu.base[2]=(mmu.base[2]&0xFFFF00FF)|(val<<8); break; + case 0x7F0A: mmu.base[2]=(mmu.base[2]&0xFF00FFFF)|(val<<16); break; + case 0x7F0B: mmu.base[2]=(mmu.base[2]&0x00FFFFFF)|(val<<24); break; + case 0x7F13: mmu.ctrl=val; break; + + case 0x7F80: acl.queued.pattern_addr=(acl.queued.pattern_addr&0xFFFFFF00)|val; break; + case 0x7F81: acl.queued.pattern_addr=(acl.queued.pattern_addr&0xFFFF00FF)|(val<<8); break; + case 0x7F82: acl.queued.pattern_addr=(acl.queued.pattern_addr&0xFF00FFFF)|(val<<16); break; + case 0x7F83: acl.queued.pattern_addr=(acl.queued.pattern_addr&0x00FFFFFF)|(val<<24); break; + case 0x7F84: acl.queued.source_addr =(acl.queued.source_addr &0xFFFFFF00)|val; break; + case 0x7F85: acl.queued.source_addr =(acl.queued.source_addr &0xFFFF00FF)|(val<<8); break; + case 0x7F86: acl.queued.source_addr =(acl.queued.source_addr &0xFF00FFFF)|(val<<16); break; + case 0x7F87: acl.queued.source_addr =(acl.queued.source_addr &0x00FFFFFF)|(val<<24); break; + case 0x7F88: acl.queued.pattern_off=(acl.queued.pattern_off&0xFF00)|val; break; + case 0x7F89: acl.queued.pattern_off=(acl.queued.pattern_off&0x00FF)|(val<<8); break; + case 0x7F8A: acl.queued.source_off =(acl.queued.source_off &0xFF00)|val; break; + case 0x7F8B: acl.queued.source_off =(acl.queued.source_off &0x00FF)|(val<<8); break; + case 0x7F8C: acl.queued.dest_off =(acl.queued.dest_off &0xFF00)|val; break; + case 0x7F8D: acl.queued.dest_off =(acl.queued.dest_off &0x00FF)|(val<<8); break; + case 0x7F8E: acl.queued.vbus=val; break; + case 0x7F8F: acl.queued.xy_dir=val; break; + case 0x7F90: acl.queued.pattern_wrap=val; break; + case 0x7F92: acl.queued.source_wrap=val; break; + case 0x7F98: acl.queued.count_x =(acl.queued.count_x &0xFF00)|val; break; + case 0x7F99: acl.queued.count_x =(acl.queued.count_x &0x00FF)|(val<<8); break; + case 0x7F9A: acl.queued.count_y =(acl.queued.count_y &0xFF00)|val; break; + case 0x7F9B: acl.queued.count_y =(acl.queued.count_y &0x00FF)|(val<<8); break; + case 0x7F9C: acl.queued.ctrl_routing=val; break; + case 0x7F9D: acl.queued.ctrl_reload =val; break; + case 0x7F9E: acl.queued.rop_bg =val; break; + case 0x7F9F: acl.queued.rop_fg =val; break; + case 0x7FA0: acl.queued.dest_addr =(acl.queued.dest_addr &0xFFFFFF00)|val; break; + case 0x7FA1: acl.queued.dest_addr =(acl.queued.dest_addr &0xFFFF00FF)|(val<<8); break; + case 0x7FA2: acl.queued.dest_addr =(acl.queued.dest_addr &0xFF00FFFF)|(val<<16); break; + case 0x7FA3: acl.queued.dest_addr =(acl.queued.dest_addr &0x00FFFFFF)|(val<<24); + acl.internal=acl.queued; + et4000w32_blit_start(); + acl.cpu_input_num=0; + if (!(acl.queued.ctrl_routing&0x37)) + { + et4000w32_blit(0xFFFFFF, ~0, 0, 0); + } + break; + } + break; + } +} + +uint8_t et4000w32_mmu_read(uint32_t addr) +{ + int bank; + pclog("ET4K read %08X %04X(%08X):%08X\n",addr,CS,cs,pc); + switch (addr&0x6000) + { + case 0x0000: /*MMU 0*/ + case 0x2000: /*MMU 1*/ + case 0x4000: /*MMU 2*/ + bank=(addr>>13)&3; + if (mmu.ctrl&(1<>8; + case 0x7F02: return mmu.base[0]>>16; + case 0x7F03: return mmu.base[0]>>24; + case 0x7F04: return mmu.base[1]; + case 0x7F05: return mmu.base[1]>>8; + case 0x7F06: return mmu.base[1]>>16; + case 0x7F07: return mmu.base[1]>>24; + case 0x7F08: return mmu.base[2]; + case 0x7F09: return mmu.base[2]>>8; + case 0x7F0A: return mmu.base[2]>>16; + case 0x7F0B: return mmu.base[2]>>24; + case 0x7F13: return mmu.ctrl; + + case 0x7F36: +// if (acl.internal.pos_x!=acl.internal.count_x || acl.internal.pos_y!=acl.internal.count_y) return acl.status | ACL_XYST; + return acl.status & ~(ACL_XYST | ACL_SSO); + case 0x7F80: return acl.internal.pattern_addr; + case 0x7F81: return acl.internal.pattern_addr>>8; + case 0x7F82: return acl.internal.pattern_addr>>16; + case 0x7F83: return acl.internal.pattern_addr>>24; + case 0x7F84: return acl.internal.source_addr; + case 0x7F85: return acl.internal.source_addr>>8; + case 0x7F86: return acl.internal.source_addr>>16; + case 0x7F87: return acl.internal.source_addr>>24; + case 0x7F88: return acl.internal.pattern_off; + case 0x7F89: return acl.internal.pattern_off>>8; + case 0x7F8A: return acl.internal.source_off; + case 0x7F8B: return acl.internal.source_off>>8; + case 0x7F8C: return acl.internal.dest_off; + case 0x7F8D: return acl.internal.dest_off>>8; + case 0x7F8E: return acl.internal.vbus; + case 0x7F8F: return acl.internal.xy_dir; + case 0x7F90: return acl.internal.pattern_wrap; + case 0x7F92: return acl.internal.source_wrap; + case 0x7F98: return acl.internal.count_x; + case 0x7F99: return acl.internal.count_x>>8; + case 0x7F9A: return acl.internal.count_y; + case 0x7F9B: return acl.internal.count_y>>8; + case 0x7F9C: return acl.internal.ctrl_routing; + case 0x7F9D: return acl.internal.ctrl_reload; + case 0x7F9E: return acl.internal.rop_bg; + case 0x7F9F: return acl.internal.rop_fg; + case 0x7FA0: return acl.internal.dest_addr; + case 0x7FA1: return acl.internal.dest_addr>>8; + case 0x7FA2: return acl.internal.dest_addr>>16; + case 0x7FA3: return acl.internal.dest_addr>>24; + } + return 0xFF; + } +} + +int et4000w32_wrap_x[8]={0,0,3,7,15,31,63,0xFFFFFFFF}; +int et4000w32_wrap_y[8]={1,2,4,8,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF}; + +void et4000w32_blit_start() +{ + pclog("Blit - %08X %08X %08X (%i,%i) %i %i %i %02X %02X %02X\n",acl.internal.pattern_addr,acl.internal.source_addr,acl.internal.dest_addr,acl.internal.dest_addr%640,acl.internal.dest_addr/640,acl.internal.xy_dir,acl.internal.count_x,acl.internal.count_y,acl.internal.rop_fg,acl.internal.rop_bg, acl.internal.ctrl_routing); + acl.pattern_addr=acl.internal.pattern_addr; + acl.source_addr =acl.internal.source_addr; + acl.dest_addr =acl.internal.dest_addr; + acl.dest_back =acl.dest_addr; + acl.internal.pos_x=acl.internal.pos_y=0; + acl.pattern_x=acl.source_x=acl.pattern_y=acl.source_y=0; + acl.status = ACL_XYST; + if (!(acl.internal.ctrl_routing&7) || (acl.internal.ctrl_routing&4)) acl.status |= ACL_SSO; + if (et4000w32_wrap_x[acl.internal.pattern_wrap&7]) + { + acl.pattern_x=acl.pattern_addr&et4000w32_wrap_x[acl.internal.pattern_wrap&7]; + acl.pattern_addr&=~et4000w32_wrap_x[acl.internal.pattern_wrap&7]; + } + if (!(acl.internal.pattern_wrap&0x80)) + { + acl.pattern_y=(acl.pattern_addr/(et4000w32_wrap_x[acl.internal.pattern_wrap&7]+1))&(et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7]-1); + acl.pattern_addr&=~(((et4000w32_wrap_x[acl.internal.pattern_wrap&7]+1)*et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7])-1); + } + acl.pattern_x_back=acl.pattern_x; + acl.pattern_back=acl.pattern_addr; +} + +void et4000w32_blit(int count, uint32_t mix, uint32_t sdat, int cpu_input) +{ + int c,d; + uint8_t pattern,source,dest,out; + uint8_t rop; + +// if (count>400) pclog("New blit - %i,%i %06X (%i,%i) %06X %06X\n",acl.internal.count_x,acl.internal.count_y,acl.dest_addr,acl.dest_addr%640,acl.dest_addr/640,acl.source_addr,acl.pattern_addr); +// pclog("Blit exec - %i %i %i\n",count,acl.internal.pos_x,acl.internal.pos_y); + while (count--) + { + pclog("%i,%i : ",acl.internal.pos_x,acl.internal.pos_y); + if (acl.internal.xy_dir&1) + { + pattern=vram[(acl.pattern_addr-acl.pattern_x)&0x1FFFFF]; + source =vram[(acl.source_addr -acl.source_x) &0x1FFFFF]; + pclog("%06X %06X ",(acl.pattern_addr-acl.pattern_x)&0x1FFFFF,(acl.source_addr -acl.source_x) &0x1FFFFF); + } + else + { + pattern=vram[(acl.pattern_addr+acl.pattern_x)&0x1FFFFF]; + source =vram[(acl.source_addr +acl.source_x) &0x1FFFFF]; + pclog("%06X %06X ",(acl.pattern_addr+acl.pattern_x)&0x1FFFFF,(acl.source_addr +acl.source_x) &0x1FFFFF); + } + if (cpu_input==2) + { + source=sdat&0xFF; + sdat>>=8; + } + dest=vram[acl.dest_addr &0x1FFFFF]; + out=0; + pclog("%06X %i %08X ",acl.dest_addr,mix&1,mix); + rop = (mix & 1) ? acl.internal.rop_fg:acl.internal.rop_bg; + mix>>=1; mix|=0x80000000; + for (c=0;c<8;c++) + { + d=(dest & (1<>12]=changeframecount; + + acl.pattern_x++; + acl.pattern_x&=et4000w32_wrap_x[acl.internal.pattern_wrap&7]; + acl.source_x++; + acl.source_x &=et4000w32_wrap_x[acl.internal.source_wrap&7]; + if (acl.internal.xy_dir&1) acl.dest_addr--; + else acl.dest_addr++; + + acl.internal.pos_x++; + if (acl.internal.pos_x>acl.internal.count_x) + { + if (acl.internal.xy_dir&2) + { + acl.pattern_addr-=(acl.internal.pattern_off+1); + acl.source_addr -=(acl.internal.source_off +1); + acl.dest_back=acl.dest_addr=acl.dest_back-(acl.internal.dest_off+1); + } + else + { + acl.pattern_addr+=acl.internal.pattern_off+1; + acl.source_addr +=acl.internal.source_off +1; + acl.dest_back=acl.dest_addr=acl.dest_back+acl.internal.dest_off+1; + } + acl.pattern_x = acl.pattern_x_back; + acl.source_x = 0; + acl.pattern_y++; + if (acl.pattern_y==et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7]) + { + acl.pattern_y=0; + acl.pattern_addr=acl.pattern_back; + } + acl.source_y++; + if (acl.source_y ==et4000w32_wrap_y[(acl.internal.source_wrap >>4)&7]) + { + acl.source_y=0; + acl.source_addr=acl.internal.source_addr; + } + + acl.internal.pos_y++; + if (acl.internal.pos_y>acl.internal.count_y) + { + acl.status = 0; + return; + } + acl.internal.pos_x=0; + if (cpu_input) return; + } + } +} + +/* for (y=0;y<=acl.internal.count_y;y++) + { + dest_back=acl.dest_addr; + for (x=0;x<=acl.internal.count_x;x++) + { + if (acl.internal.xy_dir&1) + { + pattern=vram[(acl.pattern_addr-pattern_x)&0x1FFFFF]; + source =vram[(acl.source_addr -source_x) &0x1FFFFF]; + } + else + { + pattern=vram[(acl.pattern_addr+pattern_x)&0x1FFFFF]; + source =vram[(acl.source_addr +source_x) &0x1FFFFF]; + } + dest=vram[acl.dest_addr &0x1FFFFF]; + out=0; + for (c=0;c<8;c++) + { + d=(dest&(1<>12]=changeframecount; + + pattern_x++; + pattern_x&=et4000w32_wrap_x[acl.internal.pattern_wrap&7]; + source_x++; + source_x &=et4000w32_wrap_x[acl.internal.source_wrap&7]; + if (acl.internal.xy_dir&1) acl.dest_addr--; + else acl.dest_addr++; + } + acl.pattern_addr+=acl.internal.pattern_off+1; + acl.source_addr +=acl.internal.source_off+1; + acl.dest_addr=dest_back+acl.internal.dest_off+1; + pattern_y++; + if (pattern_y==et4000w32_wrap_y[(acl.internal.pattern_wrap>>4)&7]) + { + pattern_y=0; + acl.pattern_addr=acl.internal.pattern_addr; + } + source_y++; + if (source_y ==et4000w32_wrap_y[(acl.internal.source_wrap >>4)&7]) + { + source_y=0; + acl.source_addr=acl.internal.source_addr; + } + }*/ + +#endif diff --git a/src/vid_hercules.c b/src/vid_hercules.c new file mode 100644 index 000000000..c834f55bb --- /dev/null +++ b/src/vid_hercules.c @@ -0,0 +1,371 @@ +/*Hercules emulation*/ +#include +#include "ibm.h" +#include "device.h" +#include "mem.h" +#include "timer.h" +#include "video.h" +#include "vid_hercules.h" + +typedef struct hercules_t +{ + mem_mapping_t mapping; + + uint8_t crtc[32]; + int crtcreg; + + uint8_t ctrl, ctrl2, stat; + + int dispontime, dispofftime; + int vidtime; + + int firstline, lastline; + + int linepos, displine; + int vc, sc; + uint16_t ma, maback; + int con, coff, cursoron; + int dispon, blink; + int vsynctime, vadj; + + uint8_t *vram; +} hercules_t; + +static int mdacols[256][2][2]; + +void hercules_recalctimings(hercules_t *hercules); +void hercules_write(uint32_t addr, uint8_t val, void *p); +uint8_t hercules_read(uint32_t addr, void *p); + + +void hercules_out(uint16_t addr, uint8_t val, void *p) +{ + hercules_t *hercules = (hercules_t *)p; +// pclog("Herc out %04X %02X\n",addr,val); + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + hercules->crtcreg = val & 31; + return; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + hercules->crtc[hercules->crtcreg] = val; + if (hercules->crtc[10] == 6 && hercules->crtc[11] == 7) /*Fix for Generic Turbo XT BIOS, which sets up cursor registers wrong*/ + { + hercules->crtc[10] = 0xb; + hercules->crtc[11] = 0xc; + } + hercules_recalctimings(hercules); + return; + case 0x3b8: + hercules->ctrl = val; + return; + case 0x3bf: + hercules->ctrl2 = val; + if (val & 2) + mem_mapping_set_addr(&hercules->mapping, 0xb0000, 0x10000); + else + mem_mapping_set_addr(&hercules->mapping, 0xb0000, 0x08000); + return; + } +} + +uint8_t hercules_in(uint16_t addr, void *p) +{ + hercules_t *hercules = (hercules_t *)p; + // pclog("Herc in %04X %02X %04X:%04X %04X\n",addr,(hercules_stat & 0xF) | ((hercules_stat & 8) << 4),CS,pc,CX); + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + return hercules->crtcreg; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + return hercules->crtc[hercules->crtcreg]; + case 0x3ba: + return (hercules->stat & 0xf) | ((hercules->stat & 8) << 4); + } + return 0xff; +} + +void hercules_write(uint32_t addr, uint8_t val, void *p) +{ + hercules_t *hercules = (hercules_t *)p; + egawrites++; + /* Horrible hack, I know, but it's the only way to fix the 440FX BIOS filling the VRAM with garbage until Tom fixes the memory emulation. */ + if ((cs == 0xE0000) && (cpu_state.pc == 0xBF2F) && (romset == ROM_440FX)) return; + if ((cs == 0xE0000) && (cpu_state.pc == 0xBF77) && (romset == ROM_440FX)) return; +// pclog("Herc write %08X %02X\n",addr,val); + hercules->vram[addr & 0xffff] = val; +} + +uint8_t hercules_read(uint32_t addr, void *p) +{ + hercules_t *hercules = (hercules_t *)p; + egareads++; + return hercules->vram[addr & 0xffff]; +} + +void hercules_recalctimings(hercules_t *hercules) +{ + double disptime; + double _dispontime, _dispofftime; + disptime = hercules->crtc[0] + 1; + _dispontime = hercules->crtc[1]; + _dispofftime = disptime - _dispontime; + _dispontime *= MDACONST; + _dispofftime *= MDACONST; + hercules->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + hercules->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + +void hercules_poll(void *p) +{ + hercules_t *hercules = (hercules_t *)p; + uint16_t ca = (hercules->crtc[15] | (hercules->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + uint16_t dat; + int cols[4]; + int oldsc; + int blink; + if (!hercules->linepos) + { + //pclog("Poll %i %i\n",vc,sc); + hercules->vidtime += hercules->dispofftime; + hercules->stat |= 1; + hercules->linepos = 1; + oldsc = hercules->sc; + if ((hercules->crtc[8] & 3) == 3) + hercules->sc = (hercules->sc << 1) & 7; + if (hercules->dispon) + { + if (hercules->displine < hercules->firstline) + { + hercules->firstline = hercules->displine; + } + hercules->lastline = hercules->displine; + cols[0] = 0; + cols[1] = 7; + if ((hercules->ctrl & 2) && (hercules->ctrl2 & 1)) + { + ca = (hercules->sc & 3) * 0x2000; + if ((hercules->ctrl & 0x80) && (hercules->ctrl2 & 2)) + ca += 0x8000; +// printf("Draw herc %04X\n",ca); + for (x = 0; x < hercules->crtc[1]; x++) + { + dat = (hercules->vram[((hercules->ma << 1) & 0x1fff) + ca] << 8) | hercules->vram[((hercules->ma << 1) & 0x1fff) + ca + 1]; + hercules->ma++; + for (c = 0; c < 16; c++) + buffer->line[hercules->displine][(x << 4) + c] = (dat & (32768 >> c)) ? 7 : 0; + } + } + else + { + for (x = 0; x < hercules->crtc[1]; x++) + { + chr = hercules->vram[(hercules->ma << 1) & 0x3fff]; + attr = hercules->vram[((hercules->ma << 1) + 1) & 0x3fff]; + drawcursor = ((hercules->ma == ca) && hercules->con && hercules->cursoron); + blink = ((hercules->blink & 16) && (hercules->ctrl & 0x20) && (attr & 0x80) && !drawcursor); + if (hercules->sc == 12 && ((attr & 7) == 1)) + { + for (c = 0; c < 9; c++) + buffer->line[hercules->displine][(x * 9) + c] = mdacols[attr][blink][1]; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[hercules->displine][(x * 9) + c] = mdacols[attr][blink][(fontdatm[chr][hercules->sc] & (1 << (c ^ 7))) ? 1 : 0]; + if ((chr & ~0x1f) == 0xc0) buffer->line[hercules->displine][(x * 9) + 8] = mdacols[attr][blink][fontdatm[chr][hercules->sc] & 1]; + else buffer->line[hercules->displine][(x * 9) + 8] = mdacols[attr][blink][0]; + } + hercules->ma++; + if (drawcursor) + { + for (c = 0; c < 9; c++) + buffer->line[hercules->displine][(x * 9) + c] ^= mdacols[attr][0][1]; + } + } + } + } + hercules->sc = oldsc; + if (hercules->vc == hercules->crtc[7] && !hercules->sc) + { + hercules->stat |= 8; +// printf("VSYNC on %i %i\n",vc,sc); + } + hercules->displine++; + if (hercules->displine >= 500) + hercules->displine = 0; + } + else + { + hercules->vidtime += hercules->dispontime; + if (hercules->dispon) + hercules->stat &= ~1; + hercules->linepos = 0; + if (hercules->vsynctime) + { + hercules->vsynctime--; + if (!hercules->vsynctime) + { + hercules->stat &= ~8; +// printf("VSYNC off %i %i\n",vc,sc); + } + } + if (hercules->sc == (hercules->crtc[11] & 31) || ((hercules->crtc[8] & 3) == 3 && hercules->sc == ((hercules->crtc[11] & 31) >> 1))) + { + hercules->con = 0; + hercules->coff = 1; + } + if (hercules->vadj) + { + hercules->sc++; + hercules->sc &= 31; + hercules->ma = hercules->maback; + hercules->vadj--; + if (!hercules->vadj) + { + hercules->dispon = 1; + hercules->ma = hercules->maback = (hercules->crtc[13] | (hercules->crtc[12] << 8)) & 0x3fff; + hercules->sc = 0; + } + } + else if (hercules->sc == hercules->crtc[9] || ((hercules->crtc[8] & 3) == 3 && hercules->sc == (hercules->crtc[9] >> 1))) + { + hercules->maback = hercules->ma; + hercules->sc = 0; + oldvc = hercules->vc; + hercules->vc++; + hercules->vc &= 127; + if (hercules->vc == hercules->crtc[6]) + hercules->dispon = 0; + if (oldvc == hercules->crtc[4]) + { +// printf("Display over at %i\n",displine); + hercules->vc = 0; + hercules->vadj = hercules->crtc[5]; + if (!hercules->vadj) hercules->dispon=1; + if (!hercules->vadj) hercules->ma = hercules->maback = (hercules->crtc[13] | (hercules->crtc[12] << 8)) & 0x3fff; + if ((hercules->crtc[10] & 0x60) == 0x20) hercules->cursoron = 0; + else hercules->cursoron = hercules->blink & 16; + } + if (hercules->vc == hercules->crtc[7]) + { + hercules->dispon = 0; + hercules->displine = 0; + hercules->vsynctime = 16;//(crtcm[3]>>4)+1; + if (hercules->crtc[7]) + { +// printf("Lastline %i Firstline %i %i\n",lastline,firstline,lastline-firstline); + if ((hercules->ctrl & 2) && (hercules->ctrl2 & 1)) x = hercules->crtc[1] << 4; + else x = hercules->crtc[1] * 9; + hercules->lastline++; + if (x != xsize || (hercules->lastline - hercules->firstline) != ysize) + { + xsize = x; + ysize = hercules->lastline - hercules->firstline; +// printf("Resize to %i,%i - R1 %i\n",xsize,ysize,crtcm[1]); + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + updatewindowsize(xsize, ysize); + } + startblit(); + video_blit_memtoscreen_8(0, hercules->firstline, xsize, ysize); + endblit(); + frames++; + if ((hercules->ctrl & 2) && (hercules->ctrl2 & 1)) + { + video_res_x = hercules->crtc[1] * 16; + video_res_y = hercules->crtc[6] * 4; + video_bpp = 1; + } + else + { + video_res_x = hercules->crtc[1]; + video_res_y = hercules->crtc[6]; + video_bpp = 0; + } + } + hercules->firstline = 1000; + hercules->lastline = 0; + hercules->blink++; + } + } + else + { + hercules->sc++; + hercules->sc &= 31; + hercules->ma = hercules->maback; + } + if ((hercules->sc == (hercules->crtc[10] & 31) || ((hercules->crtc[8] & 3) == 3 && hercules->sc == ((hercules->crtc[10] & 31) >> 1)))) + { + hercules->con = 1; +// printf("Cursor on - %02X %02X %02X\n",crtcm[8],crtcm[10],crtcm[11]); + } + } +} + +void *hercules_init() +{ + int c; + hercules_t *hercules = malloc(sizeof(hercules_t)); + memset(hercules, 0, sizeof(hercules_t)); + + hercules->vram = malloc(0x10000); + + timer_add(hercules_poll, &hercules->vidtime, TIMER_ALWAYS_ENABLED, hercules); + mem_mapping_add(&hercules->mapping, 0xb0000, 0x08000, hercules_read, NULL, NULL, hercules_write, NULL, NULL, NULL, 0, hercules); + io_sethandler(0x03b0, 0x0010, hercules_in, NULL, NULL, hercules_out, NULL, NULL, hercules); + + for (c = 0; c < 256; c++) + { + mdacols[c][0][0] = mdacols[c][1][0] = mdacols[c][1][1] = 16; + if (c & 8) mdacols[c][0][1] = 15 + 16; + else mdacols[c][0][1] = 7 + 16; + } + mdacols[0x70][0][1] = 16; + mdacols[0x70][0][0] = mdacols[0x70][1][0] = mdacols[0x70][1][1] = 16 + 15; + mdacols[0xF0][0][1] = 16; + mdacols[0xF0][0][0] = mdacols[0xF0][1][0] = mdacols[0xF0][1][1] = 16 + 15; + mdacols[0x78][0][1] = 16 + 7; + mdacols[0x78][0][0] = mdacols[0x78][1][0] = mdacols[0x78][1][1] = 16 + 15; + mdacols[0xF8][0][1] = 16 + 7; + mdacols[0xF8][0][0] = mdacols[0xF8][1][0] = mdacols[0xF8][1][1] = 16 + 15; + mdacols[0x00][0][1] = mdacols[0x00][1][1] = 16; + mdacols[0x08][0][1] = mdacols[0x08][1][1] = 16; + mdacols[0x80][0][1] = mdacols[0x80][1][1] = 16; + mdacols[0x88][0][1] = mdacols[0x88][1][1] = 16; + + overscan_x = overscan_y = 0; + + return hercules; +} + +void hercules_close(void *p) +{ + hercules_t *hercules = (hercules_t *)p; + + free(hercules->vram); + free(hercules); +} + +void hercules_speed_changed(void *p) +{ + hercules_t *hercules = (hercules_t *)p; + + hercules_recalctimings(hercules); +} + +device_t hercules_device = +{ + "Hercules", + 0, + hercules_init, + hercules_close, + NULL, + hercules_speed_changed, + NULL, + NULL +}; diff --git a/src/vid_hercules.h b/src/vid_hercules.h new file mode 100644 index 000000000..93b222bc2 --- /dev/null +++ b/src/vid_hercules.h @@ -0,0 +1 @@ +extern device_t hercules_device; diff --git a/src/vid_icd2061.c b/src/vid_icd2061.c new file mode 100644 index 000000000..8dc254ec2 --- /dev/null +++ b/src/vid_icd2061.c @@ -0,0 +1,66 @@ +/*PCem v8.1 by Tom Walker + + ICD2061 clock generator emulation + Used by ET4000w32/p (Diamond Stealth 32)*/ +#include "ibm.h" +#include "vid_icd2061.h" + +void icd2061_write(icd2061_t *icd2061, int val) +{ + int q, p, m, i, a; + if ((val & 1) && !(icd2061->state & 1)) + { + pclog("ICD2061 write %02X %i %08X %i\n", val, icd2061->unlock, icd2061->data, icd2061->pos); + if (!icd2061->status) + { + if (val & 2) + icd2061->unlock++; + else + { + if (icd2061->unlock >= 5) + { + icd2061->status = 1; + icd2061->pos = 0; + } + else + icd2061->unlock = 0; + } + } + else if (val & 1) + { + icd2061->data = (icd2061->data >> 1) | (((val & 2) ? 1 : 0) << 24); + icd2061->pos++; + if (icd2061->pos == 26) + { + pclog("ICD2061 data - %08X\n", icd2061->data); + a = (icd2061->data >> 21) & 0x7; + if (!(a & 4)) + { + q = (icd2061->data & 0x7f) - 2; + m = 1 << ((icd2061->data >> 7) & 0x7); + p = ((icd2061->data >> 10) & 0x7f) - 3; + i = (icd2061->data >> 17) & 0xf; + pclog("p %i q %i m %i\n", p, q, m); + if (icd2061->ctrl & (1 << a)) + p <<= 1; + icd2061->freq[a] = ((double)p / (double)q) * 2.0 * 14318184.0 / (double)m; + pclog("ICD2061 freq %i = %f\n", a, icd2061->freq[a]); + } + else if (a == 6) + { + icd2061->ctrl = val; + pclog("ICD2061 ctrl = %08X\n", val); + } + icd2061->unlock = icd2061->data = 0; + icd2061->status = 0; + } + } + } + icd2061->state = val; +} + +double icd2061_getfreq(icd2061_t *icd2061, int i) +{ + pclog("Return freq %f\n", icd2061->freq[i]); + return icd2061->freq[i]; +} diff --git a/src/vid_icd2061.h b/src/vid_icd2061.h new file mode 100644 index 000000000..6a235fae6 --- /dev/null +++ b/src/vid_icd2061.h @@ -0,0 +1,14 @@ +typedef struct icd2061_t +{ + int state; + int status; + int pos; + int unlock; + uint32_t data; + + double freq[4]; + uint32_t ctrl; +} icd2061_t; + +void icd2061_write(icd2061_t *icd2061, int val); +double icd2061_getfreq(icd2061_t *icd2061, int i); diff --git a/src/vid_ics2595.c b/src/vid_ics2595.c new file mode 100644 index 000000000..72c5b6fdb --- /dev/null +++ b/src/vid_ics2595.c @@ -0,0 +1,55 @@ +/*ICS2595 clock chip emulation + Used by ATI Mach64*/ + +#include "ibm.h" +#include "vid_ics2595.h" + +enum +{ + ICS2595_IDLE = 0, + ICS2595_WRITE, + ICS2595_READ +}; + +static int ics2595_div[4] = {8, 4, 2, 1}; + +void ics2595_write(ics2595_t *ics2595, int strobe, int dat) +{ +// pclog("ics2595_write : %i %i\n", strobe, dat); + if (strobe) + { + if ((dat & 8) && !ics2595->oldfs3) /*Data clock*/ + { +// pclog(" - new dat %i\n", dat & 4); + switch (ics2595->state) + { + case ICS2595_IDLE: + ics2595->state = (dat & 4) ? ICS2595_WRITE : ICS2595_IDLE; + ics2595->pos = 0; + break; + case ICS2595_WRITE: + ics2595->dat = (ics2595->dat >> 1); + if (dat & 4) + ics2595->dat |= (1 << 19); + ics2595->pos++; + if (ics2595->pos == 20) + { + int d, n, l; +// pclog("ICS2595_WRITE : dat %08X\n", ics2595->dat); + l = (ics2595->dat >> 2) & 0xf; + n = ((ics2595->dat >> 7) & 255) + 257; + d = ics2595_div[(ics2595->dat >> 16) & 3]; + + ics2595->clocks[l] = (14318181.8 * ((double)n / 46.0)) / (double)d; +// pclog("ICS2595 clock set - L %i N %i D %i freq = %f\n", l, n, d, (14318181.8 * ((double)n / 46.0)) / (double)d); + ics2595->state = ICS2595_IDLE; + } + break; + } + } + + ics2595->oldfs2 = dat & 4; + ics2595->oldfs3 = dat & 8; + } + ics2595->output_clock = ics2595->clocks[dat]; +} diff --git a/src/vid_ics2595.h b/src/vid_ics2595.h new file mode 100644 index 000000000..2efe1734e --- /dev/null +++ b/src/vid_ics2595.h @@ -0,0 +1,12 @@ +typedef struct ics2595_t +{ + int oldfs3, oldfs2; + int dat; + int pos; + int state; + + double clocks[16]; + double output_clock; +} ics2595_t; + +void ics2595_write(ics2595_t *ics2595, int strobe, int dat); diff --git a/src/vid_incolor.c b/src/vid_incolor.c new file mode 100644 index 000000000..c4df83bf3 --- /dev/null +++ b/src/vid_incolor.c @@ -0,0 +1,1061 @@ +/*Hercules InColor emulation*/ + +#include +#include "ibm.h" +#include "device.h" +#include "mem.h" +#include "timer.h" +#include "video.h" +#include "vid_incolor.h" + + +/* extended CRTC registers */ + +#define INCOLOR_CRTC_XMODE 20 /* xMode register */ +#define INCOLOR_CRTC_UNDER 21 /* Underline */ +#define INCOLOR_CRTC_OVER 22 /* Overstrike */ +#define INCOLOR_CRTC_EXCEPT 23 /* Exception */ +#define INCOLOR_CRTC_MASK 24 /* Plane display mask & write mask */ +#define INCOLOR_CRTC_RWCTRL 25 /* Read/write control */ +#define INCOLOR_CRTC_RWCOL 26 /* Read/write colour */ +#define INCOLOR_CRTC_PROTECT 27 /* Latch protect */ +#define INCOLOR_CRTC_PALETTE 28 /* Palette */ + +/* character width */ +#define INCOLOR_CW ((incolor->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL) ? 8 : 9) + +/* mode control register */ +#define INCOLOR_CTRL_GRAPH 0x02 +#define INCOLOR_CTRL_ENABLE 0x08 +#define INCOLOR_CTRL_BLINK 0x20 +#define INCOLOR_CTRL_PAGE1 0x80 + +/* CRTC status register */ +#define INCOLOR_STATUS_HSYNC 0x01 /* horizontal sync */ +#define INCOLOR_STATUS_LIGHT 0x02 +#define INCOLOR_STATUS_VIDEO 0x08 +#define INCOLOR_STATUS_ID 0x50 /* Card identification */ +#define INCOLOR_STATUS_VSYNC 0x80 /* -vertical sync */ + +/* configuration switch register */ +#define INCOLOR_CTRL2_GRAPH 0x01 +#define INCOLOR_CTRL2_PAGE1 0x02 + +/* extended mode register */ +#define INCOLOR_XMODE_RAMFONT 0x01 +#define INCOLOR_XMODE_90COL 0x02 + + +/* Read/write control */ +#define INCOLOR_RWCTRL_WRMODE 0x30 +#define INCOLOR_RWCTRL_POLARITY 0x40 + +/* exception register */ +#define INCOLOR_EXCEPT_CURSOR 0x0F /* Cursor colour */ +#define INCOLOR_EXCEPT_PALETTE 0x10 /* Enable palette register */ +#define INCOLOR_EXCEPT_ALTATTR 0x20 /* Use alternate attributes */ + + + +/* Default palette */ +static unsigned char defpal[16] = +{ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F +}; + +static uint32_t incolor_rgb[64]; + +/* Mapping of inks to RGB */ +static unsigned char init_rgb[64][3] = +{ + // rgbRGB + { 0x00, 0x00, 0x00 }, // 000000 + { 0x00, 0x00, 0xaa }, // 000001 + { 0x00, 0xaa, 0x00 }, // 000010 + { 0x00, 0xaa, 0xaa }, // 000011 + { 0xaa, 0x00, 0x00 }, // 000100 + { 0xaa, 0x00, 0xaa }, // 000101 + { 0xaa, 0xaa, 0x00 }, // 000110 + { 0xaa, 0xaa, 0xaa }, // 000111 + { 0x00, 0x00, 0x55 }, // 001000 + { 0x00, 0x00, 0xff }, // 001001 + { 0x00, 0xaa, 0x55 }, // 001010 + { 0x00, 0xaa, 0xff }, // 001011 + { 0xaa, 0x00, 0x55 }, // 001100 + { 0xaa, 0x00, 0xff }, // 001101 + { 0xaa, 0xaa, 0x55 }, // 001110 + { 0xaa, 0xaa, 0xff }, // 001111 + { 0x00, 0x55, 0x00 }, // 010000 + { 0x00, 0x55, 0xaa }, // 010001 + { 0x00, 0xff, 0x00 }, // 010010 + { 0x00, 0xff, 0xaa }, // 010011 + { 0xaa, 0x55, 0x00 }, // 010100 + { 0xaa, 0x55, 0xaa }, // 010101 + { 0xaa, 0xff, 0x00 }, // 010110 + { 0xaa, 0xff, 0xaa }, // 010111 + { 0x00, 0x55, 0x55 }, // 011000 + { 0x00, 0x55, 0xff }, // 011001 + { 0x00, 0xff, 0x55 }, // 011010 + { 0x00, 0xff, 0xff }, // 011011 + { 0xaa, 0x55, 0x55 }, // 011100 + { 0xaa, 0x55, 0xff }, // 011101 + { 0xaa, 0xff, 0x55 }, // 011110 + { 0xaa, 0xff, 0xff }, // 011111 + { 0x55, 0x00, 0x00 }, // 100000 + { 0x55, 0x00, 0xaa }, // 100001 + { 0x55, 0xaa, 0x00 }, // 100010 + { 0x55, 0xaa, 0xaa }, // 100011 + { 0xff, 0x00, 0x00 }, // 100100 + { 0xff, 0x00, 0xaa }, // 100101 + { 0xff, 0xaa, 0x00 }, // 100110 + { 0xff, 0xaa, 0xaa }, // 100111 + { 0x55, 0x00, 0x55 }, // 101000 + { 0x55, 0x00, 0xff }, // 101001 + { 0x55, 0xaa, 0x55 }, // 101010 + { 0x55, 0xaa, 0xff }, // 101011 + { 0xff, 0x00, 0x55 }, // 101100 + { 0xff, 0x00, 0xff }, // 101101 + { 0xff, 0xaa, 0x55 }, // 101110 + { 0xff, 0xaa, 0xff }, // 101111 + { 0x55, 0x55, 0x00 }, // 110000 + { 0x55, 0x55, 0xaa }, // 110001 + { 0x55, 0xff, 0x00 }, // 110010 + { 0x55, 0xff, 0xaa }, // 110011 + { 0xff, 0x55, 0x00 }, // 110100 + { 0xff, 0x55, 0xaa }, // 110101 + { 0xff, 0xff, 0x00 }, // 110110 + { 0xff, 0xff, 0xaa }, // 110111 + { 0x55, 0x55, 0x55 }, // 111000 + { 0x55, 0x55, 0xff }, // 111001 + { 0x55, 0xff, 0x55 }, // 111010 + { 0x55, 0xff, 0xff }, // 111011 + { 0xff, 0x55, 0x55 }, // 111100 + { 0xff, 0x55, 0xff }, // 111101 + { 0xff, 0xff, 0x55 }, // 111110 + { 0xff, 0xff, 0xff }, // 111111 +}; + + + +typedef struct incolor_t +{ + mem_mapping_t mapping; + + uint8_t crtc[32]; + int crtcreg; + + uint8_t ctrl, ctrl2, stat; + + int dispontime, dispofftime; + int vidtime; + + int firstline, lastline; + + int linepos, displine; + int vc, sc; + uint16_t ma, maback; + int con, coff, cursoron; + int dispon, blink; + int vsynctime, vadj; + + uint8_t palette[16]; /* EGA-style 16 -> 64 palette registers */ + uint8_t palette_idx; /* Palette write index */ + uint8_t latch[4]; /* Memory read/write latches */ + uint8_t *vram; +} incolor_t; + +void incolor_recalctimings(incolor_t *incolor); +void incolor_write(uint32_t addr, uint8_t val, void *p); +uint8_t incolor_read(uint32_t addr, void *p); + + +void incolor_out(uint16_t addr, uint8_t val, void *p) +{ + incolor_t *incolor = (incolor_t *)p; +/* pclog("InColor out %04X %02X\n",addr,val); */ + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + incolor->crtcreg = val & 31; + return; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + if (incolor->crtcreg > 28) return; + /* Palette load register */ + if (incolor->crtcreg == INCOLOR_CRTC_PALETTE) + { + incolor->palette[incolor->palette_idx % 16] = val; + ++incolor->palette_idx; + } + incolor->crtc[incolor->crtcreg] = val; + if (incolor->crtc[10] == 6 && incolor->crtc[11] == 7) /*Fix for Generic Turbo XT BIOS, which sets up cursor registers wrong*/ + { + incolor->crtc[10] = 0xb; + incolor->crtc[11] = 0xc; + } + incolor_recalctimings(incolor); + return; + case 0x3b8: + incolor->ctrl = val; + return; + case 0x3bf: + incolor->ctrl2 = val; + if (val & 2) + mem_mapping_set_addr(&incolor->mapping, 0xb0000, 0x10000); + else + mem_mapping_set_addr(&incolor->mapping, 0xb0000, 0x08000); + return; + } +} + +uint8_t incolor_in(uint16_t addr, void *p) +{ + incolor_t *incolor = (incolor_t *)p; +/* pclog("InColor in %04X %02X %04X:%04X %04X\n",addr,(incolor->stat & 0xF) | ((incolor->stat & 8) << 4),CS,pc,CX); */ + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + return incolor->crtcreg; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + if (incolor->crtcreg > 28) return 0xff; + incolor->palette_idx = 0; /* Read resets the palette index */ + return incolor->crtc[incolor->crtcreg]; + case 0x3ba: + /* 0x50: InColor card identity */ + return (incolor->stat & 0xf) | ((incolor->stat & 8) << 4) | 0x50; + } + return 0xff; +} + +void incolor_write(uint32_t addr, uint8_t val, void *p) +{ + incolor_t *incolor = (incolor_t *)p; + egawrites++; + + int plane; + unsigned char wmask = incolor->crtc[INCOLOR_CRTC_MASK]; + unsigned char wmode = incolor->crtc[INCOLOR_CRTC_RWCTRL] & INCOLOR_RWCTRL_WRMODE; + unsigned char fg = incolor->crtc[INCOLOR_CRTC_RWCOL] & 0x0F; + unsigned char bg = (incolor->crtc[INCOLOR_CRTC_RWCOL] >> 4)&0x0F; + unsigned char w; + unsigned char vmask; /* Mask of bit within byte */ + unsigned char pmask; /* Mask of plane within colour value */ + unsigned char latch; + + /* Horrible hack, I know, but it's the only way to fix the 440FX BIOS filling the VRAM with garbage until Tom fixes the memory emulation. */ + if ((cs == 0xE0000) && (cpu_state.pc == 0xBF2F) && (romset == ROM_440FX)) return; + if ((cs == 0xE0000) && (cpu_state.pc == 0xBF77) && (romset == ROM_440FX)) return; + + addr &= 0xFFFF; + + /* In text mode, writes to the bottom 16k always touch all 4 planes */ + if (!(incolor->ctrl & INCOLOR_CTRL_GRAPH) && addr < 0x4000) + { + incolor->vram[addr] = val; + return; + } + + /* There are four write modes: + * 0: 1 => foreground, 0 => background + * 1: 1 => foreground, 0 => source latch + * 2: 1 => source latch, 0 => background + * 3: 1 => source latch, 0 => ~source latch + */ + pmask = 1; + for (plane = 0; plane < 4; pmask <<= 1, wmask >>= 1, addr += 0x10000, + plane++) + { + if (wmask & 0x10) /* Ignore writes to selected plane */ + { + continue; + } + latch = incolor->latch[plane]; + for (vmask = 0x80; vmask != 0; vmask >>= 1) + { + switch (wmode) + { + case 0x00: + if (val & vmask) w = (fg & pmask); + else w = (bg & pmask); + break; + case 0x10: + if (val & vmask) w = (fg & pmask); + else w = (latch & vmask); + break; + case 0x20: + if (val & vmask) w = (latch & vmask); + else w = (bg & pmask); + break; + case 0x30: + if (val & vmask) w = (latch & vmask); + else w = ((~latch) & vmask); + break; + } + /* w is nonzero to write a 1, zero to write a 0 */ + if (w) incolor->vram[addr] |= vmask; + else incolor->vram[addr] &= ~vmask; + } + } +} + +uint8_t incolor_read(uint32_t addr, void *p) +{ + incolor_t *incolor = (incolor_t *)p; + egareads++; + unsigned plane; + unsigned char lp = incolor->crtc[INCOLOR_CRTC_PROTECT]; + unsigned char value = 0; + unsigned char dc; /* "don't care" register */ + unsigned char bg; /* background colour */ + unsigned char fg; + unsigned char mask, pmask; + + addr &= 0xFFFF; + /* Read the four planes into latches */ + for (plane = 0; plane < 4; plane++, addr += 0x10000) + { + incolor->latch[plane] &= lp; + incolor->latch[plane] |= (incolor->vram[addr] & ~lp); + } + addr &= 0xFFFF; + /* In text mode, reads from the bottom 16k assume all planes have + * the same contents */ + if (!(incolor->ctrl & INCOLOR_CTRL_GRAPH) && addr < 0x4000) + { + return incolor->latch[0]; + } + /* For each pixel, work out if its colour matches the background */ + for (mask = 0x80; mask != 0; mask >>= 1) + { + fg = 0; + dc = incolor->crtc[INCOLOR_CRTC_RWCTRL] & 0x0F; + bg = (incolor->crtc[INCOLOR_CRTC_RWCOL] >> 4) & 0x0F; + for (plane = 0, pmask = 1; plane < 4; plane++, pmask <<= 1) + { + if (dc & pmask) + { + fg |= (bg & pmask); + } + else if (incolor->latch[plane] & mask) + { + fg |= pmask; + } + } + if (bg == fg) value |= mask; + } + if (incolor->crtc[INCOLOR_CRTC_RWCTRL] & INCOLOR_RWCTRL_POLARITY) + { + value = ~value; + } + return value; +} + + + +void incolor_recalctimings(incolor_t *incolor) +{ + double disptime; + double _dispontime, _dispofftime; + disptime = incolor->crtc[0] + 1; + _dispontime = incolor->crtc[1]; + _dispofftime = disptime - _dispontime; + _dispontime *= MDACONST; + _dispofftime *= MDACONST; + incolor->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + incolor->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + + +static void incolor_draw_char_rom(incolor_t *incolor, int x, uint8_t chr, uint8_t attr) +{ + unsigned i; + int elg, blk; + unsigned ull; + unsigned val; + unsigned ifg, ibg; + const unsigned char *fnt; + uint32_t fg, bg; + int cw = INCOLOR_CW; + + blk = 0; + if (incolor->ctrl & INCOLOR_CTRL_BLINK) + { + if (attr & 0x80) + { + blk = (incolor->blink & 16); + } + attr &= 0x7f; + } + + if (incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR) + { + /* MDA-compatible attributes */ + ibg = 0; + ifg = 7; + if ((attr & 0x77) == 0x70) /* Invert */ + { + ifg = 0; + ibg = 7; + } + if (attr & 8) + { + ifg |= 8; /* High intensity FG */ + } + if (attr & 0x80) + { + ibg |= 8; /* High intensity BG */ + } + if ((attr & 0x77) == 0) /* Blank */ + { + ifg = ibg; + } + ull = ((attr & 0x07) == 1) ? 13 : 0xffff; + } + else + { + /* CGA-compatible attributes */ + ull = 0xffff; + ifg = attr & 0x0F; + ibg = (attr >> 4) & 0x0F; + } + if (incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE) + { + fg = incolor_rgb[incolor->palette[ifg]]; + bg = incolor_rgb[incolor->palette[ibg]]; + } + else + { + fg = incolor_rgb[defpal[ifg]]; + bg = incolor_rgb[defpal[ibg]]; + } + + /* ELG set to stretch 8px character to 9px */ + elg = ((chr >= 0xc0) && (chr <= 0xdf)); + + fnt = &(fontdatm[chr][incolor->sc]); + + if (blk) + { + val = 0x000; /* Blinking, draw all background */ + } + else if (incolor->sc == ull) + { + val = 0x1ff; /* Underscore, draw all foreground */ + } + else + { + val = fnt[0] << 1; + + if (elg) + { + val |= (val >> 1) & 1; + } + } + for (i = 0; i < cw; i++) + { + ((uint32_t *)buffer32->line[incolor->displine])[x * cw + i] = (val & 0x100) ? fg : bg; + val = val << 1; + } +} + + +static void incolor_draw_char_ram4(incolor_t *incolor, int x, uint8_t chr, uint8_t attr) +{ + unsigned i; + int elg, blk; + unsigned ull; + unsigned val[4]; + unsigned ifg, ibg, cfg, pmask, plane; + const unsigned char *fnt; + uint32_t fg; + int cw = INCOLOR_CW; + int blink = incolor->ctrl & INCOLOR_CTRL_BLINK; + int altattr = incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR; + int palette = incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE; + + blk = 0; + if (blink) + { + if (attr & 0x80) + { + blk = (incolor->blink & 16); + } + attr &= 0x7f; + } + + if (altattr) + { + /* MDA-compatible attributes */ + ibg = 0; + ifg = 7; + if ((attr & 0x77) == 0x70) /* Invert */ + { + ifg = 0; + ibg = 7; + } + if (attr & 8) + { + ifg |= 8; /* High intensity FG */ + } + if (attr & 0x80) + { + ibg |= 8; /* High intensity BG */ + } + if ((attr & 0x77) == 0) /* Blank */ + { + ifg = ibg; + } + ull = ((attr & 0x07) == 1) ? 13 : 0xffff; + } + else + { + /* CGA-compatible attributes */ + ull = 0xffff; + ifg = attr & 0x0F; + ibg = (attr >> 4) & 0x0F; + } + if (incolor->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL) + { + elg = 0; + } + else + { + elg = ((chr >= 0xc0) && (chr <= 0xdf)); + } + fnt = incolor->vram + 0x4000 + 16 * chr + incolor->sc; + + if (blk) + { + /* Blinking, draw all background */ + val[0] = val[1] = val[2] = val[3] = 0x000; + } + else if (incolor->sc == ull) + { + /* Underscore, draw all foreground */ + val[0] = val[1] = val[2] = val[3] = 0x1ff; + } + else + { + val[0] = fnt[0x00000] << 1; + val[1] = fnt[0x10000] << 1; + val[2] = fnt[0x20000] << 1; + val[3] = fnt[0x30000] << 1; + + if (elg) + { + val[0] |= (val[0] >> 1) & 1; + val[1] |= (val[1] >> 1) & 1; + val[2] |= (val[2] >> 1) & 1; + val[3] |= (val[3] >> 1) & 1; + } + } + for (i = 0; i < cw; i++) + { + /* Generate pixel colour */ + cfg = 0; + pmask = 1; + for (plane = 0; plane < 4; plane++, pmask = pmask << 1) + { + if (val[plane] & 0x100) cfg |= (ifg & pmask); + else cfg |= (ibg & pmask); + } + /* cfg = colour of foreground pixels */ + if (altattr && (attr & 0x77) == 0) cfg = ibg; /* 'blank' attribute */ + if (palette) + { + fg = incolor_rgb[incolor->palette[cfg]]; + } + else + { + fg = incolor_rgb[defpal[cfg]]; + } + + ((uint32_t *)buffer32->line[incolor->displine])[x * cw + i] = fg; + val[0] = val[0] << 1; + val[1] = val[1] << 1; + val[2] = val[2] << 1; + val[3] = val[3] << 1; + } +} + + +static void incolor_draw_char_ram48(incolor_t *incolor, int x, uint8_t chr, uint8_t attr) +{ + unsigned i; + int elg, blk, ul, ol, bld; + unsigned ull, oll, ulc, olc; + unsigned val[4]; + unsigned ifg, ibg, cfg, pmask, plane; + const unsigned char *fnt; + uint32_t fg; + int cw = INCOLOR_CW; + int blink = incolor->ctrl & INCOLOR_CTRL_BLINK; + int altattr = incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR; + int palette = incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE; + int font = (attr & 0x0F); + + if (font >= 12) font &= 7; + + blk = 0; + if (blink && altattr) + { + if (attr & 0x40) + { + blk = (incolor->blink & 16); + } + attr &= 0x7f; + } + if (altattr) + { + /* MDA-compatible attributes */ + if (blink) + { + ibg = (attr & 0x80) ? 8 : 0; + bld = 0; + ol = (attr & 0x20) ? 1 : 0; + ul = (attr & 0x10) ? 1 : 0; + } + else + { + bld = (attr & 0x80) ? 1 : 0; + ibg = (attr & 0x40) ? 0x0F : 0; + ol = (attr & 0x20) ? 1 : 0; + ul = (attr & 0x10) ? 1 : 0; + } + } + else + { + /* CGA-compatible attributes */ + ibg = 0; + ifg = (attr >> 4) & 0x0F; + ol = 0; + ul = 0; + bld = 0; + } + if (ul) + { + ull = incolor->crtc[INCOLOR_CRTC_UNDER] & 0x0F; + ulc = (incolor->crtc[INCOLOR_CRTC_UNDER] >> 4) & 0x0F; + if (ulc == 0) ulc = 7; + } + else + { + ull = 0xFFFF; + } + if (ol) + { + oll = incolor->crtc[INCOLOR_CRTC_OVER] & 0x0F; + olc = (incolor->crtc[INCOLOR_CRTC_OVER] >> 4) & 0x0F; + if (olc == 0) olc = 7; + } + else + { + oll = 0xFFFF; + } + + if (incolor->crtc[INCOLOR_CRTC_XMODE] & INCOLOR_XMODE_90COL) + { + elg = 0; + } + else + { + elg = ((chr >= 0xc0) && (chr <= 0xdf)); + } + fnt = incolor->vram + 0x4000 + 16 * chr + 4096 * font + incolor->sc; + + if (blk) + { + /* Blinking, draw all background */ + val[0] = val[1] = val[2] = val[3] = 0x000; + } + else if (incolor->sc == ull) + { + /* Underscore, draw all foreground */ + val[0] = val[1] = val[2] = val[3] = 0x1ff; + } + else + { + val[0] = fnt[0x00000] << 1; + val[1] = fnt[0x10000] << 1; + val[2] = fnt[0x20000] << 1; + val[3] = fnt[0x30000] << 1; + + if (elg) + { + val[0] |= (val[0] >> 1) & 1; + val[1] |= (val[1] >> 1) & 1; + val[2] |= (val[2] >> 1) & 1; + val[3] |= (val[3] >> 1) & 1; + } + if (bld) + { + val[0] |= (val[0] >> 1); + val[1] |= (val[1] >> 1); + val[2] |= (val[2] >> 1); + val[3] |= (val[3] >> 1); + } + } + for (i = 0; i < cw; i++) + { + /* Generate pixel colour */ + cfg = 0; + pmask = 1; + if (incolor->sc == oll) + { + cfg = olc ^ ibg; /* Strikethrough */ + } + else if (incolor->sc == ull) + { + cfg = ulc ^ ibg; /* Underline */ + } + else + { + for (plane = 0; plane < 4; plane++, pmask = pmask << 1) + { + if (val[plane] & 0x100) + { + if (altattr) cfg |= ((~ibg) & pmask); + else cfg |= ((~ifg) & pmask); + } + else if (altattr) cfg |= (ibg & pmask); + } + } + if (palette) + { + fg = incolor_rgb[incolor->palette[cfg]]; + } + else + { + fg = incolor_rgb[defpal[cfg]]; + } + + ((uint32_t *)buffer32->line[incolor->displine])[x * cw + i] = fg; + val[0] = val[0] << 1; + val[1] = val[1] << 1; + val[2] = val[2] << 1; + val[3] = val[3] << 1; + } +} + + + + + + +static void incolor_text_line(incolor_t *incolor, uint16_t ca) +{ + int drawcursor; + int x, c; + uint8_t chr, attr; + uint32_t col; + + for (x = 0; x < incolor->crtc[1]; x++) + { + chr = incolor->vram[(incolor->ma << 1) & 0x3fff]; + attr = incolor->vram[((incolor->ma << 1) + 1) & 0x3fff]; + + drawcursor = ((incolor->ma == ca) && incolor->con && incolor->cursoron); + + switch (incolor->crtc[INCOLOR_CRTC_XMODE] & 5) + { + case 0: + case 4: /* ROM font */ + incolor_draw_char_rom(incolor, x, chr, attr); + break; + case 1: /* 4k RAMfont */ + incolor_draw_char_ram4(incolor, x, chr, attr); + break; + case 5: /* 48k RAMfont */ + incolor_draw_char_ram48(incolor, x, chr, attr); + break; + + } + ++incolor->ma; + if (drawcursor) + { + int cw = INCOLOR_CW; + uint8_t ink = incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_CURSOR; + if (ink == 0) ink = (attr & 0x08) | 7; + + /* In MDA-compatible mode, cursor brightness comes from + * background */ + if (incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_ALTATTR) + { + ink = (attr & 0x08) | (ink & 7); + } + if (incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE) + { + col = incolor_rgb[incolor->palette[ink]]; + } + else + { + col = incolor_rgb[defpal[ink]]; + } + for (c = 0; c < cw; c++) + { + ((uint32_t *)buffer32->line[incolor->displine])[x * cw + c] = col; + } + } + } +} + + +static void incolor_graphics_line(incolor_t *incolor) +{ + uint8_t mask; + uint16_t ca; + int x, c, plane, col; + uint8_t ink; + uint16_t val[4]; + + /* Graphics mode. */ + ca = (incolor->sc & 3) * 0x2000; + if ((incolor->ctrl & INCOLOR_CTRL_PAGE1) && (incolor->ctrl2 & INCOLOR_CTRL2_PAGE1)) + ca += 0x8000; + + for (x = 0; x < incolor->crtc[1]; x++) + { + mask = incolor->crtc[INCOLOR_CRTC_MASK]; /* Planes to display */ + for (plane = 0; plane < 4; plane++, mask = mask >> 1) + { + if (mask & 1) + val[plane] = (incolor->vram[((incolor->ma << 1) & 0x1fff) + ca + 0x10000 * plane] << 8) | + incolor->vram[((incolor->ma << 1) & 0x1fff) + ca + 0x10000 * plane + 1]; + else val[plane] = 0; + } + incolor->ma++; + for (c = 0; c < 16; c++) + { + ink = 0; + for (plane = 0; plane < 4; plane++) + { + ink = ink >> 1; + if (val[plane] & 0x8000) ink |= 8; + val[plane] = val[plane] << 1; + } + /* Is palette in use? */ + if (incolor->crtc[INCOLOR_CRTC_EXCEPT] & INCOLOR_EXCEPT_PALETTE) + col = incolor->palette[ink]; + else col = defpal[ink]; + + ((uint32_t *)buffer32->line[incolor->displine])[(x << 4) + c] = incolor_rgb[col]; + } + } +} + +void incolor_poll(void *p) +{ + incolor_t *incolor = (incolor_t *)p; + uint16_t ca = (incolor->crtc[15] | (incolor->crtc[14] << 8)) & 0x3fff; + int x; + int oldvc; + int oldsc; + + if (!incolor->linepos) + { +// pclog("InColor poll %i %i\n", incolor->vc, incolor->sc); + incolor->vidtime += incolor->dispofftime; + incolor->stat |= 1; + incolor->linepos = 1; + oldsc = incolor->sc; + if ((incolor->crtc[8] & 3) == 3) + incolor->sc = (incolor->sc << 1) & 7; + if (incolor->dispon) + { + if (incolor->displine < incolor->firstline) + { + incolor->firstline = incolor->displine; + } + incolor->lastline = incolor->displine; + if ((incolor->ctrl & INCOLOR_CTRL_GRAPH) && (incolor->ctrl2 & INCOLOR_CTRL2_GRAPH)) + { + incolor_graphics_line(incolor); + } + else + { + incolor_text_line(incolor, ca); + } + } + incolor->sc = oldsc; + if (incolor->vc == incolor->crtc[7] && !incolor->sc) + { + incolor->stat |= 8; +// printf("VSYNC on %i %i\n",vc,sc); + } + incolor->displine++; + if (incolor->displine >= 500) + incolor->displine = 0; + } + else + { + incolor->vidtime += incolor->dispontime; + if (incolor->dispon) + incolor->stat &= ~1; + incolor->linepos = 0; + if (incolor->vsynctime) + { + incolor->vsynctime--; + if (!incolor->vsynctime) + { + incolor->stat &= ~8; +// printf("VSYNC off %i %i\n",vc,sc); + } + } + if (incolor->sc == (incolor->crtc[11] & 31) || ((incolor->crtc[8] & 3) == 3 && incolor->sc == ((incolor->crtc[11] & 31) >> 1))) + { + incolor->con = 0; + incolor->coff = 1; + } + if (incolor->vadj) + { + incolor->sc++; + incolor->sc &= 31; + incolor->ma = incolor->maback; + incolor->vadj--; + if (!incolor->vadj) + { + incolor->dispon = 1; + incolor->ma = incolor->maback = (incolor->crtc[13] | (incolor->crtc[12] << 8)) & 0x3fff; + incolor->sc = 0; + } + } + else if (incolor->sc == incolor->crtc[9] || ((incolor->crtc[8] & 3) == 3 && incolor->sc == (incolor->crtc[9] >> 1))) + { + incolor->maback = incolor->ma; + incolor->sc = 0; + oldvc = incolor->vc; + incolor->vc++; + incolor->vc &= 127; + if (incolor->vc == incolor->crtc[6]) + incolor->dispon = 0; + if (oldvc == incolor->crtc[4]) + { +// printf("Display over at %i\n",displine); + incolor->vc = 0; + incolor->vadj = incolor->crtc[5]; + if (!incolor->vadj) incolor->dispon=1; + if (!incolor->vadj) incolor->ma = incolor->maback = (incolor->crtc[13] | (incolor->crtc[12] << 8)) & 0x3fff; + if ((incolor->crtc[10] & 0x60) == 0x20) incolor->cursoron = 0; + else incolor->cursoron = incolor->blink & 16; + } + if (incolor->vc == incolor->crtc[7]) + { + incolor->dispon = 0; + incolor->displine = 0; + incolor->vsynctime = 16;//(crtcm[3]>>4)+1; + if (incolor->crtc[7]) + { +// printf("Lastline %i Firstline %i %i\n",lastline,firstline,lastline-firstline); + if ((incolor->ctrl & INCOLOR_CTRL_GRAPH) && (incolor->ctrl2 & INCOLOR_CTRL2_GRAPH)) + { + x = incolor->crtc[1] << 4; + } + else + { + x = incolor->crtc[1] * 9; + } + incolor->lastline++; + if (x != xsize || (incolor->lastline - incolor->firstline) != ysize) + { + xsize = x; + ysize = incolor->lastline - incolor->firstline; +// printf("Resize to %i,%i - R1 %i\n",xsize,ysize,crtcm[1]); + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + updatewindowsize(xsize, ysize); + } + startblit(); + video_blit_memtoscreen(0, incolor->firstline, 0, incolor->lastline - incolor->firstline, xsize, incolor->lastline - incolor->firstline); + endblit(); + frames++; + if ((incolor->ctrl & INCOLOR_CTRL_GRAPH) && (incolor->ctrl2 & INCOLOR_CTRL2_GRAPH)) + { + video_res_x = incolor->crtc[1] * 16; + video_res_y = incolor->crtc[6] * 4; + video_bpp = 1; + } + else + { + video_res_x = incolor->crtc[1]; + video_res_y = incolor->crtc[6]; + video_bpp = 0; + } + } + incolor->firstline = 1000; + incolor->lastline = 0; + incolor->blink++; + } + } + else + { + incolor->sc++; + incolor->sc &= 31; + incolor->ma = incolor->maback; + } + if ((incolor->sc == (incolor->crtc[10] & 31) || ((incolor->crtc[8] & 3) == 3 && incolor->sc == ((incolor->crtc[10] & 31) >> 1)))) + { + incolor->con = 1; +// printf("Cursor on - %02X %02X %02X\n",crtcm[8],crtcm[10],crtcm[11]); + } + } +} + +void *incolor_init() +{ + int c; + incolor_t *incolor = malloc(sizeof(incolor_t)); + memset(incolor, 0, sizeof(incolor_t)); + + incolor->vram = malloc(0x40000); /* 4 planes of 64k */ + + timer_add(incolor_poll, &incolor->vidtime, TIMER_ALWAYS_ENABLED, incolor); + mem_mapping_add(&incolor->mapping, 0xb0000, 0x08000, incolor_read, NULL, NULL, incolor_write, NULL, NULL, NULL, 0, incolor); + io_sethandler(0x03b0, 0x0010, incolor_in, NULL, NULL, incolor_out, NULL, NULL, incolor); + + for (c = 0; c < 64; c++) + { + incolor_rgb[c] = makecol32(init_rgb[c][0], init_rgb[c][1], init_rgb[c][2]); + } + +/* Initialise CRTC regs to safe values */ + incolor->crtc[INCOLOR_CRTC_MASK ] = 0x0F; /* All planes displayed */ + incolor->crtc[INCOLOR_CRTC_RWCTRL] = INCOLOR_RWCTRL_POLARITY; + incolor->crtc[INCOLOR_CRTC_RWCOL ] = 0x0F; /* White on black */ + incolor->crtc[INCOLOR_CRTC_EXCEPT] = INCOLOR_EXCEPT_ALTATTR; + for (c = 0; c < 16; c++) + { + incolor->palette[c] = defpal[c]; + } + incolor->palette_idx = 0; + + + + return incolor; +} + +void incolor_close(void *p) +{ + incolor_t *incolor = (incolor_t *)p; + + free(incolor->vram); + free(incolor); +} + +void incolor_speed_changed(void *p) +{ + incolor_t *incolor = (incolor_t *)p; + + incolor_recalctimings(incolor); +} + +device_t incolor_device = +{ + "Hercules InColor", + 0, + incolor_init, + incolor_close, + NULL, + incolor_speed_changed, + NULL, + NULL +}; diff --git a/src/vid_incolor.h b/src/vid_incolor.h new file mode 100644 index 000000000..297b7b42e --- /dev/null +++ b/src/vid_incolor.h @@ -0,0 +1 @@ +extern device_t incolor_device; diff --git a/src/vid_mda.c b/src/vid_mda.c new file mode 100644 index 000000000..8d30b9ff3 --- /dev/null +++ b/src/vid_mda.c @@ -0,0 +1,328 @@ +/*MDA emulation*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "timer.h" +#include "video.h" +#include "vid_mda.h" + +typedef struct mda_t +{ + mem_mapping_t mapping; + + uint8_t crtc[32]; + int crtcreg; + + uint8_t ctrl, stat; + + int dispontime, dispofftime; + int vidtime; + + int firstline, lastline; + + int linepos, displine; + int vc, sc; + uint16_t ma, maback; + int con, coff, cursoron; + int dispon, blink; + int vsynctime, vadj; + + uint8_t *vram; +} mda_t; + +static int mdacols[256][2][2]; + +void mda_recalctimings(mda_t *mda); + +void mda_out(uint16_t addr, uint8_t val, void *p) +{ + mda_t *mda = (mda_t *)p; + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + mda->crtcreg = val & 31; + return; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + mda->crtc[mda->crtcreg] = val; + if (mda->crtc[10] == 6 && mda->crtc[11] == 7) /*Fix for Generic Turbo XT BIOS, which sets up cursor registers wrong*/ + { + mda->crtc[10] = 0xb; + mda->crtc[11] = 0xc; + } + mda_recalctimings(mda); + return; + case 0x3b8: + mda->ctrl = val; + return; + } +} + +uint8_t mda_in(uint16_t addr, void *p) +{ + mda_t *mda = (mda_t *)p; + switch (addr) + { + case 0x3b0: case 0x3b2: case 0x3b4: case 0x3b6: + return mda->crtcreg; + case 0x3b1: case 0x3b3: case 0x3b5: case 0x3b7: + return mda->crtc[mda->crtcreg]; + case 0x3ba: + return mda->stat | 0xF0; + } + return 0xff; +} + +void mda_write(uint32_t addr, uint8_t val, void *p) +{ + mda_t *mda = (mda_t *)p; + egawrites++; + /* Horrible hack, I know, but it's the only way to fix the 440FX BIOS filling the VRAM with garbage until Tom fixes the memory emulation. */ + if ((cs == 0xE0000) && (cpu_state.pc == 0xBF2F) && (romset == ROM_440FX)) return; + if ((cs == 0xE0000) && (cpu_state.pc == 0xBF77) && (romset == ROM_440FX)) return; + mda->vram[addr & 0xfff] = val; +} + +uint8_t mda_read(uint32_t addr, void *p) +{ + mda_t *mda = (mda_t *)p; + egareads++; + return mda->vram[addr & 0xfff]; +} + +void mda_recalctimings(mda_t *mda) +{ + double _dispontime, _dispofftime, disptime; + disptime = mda->crtc[0] + 1; + _dispontime = mda->crtc[1]; + _dispofftime = disptime - _dispontime; + _dispontime *= MDACONST; + _dispofftime *= MDACONST; + mda->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + mda->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + +void mda_poll(void *p) +{ + mda_t *mda = (mda_t *)p; + uint16_t ca = (mda->crtc[15] | (mda->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + int cols[4]; + int oldsc; + int blink; + if (!mda->linepos) + { + mda->vidtime += mda->dispofftime; + mda->stat |= 1; + mda->linepos = 1; + oldsc = mda->sc; + if ((mda->crtc[8] & 3) == 3) + mda->sc = (mda->sc << 1) & 7; + if (mda->dispon) + { + if (mda->displine < mda->firstline) + { + mda->firstline = mda->displine; + } + mda->lastline = mda->displine; + cols[0] = 0; + cols[1] = 7; + for (x = 0; x < mda->crtc[1]; x++) + { + chr = mda->vram[(mda->ma << 1) & 0x3fff]; + attr = mda->vram[((mda->ma << 1) + 1) & 0x3fff]; + drawcursor = ((mda->ma == ca) && mda->con && mda->cursoron); + blink = ((mda->blink & 16) && (mda->ctrl & 0x20) && (attr & 0x80) && !drawcursor); + if (mda->sc == 12 && ((attr & 7) == 1)) + { + for (c = 0; c < 9; c++) + buffer->line[mda->displine][(x * 9) + c] = mdacols[attr][blink][1]; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[mda->displine][(x * 9) + c] = mdacols[attr][blink][(fontdatm[chr][mda->sc] & (1 << (c ^ 7))) ? 1 : 0]; + if ((chr & ~0x1f) == 0xc0) buffer->line[mda->displine][(x * 9) + 8] = mdacols[attr][blink][fontdatm[chr][mda->sc] & 1]; + else buffer->line[mda->displine][(x * 9) + 8] = mdacols[attr][blink][0]; + } + mda->ma++; + if (drawcursor) + { + for (c = 0; c < 9; c++) + buffer->line[mda->displine][(x * 9) + c] ^= mdacols[attr][0][1]; + } + } + } + mda->sc = oldsc; + if (mda->vc == mda->crtc[7] && !mda->sc) + { + mda->stat |= 8; +// printf("VSYNC on %i %i\n",vc,sc); + } + mda->displine++; + if (mda->displine >= 500) + mda->displine=0; + } + else + { + mda->vidtime += mda->dispontime; + if (mda->dispon) mda->stat&=~1; + mda->linepos=0; + if (mda->vsynctime) + { + mda->vsynctime--; + if (!mda->vsynctime) + { + mda->stat&=~8; +// printf("VSYNC off %i %i\n",vc,sc); + } + } + if (mda->sc == (mda->crtc[11] & 31) || ((mda->crtc[8] & 3) == 3 && mda->sc == ((mda->crtc[11] & 31) >> 1))) + { + mda->con = 0; + mda->coff = 1; + } + if (mda->vadj) + { + mda->sc++; + mda->sc &= 31; + mda->ma = mda->maback; + mda->vadj--; + if (!mda->vadj) + { + mda->dispon = 1; + mda->ma = mda->maback = (mda->crtc[13] | (mda->crtc[12] << 8)) & 0x3fff; + mda->sc = 0; + } + } + else if (mda->sc == mda->crtc[9] || ((mda->crtc[8] & 3) == 3 && mda->sc == (mda->crtc[9] >> 1))) + { + mda->maback = mda->ma; + mda->sc = 0; + oldvc = mda->vc; + mda->vc++; + mda->vc &= 127; + if (mda->vc == mda->crtc[6]) + mda->dispon=0; + if (oldvc == mda->crtc[4]) + { +// printf("Display over at %i\n",displine); + mda->vc = 0; + mda->vadj = mda->crtc[5]; + if (!mda->vadj) mda->dispon = 1; + if (!mda->vadj) mda->ma = mda->maback = (mda->crtc[13] | (mda->crtc[12] << 8)) & 0x3fff; + if ((mda->crtc[10] & 0x60) == 0x20) mda->cursoron = 0; + else mda->cursoron = mda->blink & 16; + } + if (mda->vc == mda->crtc[7]) + { + mda->dispon = 0; + mda->displine = 0; + mda->vsynctime = 16; + if (mda->crtc[7]) + { +// printf("Lastline %i Firstline %i %i\n",lastline,firstline,lastline-firstline); + x = mda->crtc[1] * 9; + mda->lastline++; + if (x != xsize || (mda->lastline - mda->firstline) != ysize) + { + xsize = x; + ysize = mda->lastline - mda->firstline; +// printf("Resize to %i,%i - R1 %i\n",xsize,ysize,crtcm[1]); + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + updatewindowsize(xsize, ysize); + } + startblit(); + video_blit_memtoscreen_8(0, mda->firstline, xsize, mda->lastline - mda->firstline); + endblit(); + frames++; + video_res_x = mda->crtc[1]; + video_res_y = mda->crtc[6]; + video_bpp = 0; + } + mda->firstline = 1000; + mda->lastline = 0; + mda->blink++; + } + } + else + { + mda->sc++; + mda->sc &= 31; + mda->ma = mda->maback; + } + if ((mda->sc == (mda->crtc[10] & 31) || ((mda->crtc[8] & 3) == 3 && mda->sc == ((mda->crtc[10] & 31) >> 1)))) + { + mda->con = 1; +// printf("Cursor on - %02X %02X %02X\n",crtcm[8],crtcm[10],crtcm[11]); + } + } +} + +void *mda_init() +{ + int c; + mda_t *mda = malloc(sizeof(mda_t)); + memset(mda, 0, sizeof(mda_t)); + + mda->vram = malloc(0x1000); + + timer_add(mda_poll, &mda->vidtime, TIMER_ALWAYS_ENABLED, mda); + mem_mapping_add(&mda->mapping, 0xb0000, 0x08000, mda_read, NULL, NULL, mda_write, NULL, NULL, NULL, 0, mda); + io_sethandler(0x03b0, 0x0010, mda_in, NULL, NULL, mda_out, NULL, NULL, mda); + + for (c = 0; c < 256; c++) + { + mdacols[c][0][0] = mdacols[c][1][0] = mdacols[c][1][1] = 16; + if (c & 8) mdacols[c][0][1] = 15 + 16; + else mdacols[c][0][1] = 7 + 16; + } + mdacols[0x70][0][1] = 16; + mdacols[0x70][0][0] = mdacols[0x70][1][0] = mdacols[0x70][1][1] = 16 + 15; + mdacols[0xF0][0][1] = 16; + mdacols[0xF0][0][0] = mdacols[0xF0][1][0] = mdacols[0xF0][1][1] = 16 + 15; + mdacols[0x78][0][1] = 16 + 7; + mdacols[0x78][0][0] = mdacols[0x78][1][0] = mdacols[0x78][1][1] = 16 + 15; + mdacols[0xF8][0][1] = 16 + 7; + mdacols[0xF8][0][0] = mdacols[0xF8][1][0] = mdacols[0xF8][1][1] = 16 + 15; + mdacols[0x00][0][1] = mdacols[0x00][1][1] = 16; + mdacols[0x08][0][1] = mdacols[0x08][1][1] = 16; + mdacols[0x80][0][1] = mdacols[0x80][1][1] = 16; + mdacols[0x88][0][1] = mdacols[0x88][1][1] = 16; + + overscan_x = overscan_y = 0; + + return mda; +} + +void mda_close(void *p) +{ + mda_t *mda = (mda_t *)p; + + free(mda->vram); + free(mda); +} + +void mda_speed_changed(void *p) +{ + mda_t *mda = (mda_t *)p; + + mda_recalctimings(mda); +} + +device_t mda_device = +{ + "MDA", + 0, + mda_init, + mda_close, + NULL, + mda_speed_changed, + NULL, + NULL +}; diff --git a/src/vid_mda.h b/src/vid_mda.h new file mode 100644 index 000000000..682c671e2 --- /dev/null +++ b/src/vid_mda.h @@ -0,0 +1 @@ +extern device_t mda_device; diff --git a/src/vid_olivetti_m24.c b/src/vid_olivetti_m24.c new file mode 100644 index 000000000..5889022a3 --- /dev/null +++ b/src/vid_olivetti_m24.c @@ -0,0 +1,490 @@ +/*Olivetti M24 video emulation + Essentially double-res CGA*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "timer.h" +#include "video.h" +#include "vid_olivetti_m24.h" + +typedef struct m24_t +{ + mem_mapping_t mapping; + + uint8_t crtc[32]; + int crtcreg; + + uint8_t *vram; + uint8_t charbuffer[256]; + + uint8_t ctrl; + uint32_t base; + + uint8_t cgamode, cgacol; + uint8_t stat; + + int linepos, displine; + int sc, vc; + int con, coff, cursoron, blink; + int vsynctime, vadj; + int lineff; + uint16_t ma, maback; + int dispon; + + int dispontime, dispofftime, vidtime; + + int firstline, lastline; +} m24_t; + +static uint8_t crtcmask[32] = +{ + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +void m24_recalctimings(m24_t *m24); + + +void m24_out(uint16_t addr, uint8_t val, void *p) +{ + m24_t *m24 = (m24_t *)p; + uint8_t old; +// pclog("m24_out %04X %02X\n", addr, val); + switch (addr) + { + case 0x3d4: + m24->crtcreg = val & 31; + return; + case 0x3d5: + old = m24->crtc[m24->crtcreg]; + m24->crtc[m24->crtcreg] = val & crtcmask[m24->crtcreg]; + if (old != val) + { + if (m24->crtcreg < 0xe || m24->crtcreg > 0x10) + { + fullchange = changeframecount; + m24_recalctimings(m24); + } + } + return; + case 0x3d8: + m24->cgamode = val; + return; + case 0x3d9: + m24->cgacol = val; + return; + case 0x3de: + m24->ctrl = val; + m24->base = (val & 0x08) ? 0x4000 : 0; + return; + } +} + +uint8_t m24_in(uint16_t addr, void *p) +{ + m24_t *m24 = (m24_t *)p; + switch (addr) + { + case 0x3d4: + return m24->crtcreg; + case 0x3d5: + return m24->crtc[m24->crtcreg]; + case 0x3da: + return m24->stat; + } + return 0xff; +} + +void m24_write(uint32_t addr, uint8_t val, void *p) +{ + m24_t *m24 = (m24_t *)p; + m24->vram[addr & 0x7FFF]=val; + m24->charbuffer[ ((int)(((m24->dispontime - m24->vidtime) * 2) / (CGACONST / 2))) & 0xfc] = val; + m24->charbuffer[(((int)(((m24->dispontime - m24->vidtime) * 2) / (CGACONST / 2))) & 0xfc) | 1] = val; +} + +uint8_t m24_read(uint32_t addr, void *p) +{ + m24_t *m24 = (m24_t *)p; + return m24->vram[addr & 0x7FFF]; +} + +void m24_recalctimings(m24_t *m24) +{ + double _dispontime, _dispofftime, disptime; + if (m24->cgamode & 1) + { + disptime = m24->crtc[0] + 1; + _dispontime = m24->crtc[1]; + } + else + { + disptime = (m24->crtc[0] + 1) << 1; + _dispontime = m24->crtc[1] << 1; + } + _dispofftime = disptime - _dispontime; +// printf("%i %f %f %f %i %i\n",cgamode&1,disptime,dispontime,dispofftime,crtc[0],crtc[1]); + _dispontime *= CGACONST / 2; + _dispofftime *= CGACONST / 2; +// printf("Timings - on %f off %f frame %f second %f\n",dispontime,dispofftime,(dispontime+dispofftime)*262.0,(dispontime+dispofftime)*262.0*59.92); + m24->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + m24->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + +void m24_poll(void *p) +{ + m24_t *m24 = (m24_t *)p; + uint16_t ca = (m24->crtc[15] | (m24->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + uint16_t dat, dat2; + int cols[4]; + int col; + int oldsc; + if (!m24->linepos) + { +// pclog("Line poll %i %i %i %i - %04X %i %i %i\n", m24_lineff, vc, sc, vadj, ma, firstline, lastline, displine); + m24->vidtime += m24->dispofftime; + m24->stat |= 1; + m24->linepos = 1; + oldsc = m24->sc; + if ((m24->crtc[8] & 3) == 3) + m24->sc = (m24->sc << 1) & 7; + if (m24->dispon) + { + pclog("dispon %i\n", m24->linepos); + if (m24->displine < m24->firstline) + { + m24->firstline = m24->displine; +// printf("Firstline %i\n",firstline); + } + m24->lastline = m24->displine; + for (c = 0; c < 8; c++) + { + if ((m24->cgamode & 0x12) == 0x12) + { + buffer->line[m24->displine][c] = 0; + if (m24->cgamode & 1) buffer->line[m24->displine][c + (m24->crtc[1] << 3) + 8] = 0; + else buffer->line[m24->displine][c + (m24->crtc[1] << 4) + 8] = 0; + } + else + { + buffer->line[m24->displine][c] = (m24->cgacol & 15) + 16; + if (m24->cgamode & 1) buffer->line[m24->displine][c + (m24->crtc[1] << 3) + 8] = (m24->cgacol & 15) + 16; + else buffer->line[m24->displine][c + (m24->crtc[1] << 4) + 8] = (m24->cgacol & 15) + 16; + } + } + if (m24->cgamode & 1) + { + for (x = 0; x < m24->crtc[1]; x++) + { + chr = m24->charbuffer[ x << 1]; + attr = m24->charbuffer[(x << 1) + 1]; + drawcursor = ((m24->ma == ca) && m24->con && m24->cursoron); + if (m24->cgamode & 0x20) + { + cols[1] = (attr & 15) + 16; + cols[0] = ((attr >> 4) & 7) + 16; + if ((m24->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } + else + { + cols[1] = (attr & 15) + 16; + cols[0] = (attr >> 4) + 16; + } + if (drawcursor) + { + for (c = 0; c < 8; c++) + buffer->line[m24->displine][(x << 3) + c + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[m24->displine][(x << 3) + c + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0]; + } + m24->ma++; + } + } + else if (!(m24->cgamode & 2)) + { + for (x = 0; x < m24->crtc[1]; x++) + { + chr = m24->vram[((m24->ma << 1) & 0x3fff) + m24->base]; + attr = m24->vram[(((m24->ma << 1) + 1) & 0x3fff) + m24->base]; + drawcursor = ((m24->ma == ca) && m24->con && m24->cursoron); + if (m24->cgamode & 0x20) + { + cols[1] = (attr & 15) + 16; + cols[0] = ((attr >> 4) & 7) + 16; + if ((m24->blink & 16) && (attr & 0x80)) + cols[1] = cols[0]; + } + else + { + cols[1] = (attr & 15) + 16; + cols[0] = (attr >> 4) + 16; + } + m24->ma++; + if (drawcursor) + { + for (c = 0; c < 8; c++) + buffer->line[m24->displine][(x << 4) + (c << 1) + 8] = + buffer->line[m24->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[m24->displine][(x << 4) + (c << 1) + 8] = + buffer->line[m24->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdatm[chr][((m24->sc & 7) << 1) | m24->lineff] & (1 << (c ^ 7))) ? 1 : 0]; + } + } + } + else if (!(m24->cgamode & 16)) + { + cols[0] = (m24->cgacol & 15) | 16; + col = (m24->cgacol & 16) ? 24 : 16; + if (m24->cgamode & 4) + { + cols[1] = col | 3; + cols[2] = col | 4; + cols[3] = col | 7; + } + else if (m24->cgacol & 32) + { + cols[1] = col | 3; + cols[2] = col | 5; + cols[3] = col | 7; + } + else + { + cols[1] = col | 2; + cols[2] = col | 4; + cols[3] = col | 6; + } + for (x = 0; x < m24->crtc[1]; x++) + { + dat = (m24->vram[((m24->ma << 1) & 0x1fff) + ((m24->sc & 1) * 0x2000) + m24->base] << 8) | + m24->vram[((m24->ma << 1) & 0x1fff) + ((m24->sc & 1) * 0x2000) + 1 + m24->base]; + m24->ma++; + for (c = 0; c < 8; c++) + { + buffer->line[m24->displine][(x << 4) + (c << 1) + 8] = + buffer->line[m24->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + dat <<= 2; + } + } + } + else + { + if (m24->ctrl & 1) + { + dat2 = ((m24->sc & 1) * 0x4000) | (m24->lineff * 0x2000); + cols[0] = 0; cols[1] = /*(m24->cgacol & 15)*/15 + 16; + } + else + { + dat2 = (m24->sc & 1) * 0x2000; + cols[0] = 0; cols[1] = (m24->cgacol & 15) + 16; + } + for (x = 0; x < m24->crtc[1]; x++) + { + dat = (m24->vram[((m24->ma << 1) & 0x1fff) + dat2] << 8) | m24->vram[((m24->ma << 1) & 0x1fff) + dat2 + 1]; + m24->ma++; + for (c = 0; c < 16; c++) + { + buffer->line[m24->displine][(x << 4) + c + 8] = cols[dat >> 15]; + dat <<= 1; + } + } + } + } + else + { + cols[0] = ((m24->cgamode & 0x12) == 0x12) ? 0 : (m24->cgacol & 15) + 16; + if (m24->cgamode & 1) hline(buffer, 0, m24->displine, (m24->crtc[1] << 3) + 16, cols[0]); + else hline(buffer, 0, m24->displine, (m24->crtc[1] << 4) + 16, cols[0]); + } + + if (m24->cgamode & 1) x = (m24->crtc[1] << 3) + 16; + else x = (m24->crtc[1] << 4) + 16; + + m24->sc = oldsc; + if (m24->vc == m24->crtc[7] && !m24->sc) + m24->stat |= 8; + m24->displine++; + if (m24->displine >= 720) m24->displine = 0; + } + else + { +// pclog("Line poll %i %i %i %i\n", m24_lineff, vc, sc, vadj); + m24->vidtime += m24->dispontime; + if (m24->dispon) m24->stat &= ~1; + m24->linepos = 0; + m24->lineff ^= 1; + if (m24->lineff) + { + m24->ma = m24->maback; + } + else + { + if (m24->vsynctime) + { + m24->vsynctime--; + if (!m24->vsynctime) + m24->stat &= ~8; + } + if (m24->sc == (m24->crtc[11] & 31) || ((m24->crtc[8] & 3) == 3 && m24->sc == ((m24->crtc[11] & 31) >> 1))) + { + m24->con = 0; + m24->coff = 1; + } + if (m24->vadj) + { + m24->sc++; + m24->sc &= 31; + m24->ma = m24->maback; + m24->vadj--; + if (!m24->vadj) + { + m24->dispon = 1; + m24->ma = m24->maback = (m24->crtc[13] | (m24->crtc[12] << 8)) & 0x3fff; + m24->sc = 0; + } + } + else if (m24->sc == m24->crtc[9] || ((m24->crtc[8] & 3) == 3 && m24->sc == (m24->crtc[9] >> 1))) + { + m24->maback = m24->ma; + m24->sc = 0; + oldvc = m24->vc; + m24->vc++; + m24->vc &= 127; + + if (m24->vc == m24->crtc[6]) + m24->dispon=0; + + if (oldvc == m24->crtc[4]) + { + m24->vc = 0; + m24->vadj = m24->crtc[5]; + if (!m24->vadj) m24->dispon = 1; + if (!m24->vadj) m24->ma = m24->maback = (m24->crtc[13] | (m24->crtc[12] << 8)) & 0x3fff; + if ((m24->crtc[10] & 0x60) == 0x20) m24->cursoron = 0; + else m24->cursoron = m24->blink & 16; + } + + if (m24->vc == m24->crtc[7]) + { + m24->dispon = 0; + m24->displine = 0; + m24->vsynctime = (m24->crtc[3] >> 4) + 1; + if (m24->crtc[7]) + { + if (m24->cgamode & 1) x = (m24->crtc[1] << 3) + 16; + else x = (m24->crtc[1] << 4) + 16; + m24->lastline++; + if (x != xsize || (m24->lastline - m24->firstline) != ysize) + { + xsize = x; + ysize = m24->lastline - m24->firstline; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + updatewindowsize(xsize, ysize + 16); + } +startblit(); + video_blit_memtoscreen_8(0, m24->firstline - 8, xsize, (m24->lastline - m24->firstline) + 16); + frames++; +endblit(); + video_res_x = xsize - 16; + video_res_y = ysize; + if (m24->cgamode & 1) + { + video_res_x /= 8; + video_res_y /= (m24->crtc[9] + 1) * 2; + video_bpp = 0; + } + else if (!(m24->cgamode & 2)) + { + video_res_x /= 16; + video_res_y /= (m24->crtc[9] + 1) * 2; + video_bpp = 0; + } + else if (!(m24->cgamode & 16)) + { + video_res_x /= 2; + video_res_y /= 2; + video_bpp = 2; + } + else if (!(m24->ctrl & 1)) + { + video_res_y /= 2; + video_bpp = 1; + } + } + m24->firstline = 1000; + m24->lastline = 0; + m24->blink++; + } + } + else + { + m24->sc++; + m24->sc &= 31; + m24->ma = m24->maback; + } + if ((m24->sc == (m24->crtc[10] & 31) || ((m24->crtc[8] & 3) == 3 && m24->sc == ((m24->crtc[10] & 31) >> 1)))) + m24->con = 1; + } + if (m24->dispon && (m24->cgamode & 1)) + { + for (x = 0; x < (m24->crtc[1] << 1); x++) + m24->charbuffer[x] = m24->vram[(((m24->ma << 1) + x) & 0x3fff) + m24->base]; + } + } +} + +void *m24_init() +{ + int c; + m24_t *m24 = malloc(sizeof(m24_t)); + memset(m24, 0, sizeof(m24_t)); + + m24->vram = malloc(0x8000); + + timer_add(m24_poll, &m24->vidtime, TIMER_ALWAYS_ENABLED, m24); + mem_mapping_add(&m24->mapping, 0xb8000, 0x08000, m24_read, NULL, NULL, m24_write, NULL, NULL, NULL, 0, m24); + io_sethandler(0x03d0, 0x0010, m24_in, NULL, NULL, m24_out, NULL, NULL, m24); + overscan_x = overscan_y = 16; + return m24; +} + +void m24_close(void *p) +{ + m24_t *m24 = (m24_t *)p; + + free(m24->vram); + free(m24); +} + +void m24_speed_changed(void *p) +{ + m24_t *m24 = (m24_t *)p; + + m24_recalctimings(m24); +} + +device_t m24_device = +{ + "Olivetti M24 (video)", + 0, + m24_init, + m24_close, + NULL, + m24_speed_changed, + NULL, + NULL +}; diff --git a/src/vid_olivetti_m24.h b/src/vid_olivetti_m24.h new file mode 100644 index 000000000..8558cc7c6 --- /dev/null +++ b/src/vid_olivetti_m24.h @@ -0,0 +1 @@ +extern device_t m24_device; diff --git a/src/vid_oti067.c b/src/vid_oti067.c new file mode 100644 index 000000000..1c9cc5f33 --- /dev/null +++ b/src/vid_oti067.c @@ -0,0 +1,343 @@ +/*Oak OTI067 emulation*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "video.h" +#include "vid_oti067.h" +#include "vid_svga.h" + +typedef struct oti067_t +{ + svga_t svga; + + rom_t bios_rom; + + int index; + uint8_t regs[32]; + + uint8_t pos; + + uint32_t vram_size; + uint32_t vram_mask; + + uint8_t chip_id; +} oti067_t; + +void oti067_out(uint16_t addr, uint8_t val, void *p) +{ + oti067_t *oti067 = (oti067_t *)p; + svga_t *svga = &oti067->svga; + uint8_t old; + +// pclog("oti067_out : %04X %02X %02X %i\n", addr, val, ram[0x489], ins); + + if ((((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && addr < 0x3de) && !(svga->miscout & 1)) addr ^= 0x60; + + switch (addr) + { + case 0x3D4: + svga->crtcreg = val & 31; + return; + case 0x3D5: + if (svga->crtcreg <= 0x18) + val &= mask_crtc[svga->crtcreg]; + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) + { + if (svga->crtcreg < 0xE || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + + case 0x3DE: + oti067->index = val & 0x1f; + return; + case 0x3DF: + oti067->regs[oti067->index] = val; + switch (oti067->index) + { + case 0xD: + svga->vrammask = (val & 0xc) ? oti067->vram_mask : 0x3ffff; + if ((val & 0x80) && oti067->vram_size == 256) + mem_mapping_disable(&svga->mapping); + else + mem_mapping_enable(&svga->mapping); + if (!(val & 0x80)) + svga->vrammask = 0x3ffff; + break; + case 0x11: + svga->read_bank = (val & 0xf) * 65536; + svga->write_bank = (val >> 4) * 65536; + break; + } + return; + } + svga_out(addr, val, svga); +} + +uint8_t oti067_in(uint16_t addr, void *p) +{ + oti067_t *oti067 = (oti067_t *)p; + svga_t *svga = &oti067->svga; + uint8_t temp; + +// if (addr != 0x3da && addr != 0x3ba) pclog("oti067_in : %04X ", addr); + + if ((((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && addr < 0x3de) && !(svga->miscout & 1)) addr ^= 0x60; + + switch (addr) + { + case 0x3D4: + temp = svga->crtcreg; + break; + case 0x3D5: + temp = svga->crtc[svga->crtcreg]; + break; + + case 0x3DE: + temp = oti067->index | (oti067->chip_id << 5); + // temp = oti067->index | (2 << 5); + break; + case 0x3DF: + if (oti067->index==0x10) temp = 0x18; + else temp = oti067->regs[oti067->index]; + break; + + default: + temp = svga_in(addr, svga); + break; + } +// if (addr != 0x3da && addr != 0x3ba) pclog("%02X %04X:%04X\n", temp, CS,pc); + return temp; +} + +void oti067_pos_out(uint16_t addr, uint8_t val, void *p) +{ + oti067_t *oti067 = (oti067_t *)p; + + if ((val & 8) != (oti067->pos & 8)) + { + if (val & 8) + io_sethandler(0x03c0, 0x0020, oti067_in, NULL, NULL, oti067_out, NULL, NULL, oti067); + else + io_removehandler(0x03c0, 0x0020, oti067_in, NULL, NULL, oti067_out, NULL, NULL, oti067); + } + + oti067->pos = val; +} + +uint8_t oti067_pos_in(uint16_t addr, void *p) +{ + oti067_t *oti067 = (oti067_t *)p; + + return oti067->pos; +} + +void oti067_recalctimings(svga_t *svga) +{ + oti067_t *oti067 = (oti067_t *)svga->p; + + if (oti067->regs[0x14] & 0x08) svga->ma_latch |= 0x10000; + if (oti067->regs[0x0d] & 0x0c) svga->rowoffset <<= 1; + // svga->interlace = oti067->regs[0x14] & 0x80; + if (oti067->regs[0x14] & 0x80) + { + svga->vtotal *= 2; + svga->dispend *= 2; + svga->vblankstart *= 2; + svga->vsyncstart *=2; + svga->split *= 2; + } +} + +void *oti067_common_init(char *bios_fn, int vram_size, int chip_id) +{ + oti067_t *oti067 = malloc(sizeof(oti067_t)); + memset(oti067, 0, sizeof(oti067_t)); + + rom_init(&oti067->bios_rom, bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + oti067->vram_size = vram_size; + oti067->vram_mask = (vram_size << 10) - 1; + + oti067->chip_id = chip_id; + + svga_init(&oti067->svga, oti067, vram_size << 10, + oti067_recalctimings, + oti067_in, oti067_out, + NULL, + NULL); + + io_sethandler(0x03c0, 0x0020, oti067_in, NULL, NULL, oti067_out, NULL, NULL, oti067); + io_sethandler(0x46e8, 0x0001, oti067_pos_in, NULL, NULL, oti067_pos_out, NULL, NULL, oti067); + + oti067->svga.miscout = 1; + return oti067; +} + +void *oti067_init() +{ + int vram_size = device_get_config_int("memory"); + return oti067_common_init("roms/oti067/bios.bin", vram_size, 2); +} + +void *oti077_init() +{ + int vram_size = device_get_config_int("memory"); + return oti067_common_init("roms/oti077.vbi", vram_size, 5); +} + +void *oti067_acer386_init() +{ + oti067_t *oti067 = oti067_common_init("roms/acer386/oti067.bin", 512, 2); + + if (oti067) + oti067->bios_rom.rom[0x5d] = 0x74; + + return oti067; +} + +static int oti067_available() +{ + return rom_present("roms/oti067/bios.bin"); +} + +static int oti077_available() +{ + return rom_present("roms/oti077.vbi"); +} + +void oti067_close(void *p) +{ + oti067_t *oti067 = (oti067_t *)p; + + svga_close(&oti067->svga); + + free(oti067); +} + +void oti067_speed_changed(void *p) +{ + oti067_t *oti067 = (oti067_t *)p; + + svga_recalctimings(&oti067->svga); +} + +void oti067_force_redraw(void *p) +{ + oti067_t *oti067 = (oti067_t *)p; + + oti067->svga.fullchange = changeframecount; +} + +void oti067_add_status_info(char *s, int max_len, void *p) +{ + oti067_t *oti067 = (oti067_t *)p; + + svga_add_status_info(s, max_len, &oti067->svga); +} + +static device_config_t oti067_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "256 kB", + .value = 256 + }, + { + .description = "512 kB", + .value = 512 + }, + { + .description = "" + } + }, + .default_int = 512 + }, + { + .type = -1 + } +}; + +static device_config_t oti077_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "256 kB", + .value = 256 + }, + { + .description = "512 kB", + .value = 512 + }, + { + .description = "1 MB", + .value = 1024 + }, + { + .description = "" + } + }, + .default_int = 1024 + }, + { + .type = -1 + } +}; + +device_t oti067_device = +{ + "Oak OTI-067", + 0, + oti067_init, + oti067_close, + oti067_available, + oti067_speed_changed, + oti067_force_redraw, + oti067_add_status_info, + oti067_config +}; +device_t oti067_acer386_device = +{ + "Oak OTI-067 (Acermate 386SX/25N)", + 0, + oti067_acer386_init, + oti067_close, + oti067_available, + oti067_speed_changed, + oti067_force_redraw, + oti067_add_status_info +}; +device_t oti077_device = +{ + "Oak OTI-077", + 0, + oti077_init, + oti067_close, + oti077_available, + oti067_speed_changed, + oti067_force_redraw, + oti067_add_status_info, + oti077_config +}; diff --git a/src/vid_oti067.h b/src/vid_oti067.h new file mode 100644 index 000000000..2c76fe80c --- /dev/null +++ b/src/vid_oti067.h @@ -0,0 +1,3 @@ +extern device_t oti067_device; +extern device_t oti067_acer386_device; +extern device_t oti077_device; diff --git a/src/vid_paradise.c b/src/vid_paradise.c new file mode 100644 index 000000000..2ea3f399a --- /dev/null +++ b/src/vid_paradise.c @@ -0,0 +1,463 @@ +/*Paradise VGA emulation + + PC2086, PC3086 use PVGA1A + MegaPC uses W90C11A + */ +#include +#include "ibm.h" +#include "device.h" +#include "mem.h" +#include "rom.h" +#include "video.h" +#include "vid_paradise.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "vid_unk_ramdac.h" + +typedef struct paradise_t +{ + svga_t svga; + + rom_t bios_rom; + + enum + { + PVGA1A = 0, + WD90C11 + } type; + + uint32_t read_bank[4], write_bank[4]; +} paradise_t; + +void paradise_write(uint32_t addr, uint8_t val, void *p); +uint8_t paradise_read(uint32_t addr, void *p); +void paradise_remap(paradise_t *paradise); + + +void paradise_out(uint16_t addr, uint8_t val, void *p) +{ + paradise_t *paradise = (paradise_t *)p; + svga_t *svga = ¶dise->svga; + uint8_t old; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; +// output = 3; +// pclog("Paradise out %04X %02X %04X:%04X\n", addr, val, CS, pc); + switch (addr) + { + case 0x3c5: + if (svga->seqaddr > 7) + { + if (paradise->type < WD90C11 || svga->seqregs[6] != 0x48) + return; + svga->seqregs[svga->seqaddr & 0x1f] = val; + if (svga->seqaddr == 0x11) + paradise_remap(paradise); + return; + } + break; + + case 0x3cf: + if (svga->gdcaddr >= 0x9 && svga->gdcaddr < 0xf) + { + if ((svga->gdcreg[0xf] & 7) != 5) + return; + } + if (svga->gdcaddr == 6) + { + if ((svga->gdcreg[6] & 0xc) != (val & 0xc)) + { +// pclog("Write mapping %02X\n", val); + switch (val&0xC) + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + } + svga->gdcreg[6] = val; + paradise_remap(paradise); + return; + } + if (svga->gdcaddr == 0x9 || svga->gdcaddr == 0xa) + { + svga->gdcreg[svga->gdcaddr] = val; + paradise_remap(paradise); + return; + } + if (svga->gdcaddr == 0xe) + { + svga->gdcreg[0xe] = val; + paradise_remap(paradise); + return; + } + break; + + case 0x3D4: + if (paradise->type == PVGA1A) + svga->crtcreg = val & 0x1f; + else + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if (svga->crtcreg <= 0x18) + val &= mask_crtc[svga->crtcreg]; + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + if (svga->crtcreg > 0x29 && (svga->crtc[0x29] & 7) != 5) + return; + if (svga->crtcreg >= 0x31 && svga->crtcreg <= 0x37) + return; + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(¶dise->svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t paradise_in(uint16_t addr, void *p) +{ + paradise_t *paradise = (paradise_t *)p; + svga_t *svga = ¶dise->svga; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + +// if (addr != 0x3da) pclog("Paradise in %04X\n", addr); + switch (addr) + { + case 0x3c2: + return 0x10; + + case 0x3c5: + if (svga->seqaddr > 7) + { + if (paradise->type < WD90C11 || svga->seqregs[6] != 0x48) + return 0xff; + if (svga->seqaddr > 0x12) + return 0xff; + return svga->seqregs[svga->seqaddr & 0x1f]; + } + break; + + case 0x3cf: + if (svga->gdcaddr >= 0x9 && svga->gdcaddr < 0xf) + { + if (svga->gdcreg[0xf] & 0x10) + return 0xff; + switch (svga->gdcaddr) + { + case 0xf: + return (svga->gdcreg[0xf] & 0x17) | 0x80; + } + } + break; + + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + if (svga->crtcreg > 0x29 && svga->crtcreg < 0x30 && (svga->crtc[0x29] & 0x88) != 0x80) + return 0xff; + return svga->crtc[svga->crtcreg]; + } + return svga_in(addr, svga); +} + +void paradise_remap(paradise_t *paradise) +{ + svga_t *svga = ¶dise->svga; + + if (svga->seqregs[0x11] & 0x80) + { +// pclog("Remap 1\n"); + paradise->read_bank[0] = paradise->read_bank[2] = (svga->gdcreg[0x9] & 0x7f) << 12; + paradise->read_bank[1] = paradise->read_bank[3] = ((svga->gdcreg[0x9] & 0x7f) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + paradise->write_bank[0] = paradise->write_bank[2] = (svga->gdcreg[0xa] & 0x7f) << 12; + paradise->write_bank[1] = paradise->write_bank[3] = ((svga->gdcreg[0xa] & 0x7f) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + } + else if (svga->gdcreg[0xe] & 0x08) + { + if (svga->gdcreg[0x6] & 0xc) + { +// pclog("Remap 2\n"); + paradise->read_bank[0] = paradise->read_bank[2] = (svga->gdcreg[0xa] & 0x7f) << 12; + paradise->write_bank[0] = paradise->write_bank[2] = (svga->gdcreg[0xa] & 0x7f) << 12; + paradise->read_bank[1] = paradise->read_bank[3] = ((svga->gdcreg[0x9] & 0x7f) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + paradise->write_bank[1] = paradise->write_bank[3] = ((svga->gdcreg[0x9] & 0x7f) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + } + else + { +// pclog("Remap 3\n"); + paradise->read_bank[0] = paradise->write_bank[0] = (svga->gdcreg[0xa] & 0x7f) << 12; + paradise->read_bank[1] = paradise->write_bank[1] = ((svga->gdcreg[0xa] & 0x7f) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + paradise->read_bank[2] = paradise->write_bank[2] = (svga->gdcreg[0x9] & 0x7f) << 12; + paradise->read_bank[3] = paradise->write_bank[3] = ((svga->gdcreg[0x9] & 0x7f) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + } + } + else + { + // pclog("Remap 4\n"); + paradise->read_bank[0] = paradise->read_bank[2] = (svga->gdcreg[0x9] & 0x7f) << 12; + paradise->read_bank[1] = paradise->read_bank[3] = ((svga->gdcreg[0x9] & 0x7f) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + paradise->write_bank[0] = paradise->write_bank[2] = (svga->gdcreg[0x9] & 0x7f) << 12; + paradise->write_bank[1] = paradise->write_bank[3] = ((svga->gdcreg[0x9] & 0x7f) << 12) + ((svga->gdcreg[6] & 0x08) ? 0 : 0x8000); + } +// pclog("Remap - %04X %04X\n", paradise->read_bank[0], paradise->write_bank[0]); +} + +void paradise_recalctimings(svga_t *svga) +{ + svga->lowres = !(svga->gdcreg[0xe] & 0x01); + if (svga->bpp == 8 && !svga->lowres) + svga->render = svga_render_8bpp_highres; +} + +#define egacycles 1 +#define egacycles2 1 +void paradise_write(uint32_t addr, uint8_t val, void *p) +{ + paradise_t *paradise = (paradise_t *)p; +// pclog("paradise_write : %05X %02X ", addr, val); + addr = (addr & 0x7fff) + paradise->write_bank[(addr >> 15) & 3]; +// pclog("%08X\n", addr); + /* Horrible hack, I know, but it's the only way to fix the 440FX BIOS filling the VRAM with garbage until Tom fixes the memory emulation. */ + if ((cs == 0xE0000) && (cpu_state.pc == 0xBF2F) && (romset == ROM_440FX)) return; + if ((cs == 0xE0000) && (cpu_state.pc == 0xBF77) && (romset == ROM_440FX)) return; + svga_write_linear(addr, val, ¶dise->svga); +} + +uint8_t paradise_read(uint32_t addr, void *p) +{ + paradise_t *paradise = (paradise_t *)p; +// pclog("paradise_read : %05X ", addr); + addr = (addr & 0x7fff) + paradise->read_bank[(addr >> 15) & 3]; +// pclog("%08X\n", addr); + return svga_read_linear(addr, ¶dise->svga); +} + +void *paradise_pvga1a_init() +{ + paradise_t *paradise = malloc(sizeof(paradise_t)); + svga_t *svga = ¶dise->svga; + memset(paradise, 0, sizeof(paradise_t)); + + io_sethandler(0x03c0, 0x0020, paradise_in, NULL, NULL, paradise_out, NULL, NULL, paradise); + + svga_init(¶dise->svga, paradise, 1 << 18, /*256kb*/ + NULL, + paradise_in, paradise_out, + NULL, + NULL); + + mem_mapping_set_handler(¶dise->svga.mapping, paradise_read, NULL, NULL, paradise_write, NULL, NULL); + mem_mapping_set_p(¶dise->svga.mapping, paradise); + + svga->crtc[0x31] = 'W'; + svga->crtc[0x32] = 'D'; + svga->crtc[0x33] = '9'; + svga->crtc[0x34] = '0'; + svga->crtc[0x35] = 'C'; + + svga->bpp = 8; + svga->miscout = 1; + + paradise->type = PVGA1A; + + return paradise; +} + +void *paradise_wd90c11_init() +{ + paradise_t *paradise = malloc(sizeof(paradise_t)); + svga_t *svga = ¶dise->svga; + memset(paradise, 0, sizeof(paradise_t)); + + io_sethandler(0x03c0, 0x0020, paradise_in, NULL, NULL, paradise_out, NULL, NULL, paradise); + + svga_init(¶dise->svga, paradise, 1 << 19, /*512kb*/ + paradise_recalctimings, + paradise_in, paradise_out, + NULL, + NULL); + + mem_mapping_set_handler(¶dise->svga.mapping, paradise_read, NULL, NULL, paradise_write, NULL, NULL); + mem_mapping_set_p(¶dise->svga.mapping, paradise); + + svga->crtc[0x31] = 'W'; + svga->crtc[0x32] = 'D'; + svga->crtc[0x33] = '9'; + svga->crtc[0x34] = '0'; + svga->crtc[0x35] = 'C'; + svga->crtc[0x36] = '1'; + svga->crtc[0x37] = '1'; + + svga->bpp = 8; + svga->miscout = 1; + + paradise->type = WD90C11; + + return paradise; +} + +static void *paradise_pvga1a_pc2086_init() +{ + paradise_t *paradise = paradise_pvga1a_init(); + + if (paradise) + rom_init(¶dise->bios_rom, "roms/pc2086/40186.ic171", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + return paradise; +} +static void *paradise_pvga1a_pc3086_init() +{ + paradise_t *paradise = paradise_pvga1a_init(); + + if (paradise) + rom_init(¶dise->bios_rom, "roms/pc3086/c000.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + return paradise; +} + +static void *paradise_wd90c11_megapc_init() +{ + paradise_t *paradise = paradise_wd90c11_init(); + + if (paradise) + rom_init_interleaved(¶dise->bios_rom, + "roms/megapc/41651-bios lo.u18", + "roms/megapc/211253-bios hi.u19", + 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + return paradise; +} + +static int paradise_wd90c11_standalone_available() +{ + return rom_present("roms/megapc/41651-bios lo.u18") && rom_present("roms/megapc/211253-bios hi.u19"); +} + +static void *cpqvga_init() +{ + paradise_t *paradise = paradise_pvga1a_init(); + + if (paradise) + rom_init(¶dise->bios_rom, "roms/1988-05-18.rom", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + return paradise; +} + +static int cpqvga_standalone_available() +{ + return rom_present("roms/1988-05-18.rom"); +} + +void paradise_close(void *p) +{ + paradise_t *paradise = (paradise_t *)p; + + svga_close(¶dise->svga); + + free(paradise); +} + +void paradise_speed_changed(void *p) +{ + paradise_t *paradise = (paradise_t *)p; + + svga_recalctimings(¶dise->svga); +} + +void paradise_force_redraw(void *p) +{ + paradise_t *paradise = (paradise_t *)p; + + paradise->svga.fullchange = changeframecount; +} + +void paradise_add_status_info(char *s, int max_len, void *p) +{ + paradise_t *paradise = (paradise_t *)p; + + svga_add_status_info(s, max_len, ¶dise->svga); +} + +device_t paradise_pvga1a_pc2086_device = +{ + "Paradise PVGA1A (Amstrad PC2086)", + 0, + paradise_pvga1a_pc2086_init, + paradise_close, + NULL, + paradise_speed_changed, + paradise_force_redraw, + paradise_add_status_info +}; +device_t paradise_pvga1a_pc3086_device = +{ + "Paradise PVGA1A (Amstrad PC3086)", + 0, + paradise_pvga1a_pc3086_init, + paradise_close, + NULL, + paradise_speed_changed, + paradise_force_redraw, + paradise_add_status_info +}; +device_t paradise_wd90c11_megapc_device = +{ + "Paradise WD90C11 (Amstrad MegaPC)", + 0, + paradise_wd90c11_megapc_init, + paradise_close, + NULL, + paradise_speed_changed, + paradise_force_redraw, + paradise_add_status_info +}; +device_t paradise_wd90c11_device = +{ + "Paradise WD90C11", + 0, + paradise_wd90c11_megapc_init, + paradise_close, + paradise_wd90c11_standalone_available, + paradise_speed_changed, + paradise_force_redraw, + paradise_add_status_info +}; +device_t cpqvga_device = +{ + "Compaq/Paradise VGA", + 0, + cpqvga_init, + paradise_close, + cpqvga_standalone_available, + paradise_speed_changed, + paradise_force_redraw, + paradise_add_status_info +}; diff --git a/src/vid_paradise.h b/src/vid_paradise.h new file mode 100644 index 000000000..44d74dd4a --- /dev/null +++ b/src/vid_paradise.h @@ -0,0 +1,5 @@ +extern device_t paradise_pvga1a_pc2086_device; +extern device_t paradise_pvga1a_pc3086_device; +extern device_t paradise_wd90c11_megapc_device; +extern device_t paradise_wd90c11_device; +extern device_t cpqvga_device; diff --git a/src/vid_pc1512.c b/src/vid_pc1512.c new file mode 100644 index 000000000..8beef9074 --- /dev/null +++ b/src/vid_pc1512.c @@ -0,0 +1,494 @@ +/*PC1512 CGA emulation + + The PC1512 extends CGA with a bit-planar 640x200x16 mode. + + Most CRTC registers are fixed. + + The Technical Reference Manual lists the video waitstate time as between 12 + and 46 cycles. PCem currently always uses the lower number.*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "timer.h" +#include "video.h" +#include "vid_pc1512.h" + +typedef struct pc1512_t +{ + mem_mapping_t mapping; + + uint8_t crtc[32]; + int crtcreg; + + uint8_t cgacol, cgamode, stat; + + uint8_t plane_write, plane_read, border; + + int linepos, displine; + int sc, vc; + int cgadispon; + int con, coff, cursoron, cgablink; + int vsynctime, vadj; + uint16_t ma, maback; + int dispon; + int blink; + + int dispontime, dispofftime, vidtime; + int firstline, lastline; + + uint8_t *vram; +} pc1512_t; + +static uint8_t crtcmask[32] = +{ + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static void pc1512_recalctimings(pc1512_t *pc1512); + +static void pc1512_out(uint16_t addr, uint8_t val, void *p) +{ + pc1512_t *pc1512 = (pc1512_t *)p; + uint8_t old; +// pclog("PC1512 out %04X %02X %04X:%04X\n",addr,val,CS,pc); + switch (addr) + { + case 0x3d4: + pc1512->crtcreg = val & 31; + return; + case 0x3d5: + old = pc1512->crtc[pc1512->crtcreg]; + pc1512->crtc[pc1512->crtcreg] = val & crtcmask[pc1512->crtcreg]; + if (old != val) + { + if (pc1512->crtcreg < 0xe || pc1512->crtcreg > 0x10) + { + fullchange = changeframecount; + pc1512_recalctimings(pc1512); + } + } + return; + case 0x3d8: + if ((val & 0x12) == 0x12 && (pc1512->cgamode & 0x12) != 0x12) + { + pc1512->plane_write = 0xf; + pc1512->plane_read = 0; + } + pc1512->cgamode = val; + return; + case 0x3d9: + pc1512->cgacol = val; + return; + case 0x3dd: + pc1512->plane_write = val; + return; + case 0x3de: + pc1512->plane_read = val & 3; + return; + case 0x3df: + pc1512->border = val; + return; + } +} + +static uint8_t pc1512_in(uint16_t addr, void *p) +{ + pc1512_t *pc1512 = (pc1512_t *)p; +// pclog("PC1512 in %04X %02X %04X:%04X\n",addr,CS,pc); + switch (addr) + { + case 0x3d4: + return pc1512->crtcreg; + case 0x3d5: + return pc1512->crtc[pc1512->crtcreg]; + case 0x3da: + return pc1512->stat; + } + return 0xff; +} + +static void pc1512_write(uint32_t addr, uint8_t val, void *p) +{ + pc1512_t *pc1512 = (pc1512_t *)p; + + egawrites++; + cycles -= 12; + addr &= 0x3fff; + + if ((pc1512->cgamode & 0x12) == 0x12) + { + if (pc1512->plane_write & 1) pc1512->vram[addr] = val; + if (pc1512->plane_write & 2) pc1512->vram[addr | 0x4000] = val; + if (pc1512->plane_write & 4) pc1512->vram[addr | 0x8000] = val; + if (pc1512->plane_write & 8) pc1512->vram[addr | 0xc000] = val; + } + else + pc1512->vram[addr] = val; +} + +static uint8_t pc1512_read(uint32_t addr, void *p) +{ + pc1512_t *pc1512 = (pc1512_t *)p; + + egareads++; + cycles -= 12; + addr &= 0x3fff; + + if ((pc1512->cgamode & 0x12) == 0x12) + return pc1512->vram[addr | (pc1512->plane_read << 14)]; + return pc1512->vram[addr]; +} + + +static void pc1512_recalctimings(pc1512_t *pc1512) +{ + double _dispontime, _dispofftime, disptime; + disptime = 128; /*Fixed on PC1512*/ + _dispontime = 80; + _dispofftime = disptime - _dispontime; +// printf("%i %f %f %f %i %i\n",cgamode&1,disptime,dispontime,dispofftime,crtc[0],crtc[1]); + _dispontime *= CGACONST; + _dispofftime *= CGACONST; +// printf("Timings - on %f off %f frame %f second %f\n",dispontime,dispofftime,(dispontime+dispofftime)*262.0,(dispontime+dispofftime)*262.0*59.92); + pc1512->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + pc1512->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + +static void pc1512_poll(void *p) +{ + pc1512_t *pc1512 = (pc1512_t *)p; + uint16_t ca = (pc1512->crtc[15] | (pc1512->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + uint16_t dat, dat2, dat3, dat4; + int cols[4]; + int col; + int oldsc; + + if (!pc1512->linepos) + { + pc1512->vidtime += pc1512->dispofftime; + pc1512->stat |= 1; + pc1512->linepos = 1; + oldsc = pc1512->sc; + if (pc1512->dispon) + { + if (pc1512->displine < pc1512->firstline) + pc1512->firstline = pc1512->displine; + pc1512->lastline = pc1512->displine; + for (c = 0; c < 8; c++) + { + if ((pc1512->cgamode & 0x12) == 0x12) + { + buffer->line[pc1512->displine][c] = (pc1512->border & 15) + 16; + if (pc1512->cgamode & 1) buffer->line[pc1512->displine][c + (pc1512->crtc[1] << 3) + 8] = 0; + else buffer->line[pc1512->displine][c + (pc1512->crtc[1] << 4) + 8] = 0; + } + else + { + buffer->line[pc1512->displine][c] = (pc1512->cgacol & 15) + 16; + if (pc1512->cgamode & 1) buffer->line[pc1512->displine][c + (pc1512->crtc[1] << 3) + 8] = (pc1512->cgacol & 15) + 16; + else buffer->line[pc1512->displine][c + (pc1512->crtc[1] << 4) + 8] = (pc1512->cgacol & 15) + 16; + } + } + if (pc1512->cgamode & 1) + { + for (x = 0; x < 80; x++) + { + chr = pc1512->vram[ ((pc1512->ma << 1) & 0x3fff)]; + attr = pc1512->vram[(((pc1512->ma << 1) + 1) & 0x3fff)]; + drawcursor = ((pc1512->ma == ca) && pc1512->con && pc1512->cursoron); + if (pc1512->cgamode & 0x20) + { + cols[1] = (attr & 15) + 16; + cols[0] = ((attr >> 4) & 7) + 16; + if ((pc1512->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } + else + { + cols[1] = (attr & 15) + 16; + cols[0] = (attr >> 4) + 16; + } + if (drawcursor) + { + for (c = 0; c < 8; c++) + buffer->line[pc1512->displine][(x << 3) + c + 8] = cols[(fontdat[chr][pc1512->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[pc1512->displine][(x << 3) + c + 8] = cols[(fontdat[chr][pc1512->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + pc1512->ma++; + } + } + else if (!(pc1512->cgamode & 2)) + { + for (x = 0; x < 40; x++) + { + chr = pc1512->vram[ ((pc1512->ma << 1) & 0x3fff)]; + attr = pc1512->vram[(((pc1512->ma << 1) + 1) & 0x3fff)]; + drawcursor = ((pc1512->ma == ca) && pc1512->con && pc1512->cursoron); + if (pc1512->cgamode & 0x20) + { + cols[1] = (attr & 15) + 16; + cols[0] = ((attr >> 4) & 7) + 16; + if ((pc1512->blink & 16) && (attr & 0x80)) + cols[1] = cols[0]; + } + else + { + cols[1] = (attr & 15) + 16; + cols[0] = (attr >> 4) + 16; + } + pc1512->ma++; + if (drawcursor) + { + for (c = 0; c < 8; c++) + buffer->line[pc1512->displine][(x << 4) + (c << 1) + 8] = + buffer->line[pc1512->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][pc1512->sc & 7] & (1 << (c ^ 7))) ? 1 : 0] ^ 15; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[pc1512->displine][(x << 4) + (c << 1) + 8] = + buffer->line[pc1512->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][pc1512->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + } + } + else if (!(pc1512->cgamode&16)) + { + cols[0] = (pc1512->cgacol & 15) | 16; + col = (pc1512->cgacol & 16) ? 24 : 16; + if (pc1512->cgamode & 4) + { + cols[1] = col | 3; + cols[2] = col | 4; + cols[3] = col | 7; + } + else if (pc1512->cgacol & 32) + { + cols[1] = col | 3; + cols[2] = col | 5; + cols[3] = col | 7; + } + else + { + cols[1] = col | 2; + cols[2] = col | 4; + cols[3] = col | 6; + } + for (x = 0; x < 40; x++) + { + dat = (pc1512->vram[((pc1512->ma << 1) & 0x1fff) + ((pc1512->sc & 1) * 0x2000)] << 8) | pc1512->vram[((pc1512->ma << 1) & 0x1fff) + ((pc1512->sc & 1) * 0x2000) + 1]; + pc1512->ma++; + for (c = 0; c < 8; c++) + { + buffer->line[pc1512->displine][(x << 4) + (c << 1) + 8] = + buffer->line[pc1512->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + dat <<= 2; + } + } + } + else + { + for (x = 0; x < 40; x++) + { + ca = ((pc1512->ma << 1) & 0x1fff) + ((pc1512->sc & 1) * 0x2000); + dat = (pc1512->vram[ca] << 8) | pc1512->vram[ca + 1]; + dat2 = (pc1512->vram[ca + 0x4000] << 8) | pc1512->vram[ca + 0x4001]; + dat3 = (pc1512->vram[ca + 0x8000] << 8) | pc1512->vram[ca + 0x8001]; + dat4 = (pc1512->vram[ca + 0xc000] << 8) | pc1512->vram[ca + 0xc001]; + + pc1512->ma++; + for (c = 0; c < 16; c++) + { + buffer->line[pc1512->displine][(x << 4) + c + 8] = (((dat >> 15) | ((dat2 >> 15) << 1) | ((dat3 >> 15) << 2) | ((dat4 >> 15) << 3)) & (pc1512->cgacol & 15)) + 16; + dat <<= 1; + dat2 <<= 1; + dat3 <<= 1; + dat4 <<= 1; + } + } + } + } + else + { + cols[0] = ((pc1512->cgamode & 0x12) == 0x12) ? 0 : (pc1512->cgacol & 15) + 16; + if (pc1512->cgamode & 1) hline(buffer, 0, pc1512->displine, (pc1512->crtc[1] << 3) + 16, cols[0]); + else hline(buffer, 0, pc1512->displine, (pc1512->crtc[1] << 4) + 16, cols[0]); + } + + pc1512->sc = oldsc; + if (pc1512->vsynctime) + pc1512->stat |= 8; + pc1512->displine++; + if (pc1512->displine >= 360) + pc1512->displine = 0; +// pclog("Line %i %i %i %i %i %i\n",displine,cgadispon,firstline,lastline,vc,sc); + } + else + { + pc1512->vidtime += pc1512->dispontime; + if ((pc1512->lastline - pc1512->firstline) == 199) + pc1512->dispon = 0; /*Amstrad PC1512 always displays 200 lines, regardless of CRTC settings*/ + if (pc1512->dispon) + pc1512->stat &= ~1; + pc1512->linepos = 0; + if (pc1512->vsynctime) + { + pc1512->vsynctime--; + if (!pc1512->vsynctime) + pc1512->stat &= ~8; + } + if (pc1512->sc == (pc1512->crtc[11] & 31)) + { + pc1512->con = 0; + pc1512->coff = 1; + } + if (pc1512->vadj) + { + pc1512->sc++; + pc1512->sc &= 31; + pc1512->ma = pc1512->maback; + pc1512->vadj--; + if (!pc1512->vadj) + { + pc1512->dispon = 1; + pc1512->ma = pc1512->maback = (pc1512->crtc[13] | (pc1512->crtc[12] << 8)) & 0x3fff; + pc1512->sc = 0; + } + } + else if (pc1512->sc == pc1512->crtc[9]) + { + pc1512->maback = pc1512->ma; + pc1512->sc = 0; + oldvc = pc1512->vc; + pc1512->vc++; + pc1512->vc &= 127; + + if (pc1512->displine == 32)//oldvc == (cgamode & 2) ? 127 : 31) + { + pc1512->vc = 0; + pc1512->vadj = 6; + if ((pc1512->crtc[10] & 0x60) == 0x20) pc1512->cursoron = 0; + else pc1512->cursoron = pc1512->blink & 16; + } + + if (pc1512->displine >= 262)//vc == (cgamode & 2) ? 111 : 27) + { + pc1512->dispon = 0; + pc1512->displine = 0; + pc1512->vsynctime = 46; + + if (pc1512->cgamode&1) x = (pc1512->crtc[1] << 3) + 16; + else x = (pc1512->crtc[1] << 4) + 16; + x = 640 + 16; + pc1512->lastline++; + + if (x != xsize || (pc1512->lastline - pc1512->firstline) != ysize) + { + xsize = x; + ysize = pc1512->lastline - pc1512->firstline; + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + updatewindowsize(xsize, (ysize << 1) + 16); + } +startblit(); + video_blit_memtoscreen_8(0, pc1512->firstline - 4, xsize, (pc1512->lastline - pc1512->firstline) + 8); +// blit(buffer,vbuf,0,firstline-4,0,0,xsize,(lastline-firstline)+8+1); +// if (vid_resize) stretch_blit(vbuf,screen,0,0,xsize,(lastline-firstline)+8+1,0,0,winsizex,winsizey); +// else stretch_blit(vbuf,screen,0,0,xsize,(lastline-firstline)+8+1,0,0,xsize,((lastline-firstline)<<1)+16+2); +// if (readflash) rectfill(screen,winsizex-40,8,winsizex-8,14,0xFFFFFFFF); +// readflash=0; +endblit(); + video_res_x = xsize - 16; + video_res_y = ysize; + if (pc1512->cgamode & 1) + { + video_res_x /= 8; + video_res_y /= pc1512->crtc[9] + 1; + video_bpp = 0; + } + else if (!(pc1512->cgamode & 2)) + { + video_res_x /= 16; + video_res_y /= pc1512->crtc[9] + 1; + video_bpp = 0; + } + else if (!(pc1512->cgamode & 16)) + { + video_res_x /= 2; + video_bpp = 2; + } + else + { + video_bpp = 4; + } + + pc1512->firstline = 1000; + pc1512->lastline = 0; + pc1512->blink++; + } + } + else + { + pc1512->sc++; + pc1512->sc &= 31; + pc1512->ma = pc1512->maback; + } + if (pc1512->sc == (pc1512->crtc[10] & 31)) + pc1512->con = 1; + } +} + +static void *pc1512_init() +{ + int c; + pc1512_t *pc1512 = malloc(sizeof(pc1512_t)); + memset(pc1512, 0, sizeof(pc1512_t)); + + pc1512->vram = malloc(0x10000); + + pc1512->cgacol = 7; + pc1512->cgamode = 0x12; + + timer_add(pc1512_poll, &pc1512->vidtime, TIMER_ALWAYS_ENABLED, pc1512); + mem_mapping_add(&pc1512->mapping, 0xb8000, 0x08000, pc1512_read, NULL, NULL, pc1512_write, NULL, NULL, NULL, 0, pc1512); + io_sethandler(0x03d0, 0x0010, pc1512_in, NULL, NULL, pc1512_out, NULL, NULL, pc1512); + overscan_x = overscan_y = 16; + return pc1512; +} + +static void pc1512_close(void *p) +{ + pc1512_t *pc1512 = (pc1512_t *)p; + + free(pc1512->vram); + free(pc1512); +} + +static void pc1512_speed_changed(void *p) +{ + pc1512_t *pc1512 = (pc1512_t *)p; + + pc1512_recalctimings(pc1512); +} + +device_t pc1512_device = +{ + "Amstrad PC1512 (video)", + 0, + pc1512_init, + pc1512_close, + NULL, + pc1512_speed_changed, + NULL, + NULL +}; diff --git a/src/vid_pc1512.h b/src/vid_pc1512.h new file mode 100644 index 000000000..fec42d6cd --- /dev/null +++ b/src/vid_pc1512.h @@ -0,0 +1 @@ +extern device_t pc1512_device; diff --git a/src/vid_pc1640.c b/src/vid_pc1640.c new file mode 100644 index 000000000..963e74813 --- /dev/null +++ b/src/vid_pc1640.c @@ -0,0 +1,164 @@ +/*PC1640 video emulation. + Mostly standard EGA, but with CGA & Hercules emulation*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "timer.h" +#include "video.h" +#include "vid_cga.h" +#include "vid_ega.h" +#include "vid_pc1640.h" + +typedef struct pc1640_t +{ + mem_mapping_t cga_mapping; + mem_mapping_t ega_mapping; + + cga_t cga; + ega_t ega; + + rom_t bios_rom; + + int cga_enabled; + int dispontime, dispofftime, vidtime; +} pc1640_t; + +void pc1640_out(uint16_t addr, uint8_t val, void *p) +{ + pc1640_t *pc1640 = (pc1640_t *)p; + + switch (addr) + { + case 0x3db: + pc1640->cga_enabled = val & 0x40; + if (pc1640->cga_enabled) + { + mem_mapping_enable(&pc1640->cga_mapping); + mem_mapping_disable(&pc1640->ega_mapping); + } + else + { + mem_mapping_disable(&pc1640->cga_mapping); + switch (pc1640->ega.gdcreg[6] & 0xc) + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&pc1640->ega_mapping, 0xa0000, 0x20000); + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&pc1640->ega_mapping, 0xa0000, 0x10000); + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&pc1640->ega_mapping, 0xb0000, 0x08000); + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&pc1640->ega_mapping, 0xb8000, 0x08000); + break; + } + } + pclog("3DB write %02X\n", val); + return; + } + if (pc1640->cga_enabled) cga_out(addr, val, &pc1640->cga); + else ega_out(addr, val, &pc1640->ega); +} + +uint8_t pc1640_in(uint16_t addr, void *p) +{ + pc1640_t *pc1640 = (pc1640_t *)p; + + switch (addr) + { + } + + if (pc1640->cga_enabled) return cga_in(addr, &pc1640->cga); + else return ega_in(addr, &pc1640->ega); +} + +void pc1640_recalctimings(pc1640_t *pc1640) +{ + cga_recalctimings(&pc1640->cga); + ega_recalctimings(&pc1640->ega); + if (pc1640->cga_enabled) + { + overscan_x = overscan_y = 16; + pc1640->dispontime = pc1640->cga.dispontime; + pc1640->dispofftime = pc1640->cga.dispofftime; + } + else + { + overscan_x = 16; overscan_y = 28; + pc1640->dispontime = pc1640->ega.dispontime; + pc1640->dispofftime = pc1640->ega.dispofftime; + } +} + +void pc1640_poll(void *p) +{ + pc1640_t *pc1640 = (pc1640_t *)p; + if (pc1640->cga_enabled) + { + overscan_x = overscan_y = 16; + pc1640->cga.vidtime = pc1640->vidtime; + cga_poll(&pc1640->cga); + pc1640->vidtime = pc1640->cga.vidtime; + } + else + { + overscan_x = 16; overscan_y = 28; + pc1640->ega.vidtime = pc1640->vidtime; + ega_poll(&pc1640->ega); + pc1640->vidtime = pc1640->ega.vidtime; + } +} + +void *pc1640_init() +{ + pc1640_t *pc1640 = malloc(sizeof(pc1640_t)); + cga_t *cga = &pc1640->cga; + ega_t *ega = &pc1640->ega; + memset(pc1640, 0, sizeof(pc1640_t)); + + rom_init(&pc1640->bios_rom, "roms/pc1640/40100", 0xc0000, 0x8000, 0x7fff, 0, 0); + + ega_init(&pc1640->ega); + pc1640->cga.vram = pc1640->ega.vram; + pc1640->cga_enabled = 1; + cga_init(&pc1640->cga); + + timer_add(pc1640_poll, &pc1640->vidtime, TIMER_ALWAYS_ENABLED, pc1640); + mem_mapping_add(&pc1640->cga_mapping, 0xb8000, 0x08000, cga_read, NULL, NULL, cga_write, NULL, NULL, NULL, 0, cga); + mem_mapping_add(&pc1640->ega_mapping, 0, 0, ega_read, NULL, NULL, ega_write, NULL, NULL, NULL, 0, ega); + io_sethandler(0x03a0, 0x0040, pc1640_in, NULL, NULL, pc1640_out, NULL, NULL, pc1640); + overscan_x = overscan_y = 16; + return pc1640; +} + +void pc1640_close(void *p) +{ + pc1640_t *pc1640 = (pc1640_t *)p; + + free(pc1640->ega.vram); + free(pc1640); +} + +void pc1640_speed_changed(void *p) +{ + pc1640_t *pc1640 = (pc1640_t *)p; + + pc1640_recalctimings(pc1640); +} + +device_t pc1640_device = +{ + "Amstrad PC1640 (video)", + 0, + pc1640_init, + pc1640_close, + NULL, + pc1640_speed_changed, + NULL, + NULL +}; diff --git a/src/vid_pc1640.h b/src/vid_pc1640.h new file mode 100644 index 000000000..c836fd400 --- /dev/null +++ b/src/vid_pc1640.h @@ -0,0 +1 @@ +extern device_t pc1640_device; diff --git a/src/vid_pc200.c b/src/vid_pc200.c new file mode 100644 index 000000000..414ccae28 --- /dev/null +++ b/src/vid_pc200.c @@ -0,0 +1,146 @@ +/*PC200 video emulation. + CGA with some NMI stuff. But we don't need that as it's only used for TV and + LCD displays, and we're emulating a CRT*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "timer.h" +#include "video.h" +#include "vid_cga.h" +#include "vid_pc200.h" + +typedef struct pc200_t +{ + mem_mapping_t mapping; + + cga_t cga; + + uint8_t reg_3dd, reg_3de, reg_3df; +} pc200_t; + +static uint8_t crtcmask[32] = +{ + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +void pc200_out(uint16_t addr, uint8_t val, void *p) +{ + pc200_t *pc200 = (pc200_t *)p; + cga_t *cga = &pc200->cga; + uint8_t old; + + switch (addr) + { + case 0x3d5: + if (!(pc200->reg_3de & 0x40) && cga->crtcreg <= 11) + { + if (pc200->reg_3de & 0x80) + nmi = 1; + + pc200->reg_3dd = 0x20 | (cga->crtcreg & 0x1f); + pc200->reg_3df = val; + return; + } + old = cga->crtc[cga->crtcreg]; + cga->crtc[cga->crtcreg] = val & crtcmask[cga->crtcreg]; + if (old != val) + { + if (cga->crtcreg < 0xe || cga->crtcreg > 0x10) + { + fullchange = changeframecount; + cga_recalctimings(cga); + } + } + return; + + case 0x3d8: + old = cga->cgamode; + cga->cgamode = val; + if ((cga->cgamode ^ old) & 3) + cga_recalctimings(cga); + pc200->reg_3dd |= 0x80; + if (pc200->reg_3de & 0x80) + nmi = 1; + return; + + case 0x3de: + pc200->reg_3de = val; + pc200->reg_3dd = 0x1f; + if (val & 0x80) + pc200->reg_3dd |= 0x40; + return; + } + cga_out(addr, val, cga); +} + +uint8_t pc200_in(uint16_t addr, void *p) +{ + pc200_t *pc200 = (pc200_t *)p; + cga_t *cga = &pc200->cga; + uint8_t temp; + + switch (addr) + { + case 0x3D8: + return cga->cgamode; + + case 0x3DD: + temp = pc200->reg_3dd; + pc200->reg_3dd &= 0x1f; + nmi = 0; + return temp; + + case 0x3DE: + return (pc200->reg_3de & 0xc7) | 0x10; /*External CGA*/ + + case 0x3DF: + return pc200->reg_3df; + } + return cga_in(addr, cga); +} + +void *pc200_init() +{ + pc200_t *pc200 = malloc(sizeof(pc200_t)); + cga_t *cga = &pc200->cga; + memset(pc200, 0, sizeof(pc200_t)); + + pc200->cga.vram = malloc(0x4000); + cga_init(&pc200->cga); + + timer_add(cga_poll, &cga->vidtime, TIMER_ALWAYS_ENABLED, cga); + mem_mapping_add(&pc200->mapping, 0xb8000, 0x08000, cga_read, NULL, NULL, cga_write, NULL, NULL, NULL, 0, cga); + io_sethandler(0x03d0, 0x0010, pc200_in, NULL, NULL, pc200_out, NULL, NULL, pc200); + overscan_x = overscan_y = 16; + return pc200; +} + +void pc200_close(void *p) +{ + pc200_t *pc200 = (pc200_t *)p; + + free(pc200->cga.vram); + free(pc200); +} + +void pc200_speed_changed(void *p) +{ + pc200_t *pc200 = (pc200_t *)p; + + cga_recalctimings(&pc200->cga); +} + +device_t pc200_device = +{ + "Amstrad PC200 (video)", + 0, + pc200_init, + pc200_close, + NULL, + pc200_speed_changed, + NULL, + NULL +}; diff --git a/src/vid_pc200.h b/src/vid_pc200.h new file mode 100644 index 000000000..cbb2cb58c --- /dev/null +++ b/src/vid_pc200.h @@ -0,0 +1 @@ +extern device_t pc200_device; diff --git a/src/vid_pcjr.c b/src/vid_pcjr.c new file mode 100644 index 000000000..a35da6d80 --- /dev/null +++ b/src/vid_pcjr.c @@ -0,0 +1,647 @@ +#include +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "timer.h" +#include "video.h" +#include "vid_pcjr.h" + +static int i_filt[8],q_filt[8]; + +typedef struct pcjr_t +{ + mem_mapping_t mapping; + + uint8_t crtc[32]; + int crtcreg; + + int array_index; + uint8_t array[32]; + int array_ff; + int memctrl;//=-1; + uint8_t stat; + int addr_mode; + + uint8_t *vram, *b8000; + + int linepos, displine; + int sc, vc; + int dispon; + int con, coff, cursoron, blink; + int vsynctime, vadj; + uint16_t ma, maback; + + int dispontime, dispofftime, vidtime; + int firstline, lastline; +} pcjr_t; + +static uint8_t crtcmask[32] = +{ + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +void pcjr_recalcaddress(pcjr_t *pcjr); +void pcjr_recalctimings(pcjr_t *pcjr); + +void pcjr_out(uint16_t addr, uint8_t val, void *p) +{ + pcjr_t *pcjr = (pcjr_t *)p; + uint8_t old; +// pclog("pcjr OUT %04X %02X\n",addr,val); + switch (addr) + { + case 0x3d4: + pcjr->crtcreg = val & 0x1f; + return; + case 0x3d5: +// pclog("CRTC write %02X %02x\n", pcjr->crtcreg, val); + old = pcjr->crtc[pcjr->crtcreg]; + pcjr->crtc[pcjr->crtcreg] = val & crtcmask[pcjr->crtcreg]; + if (old != val) + { + if (pcjr->crtcreg < 0xe || pcjr->crtcreg > 0x10) + { + fullchange = changeframecount; + pcjr_recalctimings(pcjr); + } + } + return; + case 0x3da: +// pclog("Array write %02X %02X\n", pcjr->array_index, val); + if (!pcjr->array_ff) + pcjr->array_index = val & 0x1f; + else + { + if (pcjr->array_index & 0x10) + val &= 0x0f; + pcjr->array[pcjr->array_index & 0x1f] = val; + } + pcjr->array_ff = !pcjr->array_ff; + break; + case 0x3df: + pcjr->memctrl = val; + pcjr->addr_mode = val >> 6; + pcjr_recalcaddress(pcjr); + break; + } +} + +uint8_t pcjr_in(uint16_t addr, void *p) +{ + pcjr_t *pcjr = (pcjr_t *)p; +// if (addr!=0x3DA) pclog("pcjr IN %04X\n",addr); + switch (addr) + { + case 0x3d4: + return pcjr->crtcreg; + case 0x3d5: + return pcjr->crtc[pcjr->crtcreg]; + case 0x3da: + pcjr->array_ff = 0; + pcjr->stat ^= 0x10; + return pcjr->stat; + } + return 0xFF; +} + +void pcjr_recalcaddress(pcjr_t *pcjr) +{ + if ((pcjr->memctrl & 0xc0) == 0xc0) + { + pcjr->vram = &ram[(pcjr->memctrl & 0x06) << 14]; + pcjr->b8000 = &ram[(pcjr->memctrl & 0x30) << 11]; +// printf("VRAM at %05X B8000 at %05X\n",((pcjr->memctrl&0x6)<<14)+pcjr->base,((pcjr->memctrl&0x30)<<11)+pcjr->base); + } + else + { + pcjr->vram = &ram[(pcjr->memctrl & 0x07) << 14]; + pcjr->b8000 = &ram[(pcjr->memctrl & 0x38) << 11]; +// printf("VRAM at %05X B8000 at %05X\n",((pcjr->memctrl&0x7)<<14)+pcjr->base,((pcjr->memctrl&0x38)<<11)+pcjr->base); + } +} + +void pcjr_write(uint32_t addr, uint8_t val, void *p) +{ + pcjr_t *pcjr = (pcjr_t *)p; + if (pcjr->memctrl == -1) + return; + + egawrites++; +// pclog("pcjr VRAM write %05X %02X %04X:%04X %04X:%04X\n",addr,val,CS,pc,DS,SI); + pcjr->b8000[addr & 0x3fff] = val; +} + +uint8_t pcjr_read(uint32_t addr, void *p) +{ + pcjr_t *pcjr = (pcjr_t *)p; + if (pcjr->memctrl == -1) + return 0xff; + + egareads++; +// pclog("pcjr VRAM read %05X %02X %04X:%04X\n",addr,pcjr->b8000[addr&0x7FFF],CS,pc); + return pcjr->b8000[addr & 0x3fff]; +} + +void pcjr_recalctimings(pcjr_t *pcjr) +{ + double _dispontime, _dispofftime, disptime; + if (pcjr->array[0] & 1) + { + disptime = pcjr->crtc[0] + 1; + _dispontime = pcjr->crtc[1]; + } + else + { + disptime = (pcjr->crtc[0] + 1) << 1; + _dispontime = pcjr->crtc[1] << 1; + } + _dispofftime = disptime - _dispontime; + _dispontime *= CGACONST; + _dispofftime *= CGACONST; + pcjr->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + pcjr->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + + +static int ntsc_col[8][8]= +{ + {0,0,0,0,0,0,0,0}, /*Black*/ + {0,0,1,1,1,1,0,0}, /*Blue*/ + {1,0,0,0,0,1,1,1}, /*Green*/ + {0,0,0,0,1,1,1,1}, /*Cyan*/ + {1,1,1,1,0,0,0,0}, /*Red*/ + {0,1,1,1,1,0,0,0}, /*Magenta*/ + {1,1,0,0,0,0,1,1}, /*Yellow*/ + {1,1,1,1,1,1,1,1} /*White*/ +}; + +/*static int cga4pal[8][4]= +{ + {0,2,4,6},{0,3,5,7},{0,3,4,7},{0,3,4,7}, + {0,10,12,14},{0,11,13,15},{0,11,12,15},{0,11,12,15} +};*/ + +void pcjr_poll(void *p) +{ +// int *cgapal=cga4pal[((pcjr->col&0x10)>>2)|((cgamode&4)>>1)|((cgacol&0x20)>>5)]; + pcjr_t *pcjr = (pcjr_t *)p; + uint16_t ca = (pcjr->crtc[15] | (pcjr->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + uint16_t dat; + int cols[4]; + int col; + int oldsc; + int y_buf[8] = {0, 0, 0, 0, 0, 0, 0, 0}, y_val, y_tot; + int i_buf[8] = {0, 0, 0, 0, 0, 0, 0, 0}, i_val, i_tot; + int q_buf[8] = {0, 0, 0, 0, 0, 0, 0, 0}, q_val, q_tot; + int r, g, b; + if (!pcjr->linepos) + { +// cgapal[0]=pcjr->col&15; +// printf("Firstline %i Lastline %i pcjr->displine %i\n",firstline,lastline,pcjr->displine); + pcjr->vidtime += pcjr->dispofftime; + pcjr->stat &= ~1; + pcjr->linepos = 1; + oldsc = pcjr->sc; + if ((pcjr->crtc[8] & 3) == 3) + pcjr->sc = (pcjr->sc << 1) & 7; + if (pcjr->dispon) + { + uint16_t offset = 0; + uint16_t mask = 0x1fff; + + if (pcjr->displine < pcjr->firstline) + pcjr->firstline = pcjr->displine; + pcjr->lastline = pcjr->displine; + cols[0] = (pcjr->array[2] & 0xf) + 16; + for (c = 0; c < 8; c++) + { + buffer->line[pcjr->displine][c] = cols[0]; + if (pcjr->array[0] & 1) buffer->line[pcjr->displine][c + (pcjr->crtc[1] << 3) + 8] = cols[0]; + else buffer->line[pcjr->displine][c + (pcjr->crtc[1] << 4) + 8] = cols[0]; + } + + switch (pcjr->addr_mode) + { + case 0: /*Alpha*/ + offset = 0; + mask = 0x3fff; + break; + case 1: /*Low resolution graphics*/ + offset = (pcjr->sc & 1) * 0x2000; + break; + case 3: /*High resolution graphics*/ + offset = (pcjr->sc & 3) * 0x2000; + break; + } + switch ((pcjr->array[0] & 0x13) | ((pcjr->array[3] & 0x08) << 5)) + { + case 0x13: /*320x200x16*/ + for (x = 0; x < pcjr->crtc[1]; x++) + { + dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | + pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + pcjr->ma++; + buffer->line[pcjr->displine][(x << 3) + 8] = + buffer->line[pcjr->displine][(x << 3) + 9] = pcjr->array[((dat >> 12) & pcjr->array[1]) + 16] + 16; + buffer->line[pcjr->displine][(x << 3) + 10] = + buffer->line[pcjr->displine][(x << 3) + 11] = pcjr->array[((dat >> 8) & pcjr->array[1]) + 16] + 16; + buffer->line[pcjr->displine][(x << 3) + 12] = + buffer->line[pcjr->displine][(x << 3) + 13] = pcjr->array[((dat >> 4) & pcjr->array[1]) + 16] + 16; + buffer->line[pcjr->displine][(x << 3) + 14] = + buffer->line[pcjr->displine][(x << 3) + 15] = pcjr->array[(dat & pcjr->array[1]) + 16] + 16; + } + break; + case 0x12: /*160x200x16*/ + for (x = 0; x < pcjr->crtc[1]; x++) + { + dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | + pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + pcjr->ma++; + buffer->line[pcjr->displine][(x << 4) + 8] = + buffer->line[pcjr->displine][(x << 4) + 9] = + buffer->line[pcjr->displine][(x << 4) + 10] = + buffer->line[pcjr->displine][(x << 4) + 11] = pcjr->array[((dat >> 12) & pcjr->array[1]) + 16] + 16; + buffer->line[pcjr->displine][(x << 4) + 12] = + buffer->line[pcjr->displine][(x << 4) + 13] = + buffer->line[pcjr->displine][(x << 4) + 14] = + buffer->line[pcjr->displine][(x << 4) + 15] = pcjr->array[((dat >> 8) & pcjr->array[1]) + 16] + 16; + buffer->line[pcjr->displine][(x << 4) + 16] = + buffer->line[pcjr->displine][(x << 4) + 17] = + buffer->line[pcjr->displine][(x << 4) + 18] = + buffer->line[pcjr->displine][(x << 4) + 19] = pcjr->array[((dat >> 4) & pcjr->array[1]) + 16] + 16; + buffer->line[pcjr->displine][(x << 4) + 20] = + buffer->line[pcjr->displine][(x << 4) + 21] = + buffer->line[pcjr->displine][(x << 4) + 22] = + buffer->line[pcjr->displine][(x << 4) + 23] = pcjr->array[(dat & pcjr->array[1]) + 16] + 16; + } + break; + case 0x03: /*640x200x4*/ + for (x = 0; x < pcjr->crtc[1]; x++) + { + dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | + pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + pcjr->ma++; + for (c = 0; c < 8; c++) + { + chr = (dat >> 7) & 1; + chr |= ((dat >> 14) & 2); + buffer->line[pcjr->displine][(x << 3) + 8 + c] = pcjr->array[(chr & pcjr->array[1]) + 16] + 16; + dat <<= 1; + } + } + break; + case 0x01: /*80 column text*/ + for (x = 0; x < pcjr->crtc[1]; x++) + { + chr = pcjr->vram[((pcjr->ma << 1) & mask) + offset]; + attr = pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + drawcursor = ((pcjr->ma == ca) && pcjr->con && pcjr->cursoron); + if (pcjr->array[3] & 4) + { + cols[1] = pcjr->array[ ((attr & 15) & pcjr->array[1]) + 16] + 16; + cols[0] = pcjr->array[(((attr >> 4) & 7) & pcjr->array[1]) + 16] + 16; + if ((pcjr->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } + else + { + cols[1] = pcjr->array[((attr & 15) & pcjr->array[1]) + 16] + 16; + cols[0] = pcjr->array[((attr >> 4) & pcjr->array[1]) + 16] + 16; + } + if (pcjr->sc & 8) + { + for (c = 0; c < 8; c++) + buffer->line[pcjr->displine][(x << 3) + c + 8] = cols[0]; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[pcjr->displine][(x << 3) + c + 8] = cols[(fontdat[chr][pcjr->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } +// if (!((ma^(crtc[15]|(crtc[14]<<8)))&0x3FFF)) printf("Cursor match! %04X\n",ma); + if (drawcursor) + { + for (c = 0; c < 8; c++) + buffer->line[pcjr->displine][(x << 3) + c + 8] ^= 15; + } + pcjr->ma++; + } + break; + case 0x00: /*40 column text*/ + for (x = 0; x < pcjr->crtc[1]; x++) + { + chr = pcjr->vram[((pcjr->ma << 1) & mask) + offset]; + attr = pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + drawcursor = ((pcjr->ma == ca) && pcjr->con && pcjr->cursoron); + if (pcjr->array[3] & 4) + { + cols[1] = pcjr->array[ ((attr & 15) & pcjr->array[1]) + 16] + 16; + cols[0] = pcjr->array[(((attr >> 4) & 7) & pcjr->array[1]) + 16] + 16; + if ((pcjr->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } + else + { + cols[1] = pcjr->array[((attr & 15) & pcjr->array[1]) + 16] + 16; + cols[0] = pcjr->array[((attr >> 4) & pcjr->array[1]) + 16] + 16; + } + pcjr->ma++; + if (pcjr->sc & 8) + { + for (c = 0; c < 8; c++) + buffer->line[pcjr->displine][(x << 4) + (c << 1) + 8] = + buffer->line[pcjr->displine][(x << 4) + (c << 1) + 1 + 8] = cols[0]; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[pcjr->displine][(x << 4) + (c << 1) + 8] = + buffer->line[pcjr->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][pcjr->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + if (drawcursor) + { + for (c = 0; c < 16; c++) + buffer->line[pcjr->displine][(x << 4) + c + 8] ^= 15; + } + } + break; + case 0x02: /*320x200x4*/ + cols[0] = pcjr->array[0 + 16] + 16; + cols[1] = pcjr->array[1 + 16] + 16; + cols[2] = pcjr->array[2 + 16] + 16; + cols[3] = pcjr->array[3 + 16] + 16; + for (x = 0; x < pcjr->crtc[1]; x++) + { + dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | + pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + pcjr->ma++; + for (c = 0; c < 8; c++) + { + buffer->line[pcjr->displine][(x << 4) + (c << 1) + 8] = + buffer->line[pcjr->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + dat <<= 2; + } + } + break; + case 0x102: /*640x200x2*/ + cols[0] = pcjr->array[0 + 16] + 16; + cols[1] = pcjr->array[1 + 16] + 16; + for (x = 0; x < pcjr->crtc[1]; x++) + { + dat = (pcjr->vram[((pcjr->ma << 1) & mask) + offset] << 8) | + pcjr->vram[((pcjr->ma << 1) & mask) + offset + 1]; + pcjr->ma++; + for (c = 0; c < 16; c++) + { + buffer->line[pcjr->displine][(x << 4) + c + 8] = cols[dat >> 15]; + dat <<= 1; + } + } + break; + } + } + else + { + if (pcjr->array[3] & 4) + { + if (pcjr->array[0] & 1) hline(buffer, 0, pcjr->displine, (pcjr->crtc[1] << 3) + 16, (pcjr->array[2] & 0xf) + 16); + else hline(buffer, 0, pcjr->displine, (pcjr->crtc[1] << 4) + 16, (pcjr->array[2] & 0xf) + 16); + } + else + { +// cols[0] = ((pcjr->mode & 0x12) == 0x12) ? 0 : (pcjr->col & 0xf) + 16; + cols[0] = pcjr->array[0 + 16] + 16; + if (pcjr->array[0] & 1) hline(buffer, 0, pcjr->displine, (pcjr->crtc[1] << 3) + 16, cols[0]); + else hline(buffer, 0, pcjr->displine, (pcjr->crtc[1] << 4) + 16, cols[0]); + } + } + if (pcjr->array[0] & 1) x = (pcjr->crtc[1] << 3) + 16; + else x = (pcjr->crtc[1] << 4) + 16; + if (cga_comp) + { + for (c = 0; c < x; c++) + { + y_buf[(c << 1) & 6] = ntsc_col[buffer->line[pcjr->displine][c] & 7][(c << 1) & 6] ? 0x6000 : 0; + y_buf[(c << 1) & 6] += (buffer->line[pcjr->displine][c] & 8) ? 0x3000 : 0; + i_buf[(c << 1) & 6] = y_buf[(c << 1) & 6] * i_filt[(c << 1) & 6]; + q_buf[(c << 1) & 6] = y_buf[(c << 1) & 6] * q_filt[(c << 1) & 6]; + y_tot = y_buf[0] + y_buf[1] + y_buf[2] + y_buf[3] + y_buf[4] + y_buf[5] + y_buf[6] + y_buf[7]; + i_tot = i_buf[0] + i_buf[1] + i_buf[2] + i_buf[3] + i_buf[4] + i_buf[5] + i_buf[6] + i_buf[7]; + q_tot = q_buf[0] + q_buf[1] + q_buf[2] + q_buf[3] + q_buf[4] + q_buf[5] + q_buf[6] + q_buf[7]; + + y_val = y_tot >> 10; + if (y_val > 255) y_val = 255; + y_val <<= 16; + i_val = i_tot >> 12; + if (i_val > 39041) i_val = 39041; + if (i_val < -39041) i_val = -39041; + q_val = q_tot >> 12; + if (q_val > 34249) q_val = 34249; + if (q_val < -34249) q_val = -34249; + + r = (y_val + 249*i_val + 159*q_val) >> 16; + g = (y_val - 70*i_val - 166*q_val) >> 16; + b = (y_val - 283*i_val + 436*q_val) >> 16; + + y_buf[((c << 1) & 6) + 1] = ntsc_col[buffer->line[pcjr->displine][c] & 7][((c << 1) & 6) + 1] ? 0x6000 : 0; + y_buf[((c << 1) & 6) + 1] += (buffer->line[pcjr->displine][c] & 8) ? 0x3000 : 0; + i_buf[((c << 1) & 6) + 1] = y_buf[((c << 1) & 6) + 1] * i_filt[((c << 1) & 6) + 1]; + q_buf[((c << 1) & 6) + 1] = y_buf[((c << 1) & 6) + 1] * q_filt[((c << 1) & 6) + 1]; + y_tot = y_buf[0] + y_buf[1] + y_buf[2] + y_buf[3] + y_buf[4] + y_buf[5] + y_buf[6] + y_buf[7]; + i_tot = i_buf[0] + i_buf[1] + i_buf[2] + i_buf[3] + i_buf[4] + i_buf[5] + i_buf[6] + i_buf[7]; + q_tot = q_buf[0] + q_buf[1] + q_buf[2] + q_buf[3] + q_buf[4] + q_buf[5] + q_buf[6] + q_buf[7]; + + y_val = y_tot >> 10; + if (y_val > 255) y_val = 255; + y_val <<= 16; + i_val = i_tot >> 12; + if (i_val > 39041) i_val = 39041; + if (i_val < -39041) i_val = -39041; + q_val = q_tot >> 12; + if (q_val > 34249) q_val = 34249; + if (q_val < -34249) q_val = -34249; + + r = (y_val + 249*i_val + 159*q_val) >> 16; + g = (y_val - 70*i_val - 166*q_val) >> 16; + b = (y_val - 283*i_val + 436*q_val) >> 16; + if (r > 511) r = 511; + if (g > 511) g = 511; + if (b > 511) b = 511; + + ((uint32_t *)buffer32->line[pcjr->displine])[c] = makecol32(r / 2, g / 2, b / 2); + } + } + pcjr->sc = oldsc; + if (pcjr->vc == pcjr->crtc[7] && !pcjr->sc) + { + pcjr->stat |= 8; +// printf("VSYNC on %i %i\n",vc,sc); + } + pcjr->displine++; + if (pcjr->displine >= 360) + pcjr->displine = 0; + } + else + { + pcjr->vidtime += pcjr->dispontime; + if (pcjr->dispon) + pcjr->stat |= 1; + pcjr->linepos = 0; + if (pcjr->vsynctime) + { + pcjr->vsynctime--; + if (!pcjr->vsynctime) + { + pcjr->stat &= ~8; +// printf("VSYNC off %i %i\n",vc,sc); + } + } + if (pcjr->sc == (pcjr->crtc[11] & 31) || ((pcjr->crtc[8] & 3) == 3 && pcjr->sc == ((pcjr->crtc[11] & 31) >> 1))) + { + pcjr->con = 0; + pcjr->coff = 1; + } + if (pcjr->vadj) + { + pcjr->sc++; + pcjr->sc &= 31; + pcjr->ma = pcjr->maback; + pcjr->vadj--; + if (!pcjr->vadj) + { + pcjr->dispon = 1; + pcjr->ma = pcjr->maback = (pcjr->crtc[13] | (pcjr->crtc[12] << 8)) & 0x3fff; + pcjr->sc = 0; +// printf("Display on!\n"); + } + } + else if (pcjr->sc == pcjr->crtc[9] || ((pcjr->crtc[8] & 3) == 3 && pcjr->sc == (pcjr->crtc[9] >> 1))) + { + pcjr->maback = pcjr->ma; +// con=0; +// coff=0; + pcjr->sc = 0; + oldvc = pcjr->vc; + pcjr->vc++; + pcjr->vc &= 127; +// pclog("VC %i %i\n", pcjr->vc, pcjr->crtc[7]); +// printf("VC %i %i %i %i %i\n",vc,crtc[4],crtc[6],crtc[7],pcjr->dispon); + if (pcjr->vc == pcjr->crtc[6]) + pcjr->dispon = 0; + if (oldvc == pcjr->crtc[4]) + { +// printf("Display over at %i\n",pcjr->displine); + pcjr->vc = 0; + pcjr->vadj = pcjr->crtc[5]; + if (!pcjr->vadj) + pcjr->dispon = 1; + if (!pcjr->vadj) + pcjr->ma = pcjr->maback = (pcjr->crtc[13] | (pcjr->crtc[12] << 8)) & 0x3fff; + if ((pcjr->crtc[10] & 0x60) == 0x20) pcjr->cursoron = 0; + else pcjr->cursoron = pcjr->blink & 16; +// printf("CRTC10 %02X %i\n",crtc[10],cursoron); + } + if (pcjr->vc == pcjr->crtc[7]) + { + pcjr->dispon = 0; + pcjr->displine = 0; + pcjr->vsynctime = 16;//(crtc[3]>>4)+1; + picint(1 << 5); +// printf("pcjr->vsynctime %i %02X\n",pcjr->vsynctime,crtc[3]); +// pcjr->stat|=8; + if (pcjr->crtc[7]) + { +// printf("Lastline %i Firstline %i %i %i %i\n",lastline,firstline,lastline-firstline,crtc[1],xsize); + if (pcjr->array[0] & 1) x = (pcjr->crtc[1] << 3) + 16; + else x = (pcjr->crtc[1] << 4) + 16; + pcjr->lastline++; + if (x != xsize || (pcjr->lastline - pcjr->firstline) != ysize) + { + xsize = x; + ysize = pcjr->lastline - pcjr->firstline; +// printf("Resize to %i,%i - R1 %i\n",xsize,ysize,crtc[1]); + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + updatewindowsize(xsize, (ysize << 1) + 16); + } +// printf("Blit %i %i\n",firstline,lastline); +//printf("Xsize is %i\n",xsize); + startblit(); + if (cga_comp) + video_blit_memtoscreen(0, pcjr->firstline-4, 0, (pcjr->lastline - pcjr->firstline) + 8, xsize, (pcjr->lastline - pcjr->firstline) + 8); + else + video_blit_memtoscreen_8(0, pcjr->firstline-4, xsize, (pcjr->lastline - pcjr->firstline) + 8); + endblit(); + frames++; + video_res_x = xsize - 16; + video_res_y = ysize; + } + pcjr->firstline = 1000; + pcjr->lastline = 0; + pcjr->blink++; + } + } + else + { + pcjr->sc++; + pcjr->sc &= 31; + pcjr->ma = pcjr->maback; + } + if ((pcjr->sc == (pcjr->crtc[10] & 31) || ((pcjr->crtc[8] & 3) == 3 && pcjr->sc == ((pcjr->crtc[10] & 31) >> 1)))) + pcjr->con = 1; + } +} + +static void *pcjr_video_init() +{ + int c; + int pcjr_tint = -2; + pcjr_t *pcjr = malloc(sizeof(pcjr_t)); + memset(pcjr, 0, sizeof(pcjr_t)); + + pcjr->memctrl = -1; + + for (c = 0; c < 8; c++) + { + i_filt[c] = 512.0 * cos((3.14 * (pcjr_tint + c * 4) / 16.0) - 33.0 / 180.0); + q_filt[c] = 512.0 * sin((3.14 * (pcjr_tint + c * 4) / 16.0) - 33.0 / 180.0); + } + timer_add(pcjr_poll, &pcjr->vidtime, TIMER_ALWAYS_ENABLED, pcjr); + mem_mapping_add(&pcjr->mapping, 0xb8000, 0x08000, pcjr_read, NULL, NULL, pcjr_write, NULL, NULL, NULL, 0, pcjr); + io_sethandler(0x03d0, 0x0010, pcjr_in, NULL, NULL, pcjr_out, NULL, NULL, pcjr); + overscan_x = overscan_y = 16; + return pcjr; +} + +static void pcjr_video_close(void *p) +{ + pcjr_t *pcjr = (pcjr_t *)p; + + free(pcjr); +} + +static void pcjr_speed_changed(void *p) +{ + pcjr_t *pcjr = (pcjr_t *)p; + + pcjr_recalctimings(pcjr); +} + +device_t pcjr_video_device = +{ + "IBM PCjr (video)", + 0, + pcjr_video_init, + pcjr_video_close, + NULL, + pcjr_speed_changed, + NULL, + NULL +}; diff --git a/src/vid_pcjr.h b/src/vid_pcjr.h new file mode 100644 index 000000000..92bfc31e0 --- /dev/null +++ b/src/vid_pcjr.h @@ -0,0 +1 @@ +extern device_t pcjr_video_device; diff --git a/src/vid_ps1_svga.c b/src/vid_ps1_svga.c new file mode 100644 index 000000000..ca1dc01c2 --- /dev/null +++ b/src/vid_ps1_svga.c @@ -0,0 +1,189 @@ +/*Emulation of the SVGA chip in the IBM PS/1 Model 2121, or at least the + 20 MHz version. + + I am not entirely sure what this chip actually is, possibly a CF62011? I can + not find any documentation on the chip so have implemented enough to pass + self-test in the PS/1 BIOS. It has 512kb video memory but I have not found any + native drivers for any operating system and there is no VBE implementation, so + it's just a VGA for now. +*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_vga.h" + +typedef struct ps1_m2121_svga_t +{ + svga_t svga; + + rom_t bios_rom; + + uint8_t banking; + uint8_t reg_2100; + uint8_t reg_210a; +} ps1_m2121_svga_t; + +void ps1_m2121_svga_out(uint16_t addr, uint8_t val, void *p) +{ + ps1_m2121_svga_t *ps1 = (ps1_m2121_svga_t *)p; + svga_t *svga = &ps1->svga; + uint8_t old; + +// pclog("svga_out : %04X %02X %04X:%04X %02X %i\n", addr, val, CS,cpu_state.pc, ram[0x489], ins); + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3D4: + svga->crtcreg = val & 0x1f; + return; + case 0x3D5: + if (svga->crtcreg <= 0x18) + val &= mask_crtc[svga->crtcreg]; + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + + case 0x2100: + ps1->reg_2100 = val; + if ((val & 7) < 4) + svga->read_bank = svga->write_bank = 0; + else + svga->read_bank = svga->write_bank = (ps1->banking & 0x7) * 0x10000; + break; + case 0x2108: + if ((ps1->reg_2100 & 7) >= 4) + svga->read_bank = svga->write_bank = (val & 0x7) * 0x10000; + ps1->banking = val; + break; + case 0x210a: + ps1->reg_210a = val; + break; + } + svga_out(addr, val, svga); +} + +uint8_t ps1_m2121_svga_in(uint16_t addr, void *p) +{ + ps1_m2121_svga_t *ps1 = (ps1_m2121_svga_t *)p; + svga_t *svga = &ps1->svga; + uint8_t temp; + +// if (addr != 0x3da) pclog("svga_in : %04X ", addr); + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x100: + temp = 0xfe; + break; + case 0x101: + temp = 0xe8; + break; + + case 0x3D4: + temp = svga->crtcreg; + break; + case 0x3D5: + temp = svga->crtc[svga->crtcreg]; + break; + + case 0x2108: + temp = ps1->banking; + break; + case 0x210a: + temp = ps1->reg_210a; + break; + + default: + temp = svga_in(addr, svga); + break; + } +// if (addr != 0x3da) pclog("%02X %04X:%04X\n", temp, CS,pc); + return temp; +} + +void *ps1_m2121_svga_init() +{ + ps1_m2121_svga_t *ps1 = malloc(sizeof(ps1_m2121_svga_t)); + memset(ps1, 0, sizeof(ps1_m2121_svga_t)); + + svga_init(&ps1->svga, ps1, 1 << 19, /*512kb*/ + NULL, + ps1_m2121_svga_in, ps1_m2121_svga_out, + NULL, + NULL); + + io_sethandler(0x0100, 0x0002, ps1_m2121_svga_in, NULL, NULL, ps1_m2121_svga_out, NULL, NULL, ps1); + io_sethandler(0x03c0, 0x0020, ps1_m2121_svga_in, NULL, NULL, ps1_m2121_svga_out, NULL, NULL, ps1); + io_sethandler(0x2100, 0x0010, ps1_m2121_svga_in, NULL, NULL, ps1_m2121_svga_out, NULL, NULL, ps1); +// io_sethandler(0x210a, 0x0001, ps1_m2121_svga_in, NULL, NULL, ps1_m2121_svga_out, NULL, NULL, ps1); + + ps1->svga.bpp = 8; + ps1->svga.miscout = 1; + + return ps1; +} + +void ps1_m2121_svga_close(void *p) +{ + ps1_m2121_svga_t *ps1 = (ps1_m2121_svga_t *)p; + + svga_close(&ps1->svga); + + free(ps1); +} + +void ps1_m2121_svga_speed_changed(void *p) +{ + ps1_m2121_svga_t *ps1 = (ps1_m2121_svga_t *)p; + + svga_recalctimings(&ps1->svga); +} + +void ps1_m2121_svga_force_redraw(void *p) +{ + ps1_m2121_svga_t *ps1 = (ps1_m2121_svga_t *)p; + + ps1->svga.fullchange = changeframecount; +} + +void ps1_m2121_svga_add_status_info(char *s, int max_len, void *p) +{ + ps1_m2121_svga_t *ps1 = (ps1_m2121_svga_t *)p; + + svga_add_status_info(s, max_len, &ps1->svga); +} + +device_t ps1_m2121_svga_device = +{ + "PS/1 Model 2121 SVGA", + 0, + ps1_m2121_svga_init, + ps1_m2121_svga_close, + NULL, + ps1_m2121_svga_speed_changed, + ps1_m2121_svga_force_redraw, + ps1_m2121_svga_add_status_info +}; diff --git a/src/vid_ps1_svga.h b/src/vid_ps1_svga.h new file mode 100644 index 000000000..8cb73a9f4 --- /dev/null +++ b/src/vid_ps1_svga.h @@ -0,0 +1 @@ +extern device_t ps1_m2121_svga_device; diff --git a/src/vid_s3.c b/src/vid_s3.c new file mode 100644 index 000000000..e93befd33 --- /dev/null +++ b/src/vid_s3.c @@ -0,0 +1,2563 @@ +/*S3 emulation*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "pci.h" +#include "rom.h" +#include "thread.h" +#include "video.h" +#include "vid_s3.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "vid_sdac_ramdac.h" + +enum +{ + S3_VISION864, + S3_TRIO32, + S3_TRIO64 +}; + +enum +{ + VRAM_4MB = 0, + VRAM_8MB = 3, + VRAM_2MB = 4, + VRAM_1MB = 6, + VRAM_512KB = 7 +}; + +#define FIFO_SIZE 65536 +#define FIFO_MASK (FIFO_SIZE - 1) +#define FIFO_ENTRY_SIZE (1 << 31) + +#define FIFO_ENTRIES (s3->fifo_write_idx - s3->fifo_read_idx) +#define FIFO_FULL ((s3->fifo_write_idx - s3->fifo_read_idx) >= FIFO_SIZE) +#define FIFO_EMPTY (s3->fifo_read_idx == s3->fifo_write_idx) + +#define FIFO_TYPE 0xff000000 +#define FIFO_ADDR 0x00ffffff + +enum +{ + FIFO_INVALID = (0x00 << 24), + FIFO_WRITE_BYTE = (0x01 << 24), + FIFO_WRITE_WORD = (0x02 << 24), + FIFO_WRITE_DWORD = (0x03 << 24), + FIFO_OUT_BYTE = (0x04 << 24), + FIFO_OUT_WORD = (0x05 << 24), + FIFO_OUT_DWORD = (0x06 << 24) +}; + +typedef struct +{ + uint32_t addr_type; + uint32_t val; +} fifo_entry_t; + +typedef struct s3_t +{ + mem_mapping_t linear_mapping; + mem_mapping_t mmio_mapping; + + rom_t bios_rom; + + svga_t svga; + sdac_ramdac_t ramdac; + + uint8_t bank; + uint8_t ma_ext; + int width; + int bpp; + + int chip; + + uint8_t id, id_ext, id_ext_pci; + + int packed_mmio; + + uint32_t linear_base, linear_size; + + uint8_t pci_regs[256]; + + uint32_t vram_mask; + + float (*getclock)(int clock, void *p); + void *getclock_p; + + struct + { + uint8_t subsys_cntl; + uint8_t setup_md; + uint8_t advfunc_cntl; + uint16_t cur_y; + uint16_t cur_x; + int16_t desty_axstp; + int16_t destx_distp; + int16_t err_term; + int16_t maj_axis_pcnt; + uint16_t cmd; + uint16_t short_stroke; + uint32_t bkgd_color; + uint32_t frgd_color; + uint32_t wrt_mask; + uint32_t rd_mask; + uint32_t color_cmp; + uint8_t bkgd_mix; + uint8_t frgd_mix; + uint16_t multifunc_cntl; + uint16_t multifunc[16]; + uint8_t pix_trans[4]; + + int cx, cy; + int sx, sy; + int dx, dy; + uint32_t src, dest, pattern; + int pix_trans_count; + + uint32_t dat_buf; + int dat_count; + } accel; + + fifo_entry_t fifo[FIFO_SIZE]; + volatile int fifo_read_idx, fifo_write_idx; + + thread_t *fifo_thread; + event_t *wake_fifo_thread; + event_t *fifo_not_full_event; + + int blitter_busy; + uint64_t blitter_time; + uint64_t status_time; +} s3_t; + +void s3_updatemapping(); + +void s3_accel_write(uint32_t addr, uint8_t val, void *p); +void s3_accel_write_w(uint32_t addr, uint16_t val, void *p); +void s3_accel_write_l(uint32_t addr, uint32_t val, void *p); +uint8_t s3_accel_read(uint32_t addr, void *p); + +static inline void wake_fifo_thread(s3_t *s3) +{ + thread_set_event(s3->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +static void s3_wait_fifo_idle(s3_t *s3) +{ + while (!FIFO_EMPTY) + { + wake_fifo_thread(s3); + thread_wait_event(s3->fifo_not_full_event, 1); + } +} + +void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_t *s3); + +#define WRITE8(addr, var, val) switch ((addr) & 3) \ + { \ + case 0: var = (var & 0xffffff00) | (val); break; \ + case 1: var = (var & 0xffff00ff) | ((val) << 8); break; \ + case 2: var = (var & 0xff00ffff) | ((val) << 16); break; \ + case 3: var = (var & 0x00ffffff) | ((val) << 24); break; \ + } + +static void s3_accel_out_fifo(s3_t *s3, uint16_t port, uint8_t val) +{ + switch (port) + { + case 0x82e8: + s3->accel.cur_y = (s3->accel.cur_y & 0xf00) | val; + break; + case 0x82e9: + s3->accel.cur_y = (s3->accel.cur_y & 0xff) | ((val & 0x1f) << 8); + break; + + case 0x86e8: + s3->accel.cur_x = (s3->accel.cur_x & 0xf00) | val; + break; + case 0x86e9: + s3->accel.cur_x = (s3->accel.cur_x & 0xff) | ((val & 0x1f) << 8); + break; + + case 0x8ae8: + s3->accel.desty_axstp = (s3->accel.desty_axstp & 0x3f00) | val; + break; + case 0x8ae9: + s3->accel.desty_axstp = (s3->accel.desty_axstp & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + s3->accel.desty_axstp |= ~0x3fff; + break; + + case 0x8ee8: + s3->accel.destx_distp = (s3->accel.destx_distp & 0x3f00) | val; + break; + case 0x8ee9: + s3->accel.destx_distp = (s3->accel.destx_distp & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + s3->accel.destx_distp |= ~0x3fff; + break; + + case 0x92e8: + s3->accel.err_term = (s3->accel.err_term & 0x3f00) | val; + break; + case 0x92e9: + s3->accel.err_term = (s3->accel.err_term & 0xff) | ((val & 0x3f) << 8); + if (val & 0x20) + s3->accel.err_term |= ~0x3fff; + break; + + case 0x96e8: + s3->accel.maj_axis_pcnt = (s3->accel.maj_axis_pcnt & 0x3f00) | val; + break; + case 0x96e9: + s3->accel.maj_axis_pcnt = (s3->accel.maj_axis_pcnt & 0xff) | ((val & 0x0f) << 8); + if (val & 0x08) + s3->accel.maj_axis_pcnt |= ~0x0fff; + break; + + case 0x9ae8: + s3->accel.cmd = (s3->accel.cmd & 0xff00) | val; + break; + case 0x9ae9: + s3->accel.cmd = (s3->accel.cmd & 0xff) | (val << 8); + s3_accel_start(-1, 0, 0xffffffff, 0, s3); + s3->accel.pix_trans_count = 0; + s3->accel.multifunc[0xe] &= ~0x10; /*hack*/ + break; + + case 0x9ee8: + s3->accel.short_stroke = (s3->accel.short_stroke & 0xff00) | val; + break; + case 0x9ee9: + s3->accel.short_stroke = (s3->accel.short_stroke & 0xff) | (val << 8); + break; + + case 0xa2e8: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x00ff0000) | (val << 16); + else + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x000000ff) | val; + break; + case 0xa2e9: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0xff000000) | (val << 24); + else + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x0000ff00) | (val << 8); + if (!(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.multifunc[0xe] ^= 0x10; + break; + case 0xa2ea: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0x00ff0000) | (val << 16); + break; + case 0xa2eb: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.bkgd_color = (s3->accel.bkgd_color & ~0xff000000) | (val << 24); + break; + + case 0xa6e8: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.frgd_color = (s3->accel.frgd_color & ~0x00ff0000) | (val << 16); + else + s3->accel.frgd_color = (s3->accel.frgd_color & ~0x000000ff) | val; + break; + case 0xa6e9: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.frgd_color = (s3->accel.frgd_color & ~0xff000000) | (val << 24); + else + s3->accel.frgd_color = (s3->accel.frgd_color & ~0x0000ff00) | (val << 8); + if (!(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.multifunc[0xe] ^= 0x10; + break; + case 0xa6ea: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.frgd_color = (s3->accel.frgd_color & ~0x00ff0000) | (val << 16); + break; + case 0xa6eb: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.frgd_color = (s3->accel.frgd_color & ~0xff000000) | (val << 24); + break; + + case 0xaae8: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x00ff0000) | (val << 16); + else + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x000000ff) | val; + break; + case 0xaae9: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0xff000000) | (val << 24); + else + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x0000ff00) | (val << 8); + if (!(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.multifunc[0xe] ^= 0x10; + break; + case 0xaaea: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0x00ff0000) | (val << 16); + break; + case 0xaaeb: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.wrt_mask = (s3->accel.wrt_mask & ~0xff000000) | (val << 24); + break; + + case 0xaee8: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.rd_mask = (s3->accel.rd_mask & ~0x00ff0000) | (val << 16); + else + s3->accel.rd_mask = (s3->accel.rd_mask & ~0x000000ff) | val; + break; + case 0xaee9: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.rd_mask = (s3->accel.rd_mask & ~0xff000000) | (val << 24); + else + s3->accel.rd_mask = (s3->accel.rd_mask & ~0x0000ff00) | (val << 8); + if (!(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.multifunc[0xe] ^= 0x10; + break; + case 0xaeea: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.rd_mask = (s3->accel.rd_mask & ~0x00ff0000) | (val << 16); + break; + case 0xaeeb: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.rd_mask = (s3->accel.rd_mask & ~0xff000000) | (val << 24); + break; + + case 0xb2e8: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.color_cmp = (s3->accel.color_cmp & ~0x00ff0000) | (val << 16); + else + s3->accel.color_cmp = (s3->accel.color_cmp & ~0x000000ff) | val; + break; + case 0xb2e9: + if (s3->bpp == 3 && s3->accel.multifunc[0xe] & 0x10 && !(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.color_cmp = (s3->accel.color_cmp & ~0xff000000) | (val << 24); + else + s3->accel.color_cmp = (s3->accel.color_cmp & ~0x0000ff00) | (val << 8); + if (!(s3->accel.multifunc[0xe] & 0x200)) + s3->accel.multifunc[0xe] ^= 0x10; + break; + case 0xb2ea: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.color_cmp = (s3->accel.color_cmp & ~0x00ff0000) | (val << 16); + break; + case 0xb2eb: + if (s3->accel.multifunc[0xe] & 0x200) + s3->accel.color_cmp = (s3->accel.color_cmp & ~0xff000000) | (val << 24); + break; + + case 0xb6e8: + s3->accel.bkgd_mix = val; + break; + + case 0xbae8: + s3->accel.frgd_mix = val; + break; + + case 0xbee8: + s3->accel.multifunc_cntl = (s3->accel.multifunc_cntl & 0xff00) | val; + break; + case 0xbee9: + s3->accel.multifunc_cntl = (s3->accel.multifunc_cntl & 0xff) | (val << 8); + s3->accel.multifunc[s3->accel.multifunc_cntl >> 12] = s3->accel.multifunc_cntl & 0xfff; + break; + + case 0xe2e8: + s3->accel.pix_trans[0] = val; + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !(s3->accel.cmd & 0x600) && (s3->accel.cmd & 0x100)) + s3_accel_start(8, 1, s3->accel.pix_trans[0], 0, s3); + else if (!(s3->accel.cmd & 0x600) && (s3->accel.cmd & 0x100)) + s3_accel_start(1, 1, 0xffffffff, s3->accel.pix_trans[0], s3); + break; + case 0xe2e9: + s3->accel.pix_trans[1] = val; + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x600) == 0x200 && (s3->accel.cmd & 0x100)) + { + if (s3->accel.cmd & 0x1000) s3_accel_start(16, 1, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), 0, s3); + else s3_accel_start(16, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), 0, s3); + } + else if ((s3->accel.cmd & 0x600) == 0x200 && (s3->accel.cmd & 0x100)) + { + if (s3->accel.cmd & 0x1000) s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[1] | (s3->accel.pix_trans[0] << 8), s3); + else s3_accel_start(2, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8), s3); + } + break; + case 0xe2ea: + s3->accel.pix_trans[2] = val; + break; + case 0xe2eb: + s3->accel.pix_trans[3] = val; + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && (s3->accel.cmd & 0x600) == 0x400 && (s3->accel.cmd & 0x100)) + s3_accel_start(32, 1, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), 0, s3); + else if ((s3->accel.cmd & 0x600) == 0x400 && (s3->accel.cmd & 0x100)) + s3_accel_start(4, 1, 0xffffffff, s3->accel.pix_trans[0] | (s3->accel.pix_trans[1] << 8) | (s3->accel.pix_trans[2] << 16) | (s3->accel.pix_trans[3] << 24), s3); + break; + } +} + +static void s3_accel_out_fifo_w(s3_t *s3, uint16_t port, uint16_t val) +{ +// pclog("Accel out w %04X %04X\n", port, val); + if (s3->accel.cmd & 0x100) + { + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) + { + if (s3->accel.cmd & 0x1000) + val = (val >> 8) | (val << 8); + s3_accel_start(16, 1, val | (val << 16), 0, s3); + } + else + s3_accel_start(2, 1, 0xffffffff, val | (val << 16), s3); + } +} + +static void s3_accel_out_fifo_l(s3_t *s3, uint16_t port, uint32_t val) +{ +// pclog("Accel out l %04X %08X\n", port, val); + if (s3->accel.cmd & 0x100) + { + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) + { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); + if ((s3->accel.cmd & 0x600) == 0x400) + s3_accel_start(32, 1, val, 0, s3); + else if ((s3->accel.cmd & 0x600) == 0x200) + { + s3_accel_start(16, 1, val >> 16, 0, s3); + s3_accel_start(16, 1, val, 0, s3); + } + else if (!(s3->accel.cmd & 0x600)) + { + s3_accel_start(8, 1, val >> 24, 0, s3); + s3_accel_start(8, 1, val >> 16, 0, s3); + s3_accel_start(8, 1, val >> 8, 0, s3); + s3_accel_start(8, 1, val, 0, s3); + } + } + else + { + if ((s3->accel.cmd & 0x600) == 0x400) + s3_accel_start(4, 1, 0xffffffff, val, s3); + else if ((s3->accel.cmd & 0x600) == 0x200) + { + s3_accel_start(2, 1, 0xffffffff, val >> 16, s3); + s3_accel_start(2, 1, 0xffffffff, val, s3); + } + else if (!(s3->accel.cmd & 0x600)) + { + s3_accel_start(1, 1, 0xffffffff, val >> 24, s3); + s3_accel_start(1, 1, 0xffffffff, val >> 16, s3); + s3_accel_start(1, 1, 0xffffffff, val >> 8, s3); + s3_accel_start(1, 1, 0xffffffff, val, s3); + } + } + } +} + +static void s3_accel_write_fifo(s3_t *s3, uint32_t addr, uint8_t val) +{ +// pclog("Write S3 accel %08X %02X\n", addr, val); + if (s3->packed_mmio) + { + int addr_lo = addr & 1; + switch (addr & 0xfffe) + { + case 0x8100: addr = 0x82e8; break; /*ALT_CURXY*/ + case 0x8102: addr = 0x86e8; break; + + case 0x8104: addr = 0x82ea; break; /*ALT_CURXY2*/ + case 0x8106: addr = 0x86ea; break; + + case 0x8108: addr = 0x8ae8; break; /*ALT_STEP*/ + case 0x810a: addr = 0x8ee8; break; + + case 0x810c: addr = 0x8aea; break; /*ALT_STEP2*/ + case 0x810e: addr = 0x8eea; break; + + case 0x8110: addr = 0x92e8; break; /*ALT_ERR*/ + case 0x8112: addr = 0x92ee; break; + + case 0x8118: addr = 0x9ae8; break; /*ALT_CMD*/ + case 0x811a: addr = 0x9aea; break; + + case 0x811c: addr = 0x9ee8; break; /*SHORT_STROKE*/ + + case 0x8120: case 0x8122: /*BKGD_COLOR*/ + WRITE8(addr, s3->accel.bkgd_color, val); + return; + + case 0x8124: case 0x8126: /*FRGD_COLOR*/ + WRITE8(addr, s3->accel.frgd_color, val); + return; + + case 0x8128: case 0x812a: /*WRT_MASK*/ + WRITE8(addr, s3->accel.wrt_mask, val); + return; + + case 0x812c: case 0x812e: /*RD_MASK*/ + WRITE8(addr, s3->accel.rd_mask, val); + return; + + case 0x8130: case 0x8132: /*COLOR_CMP*/ + WRITE8(addr, s3->accel.color_cmp, val); + return; + + case 0x8134: addr = 0xb6e8; break; /*ALT_MIX*/ + case 0x8136: addr = 0xbae8; break; + + case 0x8138: /*SCISSORS_T*/ + WRITE8(addr & 1, s3->accel.multifunc[1], val); + return; + case 0x813a: /*SCISSORS_L*/ + WRITE8(addr & 1, s3->accel.multifunc[2], val); + return; + case 0x813c: /*SCISSORS_B*/ + WRITE8(addr & 1, s3->accel.multifunc[3], val); + return; + case 0x813e: /*SCISSORS_R*/ + WRITE8(addr & 1, s3->accel.multifunc[4], val); + return; + + case 0x8140: /*PIX_CNTL*/ + WRITE8(addr & 1, s3->accel.multifunc[0xa], val); + return; + case 0x8142: /*MULT_MISC2*/ + WRITE8(addr & 1, s3->accel.multifunc[0xd], val); + return; + case 0x8144: /*MULT_MISC*/ + WRITE8(addr & 1, s3->accel.multifunc[0xe], val); + return; + case 0x8146: /*READ_SEL*/ + WRITE8(addr & 1, s3->accel.multifunc[0xf], val); + return; + + case 0x8148: /*ALT_PCNT*/ + WRITE8(addr & 1, s3->accel.multifunc[0], val); + return; + case 0x814a: addr = 0x96e8; break; + case 0x814c: addr = 0x96ea; break; + + case 0x8168: addr = 0xeae8; break; + case 0x816a: addr = 0xeaea; break; + } + addr |= addr_lo; + } + + + if (addr & 0x8000) + { + s3_accel_out_fifo(s3, addr & 0xffff, val); + } + else + { + if (s3->accel.cmd & 0x100) + { + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) + s3_accel_start(8, 1, val | (val << 8) | (val << 16) | (val << 24), 0, s3); + else + s3_accel_start(1, 1, 0xffffffff, val | (val << 8) | (val << 16) | (val << 24), s3); + } + } +} + +static void s3_accel_write_fifo_w(s3_t *s3, uint32_t addr, uint16_t val) +{ +// pclog("Write S3 accel w %08X %04X\n", addr, val); + if (addr & 0x8000) + { + s3_accel_write_fifo(s3, addr, val); + s3_accel_write_fifo(s3, addr + 1, val >> 8); + } + else + { + if (s3->accel.cmd & 0x100) + { + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) + { + if (s3->accel.cmd & 0x1000) + val = (val >> 8) | (val << 8); + s3_accel_start(16, 1, val | (val << 16), 0, s3); + } + else + s3_accel_start(2, 1, 0xffffffff, val | (val << 16), s3); + } + } +} + +static void s3_accel_write_fifo_l(s3_t *s3, uint32_t addr, uint32_t val) +{ +// pclog("Write S3 accel l %08X %08X\n", addr, val); + if (addr & 0x8000) + { + s3_accel_write_fifo(s3, addr, val); + s3_accel_write_fifo(s3, addr + 1, val >> 8); + s3_accel_write_fifo(s3, addr + 2, val >> 16); + s3_accel_write_fifo(s3, addr + 3, val >> 24); + } + else + { + if (s3->accel.cmd & 0x100) + { + if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80) + { + if (s3->accel.cmd & 0x1000) + val = ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24); + if ((s3->accel.cmd & 0x600) == 0x400) + s3_accel_start(32, 1, val, 0, s3); + else if ((s3->accel.cmd & 0x600) == 0x200) + { + s3_accel_start(16, 1, val >> 16, 0, s3); + s3_accel_start(16, 1, val, 0, s3); + } + else if (!(s3->accel.cmd & 0x600)) + { + s3_accel_start(8, 1, val >> 24, 0, s3); + s3_accel_start(8, 1, val >> 16, 0, s3); + s3_accel_start(8, 1, val >> 8, 0, s3); + s3_accel_start(8, 1, val, 0, s3); + } + } + else + { + if ((s3->accel.cmd & 0x600) == 0x400) + s3_accel_start(4, 1, 0xffffffff, val, s3); + else if ((s3->accel.cmd & 0x600) == 0x200) + { + s3_accel_start(2, 1, 0xffffffff, val, s3); + s3_accel_start(2, 1, 0xffffffff, val >> 16, s3); + } + else if (!(s3->accel.cmd & 0x600)) + { + s3_accel_start(1, 1, 0xffffffff, val, s3); + s3_accel_start(1, 1, 0xffffffff, val >> 8, s3); + s3_accel_start(1, 1, 0xffffffff, val >> 16, s3); + s3_accel_start(1, 1, 0xffffffff, val >> 24, s3); + } + } + } + } +} + +static void fifo_thread(void *param) +{ + s3_t *s3 = (s3_t *)param; + + while (1) + { + thread_set_event(s3->fifo_not_full_event); + thread_wait_event(s3->wake_fifo_thread, -1); + thread_reset_event(s3->wake_fifo_thread); + s3->blitter_busy = 1; + while (!FIFO_EMPTY) + { + uint64_t start_time = timer_read(); + uint64_t end_time; + fifo_entry_t *fifo = &s3->fifo[s3->fifo_read_idx & FIFO_MASK]; + uint32_t val = fifo->val; + + switch (fifo->addr_type & FIFO_TYPE) + { + case FIFO_WRITE_BYTE: + s3_accel_write_fifo(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_WORD: + s3_accel_write_fifo_w(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_DWORD: + s3_accel_write_fifo_l(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_OUT_BYTE: + s3_accel_out_fifo(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_OUT_WORD: + s3_accel_out_fifo_w(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_OUT_DWORD: + s3_accel_out_fifo_l(s3, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + } + + s3->fifo_read_idx++; + fifo->addr_type = FIFO_INVALID; + + if (FIFO_ENTRIES > 0xe000) + thread_set_event(s3->fifo_not_full_event); + + end_time = timer_read(); + s3->blitter_time += end_time - start_time; + } + s3->blitter_busy = 0; + } +} + +static void s3_queue(s3_t *s3, uint32_t addr, uint32_t val, uint32_t type) +{ + fifo_entry_t *fifo = &s3->fifo[s3->fifo_write_idx & FIFO_MASK]; + int c; + + if (FIFO_FULL) + { + thread_reset_event(s3->fifo_not_full_event); + if (FIFO_FULL) + { + thread_wait_event(s3->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ + } + } + + fifo->val = val; + fifo->addr_type = (addr & FIFO_ADDR) | type; + + s3->fifo_write_idx++; + + if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8) + wake_fifo_thread(s3); +} + +void s3_out(uint16_t addr, uint8_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; + uint8_t old; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + +// pclog("S3 out %04X %02X %04x:%08x\n", addr, val, CS, pc); + + switch (addr) + { + case 0x3c5: + if (svga->seqaddr >= 0x10 && svga->seqaddr < 0x20) + { + svga->seqregs[svga->seqaddr] = val; + switch (svga->seqaddr) + { + case 0x12: case 0x13: + svga_recalctimings(svga); + return; + } + } + if (svga->seqaddr == 4) /*Chain-4 - update banking*/ + { + if (val & 8) svga->write_bank = svga->read_bank = s3->bank << 16; + else svga->write_bank = svga->read_bank = s3->bank << 14; + } + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: +// pclog("Write RAMDAC %04X %02X %04X:%04X\n", addr, val, CS, pc); + sdac_ramdac_out(addr, val, &s3->ramdac, svga); + return; + + case 0x3D4: + svga->crtcreg = val & 0x7f; + return; + case 0x3D5: + if (svga->crtcreg <= 0x18) + val &= mask_crtc[svga->crtcreg]; + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + if (svga->crtcreg >= 0x20 && svga->crtcreg != 0x38 && (svga->crtc[0x38] & 0xcc) != 0x48) return; + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + switch (svga->crtcreg) + { + case 0x31: + s3->ma_ext = (s3->ma_ext & 0x1c) | ((val & 0x30) >> 4); + break; + case 0x32: + svga->vrammask = (val & 0x40) ? 0x3ffff : s3->vram_mask; + break; + + case 0x50: + switch (svga->crtc[0x50] & 0xc1) + { + case 0x00: s3->width = (svga->crtc[0x31] & 2) ? 2048 : 1024; break; + case 0x01: s3->width = 1152; break; + case 0x40: s3->width = 640; break; + case 0x80: s3->width = 800; break; + case 0x81: s3->width = 1600; break; + case 0xc0: s3->width = 1280; break; + } + s3->bpp = (svga->crtc[0x50] >> 4) & 3; + break; + case 0x69: + s3->ma_ext = val & 0x1f; + break; + + case 0x35: + s3->bank = (s3->bank & 0x70) | (val & 0xf); +// pclog("CRTC write R35 %02X\n", val); + if (svga->chain4) svga->write_bank = svga->read_bank = s3->bank << 16; + else svga->write_bank = svga->read_bank = s3->bank << 14; + break; + case 0x51: + s3->bank = (s3->bank & 0x4f) | ((val & 0xc) << 2); +// pclog("CRTC write R51 %02X\n", val); + if (svga->chain4) svga->write_bank = svga->read_bank = s3->bank << 16; + else svga->write_bank = svga->read_bank = s3->bank << 14; + s3->ma_ext = (s3->ma_ext & ~0xc) | ((val & 3) << 2); + break; + case 0x6a: + s3->bank = val; +// pclog("CRTC write R6a %02X\n", val); + if (svga->chain4) svga->write_bank = svga->read_bank = s3->bank << 16; + else svga->write_bank = svga->read_bank = s3->bank << 14; + break; + + case 0x3a: + if (val & 0x10) + svga->gdcreg[5] |= 0x40; /*Horrible cheat*/ + break; + + case 0x45: + svga->hwcursor.ena = val & 1; + break; + case 0x48: + svga->hwcursor.x = ((svga->crtc[0x46] << 8) | svga->crtc[0x47]) & 0x7ff; + if (svga->bpp == 32) svga->hwcursor.x >>= 1; + svga->hwcursor.y = ((svga->crtc[0x48] << 8) | svga->crtc[0x49]) & 0x7ff; + svga->hwcursor.xoff = svga->crtc[0x4e] & 63; + svga->hwcursor.yoff = svga->crtc[0x4f] & 63; + svga->hwcursor.addr = ((((svga->crtc[0x4c] << 8) | svga->crtc[0x4d]) & 0xfff) * 1024) + (svga->hwcursor.yoff * 16); + if ((s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) && svga->bpp == 32) + svga->hwcursor.x <<= 1; + break; + + case 0x53: + case 0x58: case 0x59: case 0x5a: + s3_updatemapping(s3); + break; + + case 0x67: + if (s3->chip == S3_TRIO32 || s3->chip == S3_TRIO64) + { + switch (val >> 4) + { + case 3: svga->bpp = 15; break; + case 5: svga->bpp = 16; break; + case 7: svga->bpp = 24; break; + case 13: svga->bpp = 32; break; + default: svga->bpp = 8; break; + } + } + break; + //case 0x55: case 0x43: +// pclog("Write CRTC R%02X %02X\n", crtcreg, val); + } + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t s3_in(uint16_t addr, void *p) +{ + s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + +// if (addr != 0x3da) pclog("S3 in %04X %08x:%02x\n", addr, CS, pc); + switch (addr) + { + case 0x3c1: + if (svga->attraddr > 0x14) + return 0xff; + break; + + case 0x3c5: + if (svga->seqaddr >= 0x10 && svga->seqaddr < 0x20) + return svga->seqregs[svga->seqaddr]; + break; + + case 0x3c6: case 0x3c7: case 0x3c8: case 0x3c9: +// pclog("Read RAMDAC %04X %04X:%04X\n", addr, CS, pc); + return sdac_ramdac_in(addr, &s3->ramdac, svga); + + case 0x3d4: + return svga->crtcreg; + case 0x3d5: +// pclog("Read CRTC R%02X %02x %04X:%04X\n", svga->crtcreg, svga->crtc[svga->crtcreg], CS, pc); + switch (svga->crtcreg) + { + case 0x2d: return 0x88; /*Extended chip ID*/ + case 0x2e: return s3->id_ext; /*New chip ID*/ + case 0x2f: return 0; /*Revision level*/ + case 0x30: return s3->id; /*Chip ID*/ + case 0x31: return (svga->crtc[0x31] & 0xcf) | ((s3->ma_ext & 3) << 4); + case 0x35: return (svga->crtc[0x35] & 0xf0) | (s3->bank & 0xf); + case 0x51: return (svga->crtc[0x51] & 0xf0) | ((s3->bank >> 2) & 0xc) | ((s3->ma_ext >> 2) & 3); + case 0x69: return s3->ma_ext; + case 0x6a: return s3->bank; + } + return svga->crtc[svga->crtcreg]; + } + return svga_in(addr, svga); +} + +void s3_recalctimings(svga_t *svga) +{ + s3_t *s3 = (s3_t *)svga->p; + svga->hdisp = svga->hdisp_old; + +// pclog("%i %i\n", svga->hdisp, svga->hdisp_time); +// pclog("recalctimings\n"); + svga->ma_latch |= (s3->ma_ext << 16); +// pclog("SVGA_MA %08X\n", svga_ma); + if (svga->crtc[0x5d] & 0x01) svga->htotal += 0x100; + if (svga->crtc[0x5d] & 0x02) + { + svga->hdisp_time += 0x100; + svga->hdisp += 0x100 * ((svga->seqregs[1] & 8) ? 16 : 8); + } + if (svga->crtc[0x5e] & 0x01) svga->vtotal += 0x400; + if (svga->crtc[0x5e] & 0x02) svga->dispend += 0x400; + if (svga->crtc[0x5e] & 0x04) svga->vblankstart += 0x400; + if (svga->crtc[0x5e] & 0x10) svga->vsyncstart += 0x400; + if (svga->crtc[0x5e] & 0x40) svga->split += 0x400; + if (svga->crtc[0x51] & 0x30) svga->rowoffset += (svga->crtc[0x51] & 0x30) << 4; + else if (svga->crtc[0x43] & 0x04) svga->rowoffset += 0x100; + if (!svga->rowoffset) svga->rowoffset = 256; + svga->interlace = svga->crtc[0x42] & 0x20; + svga->clock = cpuclock / s3->getclock((svga->miscout >> 2) & 3, s3->getclock_p); + + switch (svga->crtc[0x67] >> 4) + { + case 3: case 5: case 7: + svga->clock /= 2; + break; + } + + svga->lowres = !((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)); + if ((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)) + { + switch (svga->bpp) + { + case 8: + svga->render = svga_render_8bpp_highres; + break; + case 15: + svga->render = svga_render_15bpp_highres; + svga->hdisp /= 2; + break; + case 16: + svga->render = svga_render_16bpp_highres; + svga->hdisp /= 2; + break; + case 24: + svga->render = svga_render_24bpp_highres; + svga->hdisp /= 3; + break; + case 32: + svga->render = svga_render_32bpp_highres; + if (s3->chip != S3_TRIO32 && s3->chip != S3_TRIO64) + svga->hdisp /= 4; + break; + } + } +} + +void s3_updatemapping(s3_t *s3) +{ + svga_t *svga = &s3->svga; + +// video_write_a000_w = video_write_a000_l = NULL; + + if (!(s3->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) + { +// pclog("Update mapping - PCI disabled\n"); + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&s3->linear_mapping); + mem_mapping_disable(&s3->mmio_mapping); + return; + } + +// pclog("Update mapping - bank %02X ", svga->gdcreg[6] & 0xc); + switch (svga->gdcreg[6] & 0xc) /*Banked framebuffer*/ + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + +// pclog("Linear framebuffer %02X ", svga->crtc[0x58] & 0x10); + if (svga->crtc[0x58] & 0x10) /*Linear framebuffer*/ + { + mem_mapping_disable(&svga->mapping); + + s3->linear_base = (svga->crtc[0x5a] << 16) | (svga->crtc[0x59] << 24); + switch (svga->crtc[0x58] & 3) + { + case 0: /*64k*/ + s3->linear_size = 0x10000; + break; + case 1: /*1mb*/ + s3->linear_size = 0x100000; + break; + case 2: /*2mb*/ + s3->linear_size = 0x200000; + break; + case 3: /*8mb*/ + s3->linear_size = 0x800000; + break; + } + s3->linear_base &= ~(s3->linear_size - 1); +// pclog("%08X %08X %02X %02X %02X\n", linear_base, linear_size, crtc[0x58], crtc[0x59], crtc[0x5a]); +// pclog("Linear framebuffer at %08X size %08X\n", s3->linear_base, s3->linear_size); + if (s3->linear_base == 0xa0000) + { + mem_mapping_disable(&s3->linear_mapping); + if (!(svga->crtc[0x53] & 0x10)) + { + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + } +// mem_mapping_set_addr(&s3->linear_mapping, 0xa0000, 0x10000); + } + else + mem_mapping_set_addr(&s3->linear_mapping, s3->linear_base, s3->linear_size); + } + else + mem_mapping_disable(&s3->linear_mapping); + +// pclog("Memory mapped IO %02X\n", svga->crtc[0x53] & 0x10); + if (svga->crtc[0x53] & 0x10) /*Memory mapped IO*/ + { + mem_mapping_disable(&svga->mapping); + mem_mapping_enable(&s3->mmio_mapping); + } + else + mem_mapping_disable(&s3->mmio_mapping); +} + +static float s3_trio64_getclock(int clock, void *p) +{ + s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; + float t; + int m, n1, n2; +// pclog("Trio64_getclock %i %02X %02X\n", clock, svga->seqregs[0x13], svga->seqregs[0x12]); + if (clock == 0) return 25175000.0; + if (clock == 1) return 28322000.0; + m = svga->seqregs[0x13] + 2; + n1 = (svga->seqregs[0x12] & 0x1f) + 2; + n2 = ((svga->seqregs[0x12] >> 5) & 0x07); + t = (14318184.0 * ((float)m / (float)n1)) / (float)(1 << n2); +// pclog("TRIO64 clock %i %i %i %f %f %i\n", m, n1, n2, t, 14318184.0 * ((float)m / (float)n1), 1 << n2); + return t; +} + + +void s3_accel_out(uint16_t port, uint8_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; +// pclog("Accel out %04X %02X\n", port, val); + + if (port >= 0x8000) + { + s3_queue(s3, port, val, FIFO_OUT_BYTE); + } + else switch (port) + { + case 0x42e8: + break; + case 0x42e9: + s3->accel.subsys_cntl = val; + break; + case 0x46e8: + s3->accel.setup_md = val; + break; + case 0x4ae8: + s3->accel.advfunc_cntl = val; + break; + } +} + +void s3_accel_out_w(uint16_t port, uint16_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; +// pclog("Accel out w %04X %04X\n", port, val); + s3_queue(s3, port, val, FIFO_OUT_WORD); +} + +void s3_accel_out_l(uint16_t port, uint32_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; +// pclog("Accel out l %04X %08X\n", port, val); + s3_queue(s3, port, val, FIFO_OUT_DWORD); +} + +uint8_t s3_accel_in(uint16_t port, void *p) +{ + s3_t *s3 = (s3_t *)p; + int temp; +// pclog("Accel in %04X\n", port); + switch (port) + { + case 0x42e8: + return 0; + case 0x42e9: + return 0; + + case 0x82e8: + s3_wait_fifo_idle(s3); + return s3->accel.cur_y & 0xff; + case 0x82e9: + s3_wait_fifo_idle(s3); + return s3->accel.cur_y >> 8; + + case 0x86e8: + s3_wait_fifo_idle(s3); + return s3->accel.cur_x & 0xff; + case 0x86e9: + s3_wait_fifo_idle(s3); + return s3->accel.cur_x >> 8; + + case 0x8ae8: + s3_wait_fifo_idle(s3); + return s3->accel.desty_axstp & 0xff; + case 0x8ae9: + s3_wait_fifo_idle(s3); + return s3->accel.desty_axstp >> 8; + + case 0x8ee8: + s3_wait_fifo_idle(s3); + return s3->accel.destx_distp & 0xff; + case 0x8ee9: + s3_wait_fifo_idle(s3); + return s3->accel.destx_distp >> 8; + + case 0x92e8: + s3_wait_fifo_idle(s3); + return s3->accel.err_term & 0xff; + case 0x92e9: + s3_wait_fifo_idle(s3); + return s3->accel.err_term >> 8; + + case 0x96e8: + s3_wait_fifo_idle(s3); + return s3->accel.maj_axis_pcnt & 0xff; + case 0x96e9: + s3_wait_fifo_idle(s3); + return s3->accel.maj_axis_pcnt >> 8; + + case 0x9ae8: + if (!s3->blitter_busy) + wake_fifo_thread(s3); + if (FIFO_FULL) + return 0xff; /*FIFO full*/ + return 0; /*FIFO empty*/ + case 0x9ae9: + if (!s3->blitter_busy) + wake_fifo_thread(s3); + temp = 0; + if (!FIFO_EMPTY) + temp |= 0x02; /*Hardware busy*/ + else + temp |= 0x04; /*FIFO empty*/ + if (FIFO_FULL) + temp |= 0xf8; /*FIFO full*/ + return temp; + + case 0xa2e8: + s3_wait_fifo_idle(s3); + return s3->accel.bkgd_color & 0xff; + case 0xa2e9: + s3_wait_fifo_idle(s3); + return s3->accel.bkgd_color >> 8; + case 0xa2ea: + s3_wait_fifo_idle(s3); + return s3->accel.bkgd_color >> 16; + case 0xa2eb: + s3_wait_fifo_idle(s3); + return s3->accel.bkgd_color >> 24; + + case 0xa6e8: + s3_wait_fifo_idle(s3); + return s3->accel.frgd_color & 0xff; + case 0xa6e9: + s3_wait_fifo_idle(s3); + return s3->accel.frgd_color >> 8; + case 0xa6ea: + s3_wait_fifo_idle(s3); + return s3->accel.frgd_color >> 16; + case 0xa6eb: + s3_wait_fifo_idle(s3); + return s3->accel.frgd_color >> 24; + + case 0xaae8: + s3_wait_fifo_idle(s3); + return s3->accel.wrt_mask & 0xff; + case 0xaae9: + s3_wait_fifo_idle(s3); + return s3->accel.wrt_mask >> 8; + case 0xaaea: + s3_wait_fifo_idle(s3); + return s3->accel.wrt_mask >> 16; + case 0xaaeb: + s3_wait_fifo_idle(s3); + return s3->accel.wrt_mask >> 24; + + case 0xaee8: + s3_wait_fifo_idle(s3); + return s3->accel.rd_mask & 0xff; + case 0xaee9: + s3_wait_fifo_idle(s3); + return s3->accel.rd_mask >> 8; + case 0xaeea: + s3_wait_fifo_idle(s3); + return s3->accel.rd_mask >> 16; + case 0xaeeb: + s3_wait_fifo_idle(s3); + return s3->accel.rd_mask >> 24; + + case 0xb2e8: + s3_wait_fifo_idle(s3); + return s3->accel.color_cmp & 0xff; + case 0xb2e9: + s3_wait_fifo_idle(s3); + return s3->accel.color_cmp >> 8; + case 0xb2ea: + s3_wait_fifo_idle(s3); + return s3->accel.color_cmp >> 16; + case 0xb2eb: + s3_wait_fifo_idle(s3); + return s3->accel.color_cmp >> 24; + + case 0xb6e8: + s3_wait_fifo_idle(s3); + return s3->accel.bkgd_mix; + + case 0xbae8: + s3_wait_fifo_idle(s3); + return s3->accel.frgd_mix; + + case 0xbee8: + s3_wait_fifo_idle(s3); + temp = s3->accel.multifunc[0xf] & 0xf; + switch (temp) + { + case 0x0: return s3->accel.multifunc[0x0] & 0xff; + case 0x1: return s3->accel.multifunc[0x1] & 0xff; + case 0x2: return s3->accel.multifunc[0x2] & 0xff; + case 0x3: return s3->accel.multifunc[0x3] & 0xff; + case 0x4: return s3->accel.multifunc[0x4] & 0xff; + case 0x5: return s3->accel.multifunc[0xa] & 0xff; + case 0x6: return s3->accel.multifunc[0xe] & 0xff; + case 0x7: return s3->accel.cmd & 0xff; + case 0x8: return s3->accel.subsys_cntl & 0xff; + case 0x9: return s3->accel.setup_md & 0xff; + case 0xa: return s3->accel.multifunc[0xd] & 0xff; + } + return 0xff; + case 0xbee9: + s3_wait_fifo_idle(s3); + temp = s3->accel.multifunc[0xf] & 0xf; + s3->accel.multifunc[0xf]++; + switch (temp) + { + case 0x0: return s3->accel.multifunc[0x0] >> 8; + case 0x1: return s3->accel.multifunc[0x1] >> 8; + case 0x2: return s3->accel.multifunc[0x2] >> 8; + case 0x3: return s3->accel.multifunc[0x3] >> 8; + case 0x4: return s3->accel.multifunc[0x4] >> 8; + case 0x5: return s3->accel.multifunc[0xa] >> 8; + case 0x6: return s3->accel.multifunc[0xe] >> 8; + case 0x7: return s3->accel.cmd >> 8; + case 0x8: return (s3->accel.subsys_cntl >> 8) & ~0xe000; + case 0x9: return (s3->accel.setup_md >> 8) & ~0xf000; + case 0xa: return s3->accel.multifunc[0xd] >> 8; + } + return 0xff; + + case 0xe2e8: case 0xe2e9: case 0xe2ea: case 0xe2eb: /*PIX_TRANS*/ + break; + } + return 0; +} + +void s3_accel_write(uint32_t addr, uint8_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; +// pclog("s3_accel_write %08x %02x\n", addr, val); + s3_queue(s3, addr & 0xffff, val, FIFO_WRITE_BYTE); +} +void s3_accel_write_w(uint32_t addr, uint16_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; +// pclog("s3_accel_write_w %08x %04x\n", addr, val); + s3_queue(s3, addr & 0xffff, val, FIFO_WRITE_WORD); +} +void s3_accel_write_l(uint32_t addr, uint32_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; +// pclog("s3_accel_write_l %08x %08x\n", addr, val); + s3_queue(s3, addr & 0xffff, val, FIFO_WRITE_DWORD); +} + +uint8_t s3_accel_read(uint32_t addr, void *p) +{ + if (addr & 0x8000) + return s3_accel_in(addr & 0xffff, p); + return 0; +} + +#define READ(addr, dat) if (s3->bpp == 0) dat = svga->vram[ (addr) & s3->vram_mask]; \ + else if (s3->bpp == 1) dat = vram_w[(addr) & (s3->vram_mask >> 1)]; \ + else dat = vram_l[(addr) & (s3->vram_mask >> 2)]; + +#define MIX switch ((mix_dat & mix_mask) ? (s3->accel.frgd_mix & 0xf) : (s3->accel.bkgd_mix & 0xf)) \ + { \ + case 0x0: dest_dat = ~dest_dat; break; \ + case 0x1: dest_dat = 0; break; \ + case 0x2: dest_dat = ~0; break; \ + case 0x3: dest_dat = dest_dat; break; \ + case 0x4: dest_dat = ~src_dat; break; \ + case 0x5: dest_dat = src_dat ^ dest_dat; break; \ + case 0x6: dest_dat = ~(src_dat ^ dest_dat); break; \ + case 0x7: dest_dat = src_dat; break; \ + case 0x8: dest_dat = ~(src_dat & dest_dat); break; \ + case 0x9: dest_dat = ~src_dat | dest_dat; break; \ + case 0xa: dest_dat = src_dat | ~dest_dat; break; \ + case 0xb: dest_dat = src_dat | dest_dat; break; \ + case 0xc: dest_dat = src_dat & dest_dat; break; \ + case 0xd: dest_dat = src_dat & ~dest_dat; break; \ + case 0xe: dest_dat = ~src_dat & dest_dat; break; \ + case 0xf: dest_dat = ~(src_dat | dest_dat); break; \ + } + + +#define WRITE(addr) if (s3->bpp == 0) \ + { \ + svga->vram[(addr) & s3->vram_mask] = dest_dat; \ + svga->changedvram[((addr) & s3->vram_mask) >> 12] = changeframecount; \ + } \ + else if (s3->bpp == 1) \ + { \ + vram_w[(addr) & (s3->vram_mask >> 1)] = dest_dat; \ + svga->changedvram[((addr) & (s3->vram_mask >> 1)) >> 11] = changeframecount; \ + } \ + else \ + { \ + vram_l[(addr) & (s3->vram_mask >> 2)] = dest_dat; \ + svga->changedvram[((addr) & (s3->vram_mask >> 2)) >> 10] = changeframecount; \ + } + +void s3_accel_start(int count, int cpu_input, uint32_t mix_dat, uint32_t cpu_dat, s3_t *s3) +{ + svga_t *svga = &s3->svga; + uint32_t src_dat, dest_dat; + int frgd_mix, bkgd_mix; + int clip_t = s3->accel.multifunc[1] & 0xfff; + int clip_l = s3->accel.multifunc[2] & 0xfff; + int clip_b = s3->accel.multifunc[3] & 0xfff; + int clip_r = s3->accel.multifunc[4] & 0xfff; + int vram_mask = (s3->accel.multifunc[0xa] & 0xc0) == 0xc0; + uint32_t mix_mask; + uint16_t *vram_w = (uint16_t *)svga->vram; + uint32_t *vram_l = (uint32_t *)svga->vram; + uint32_t compare = s3->accel.color_cmp; + int compare_mode = (s3->accel.multifunc[0xe] >> 7) & 3; +//return; +// if (!cpu_input) pclog("Start S3 command %i %i, %i %i, %i (clip %i, %i to %i, %i %i)\n", s3->accel.cmd >> 13, s3->accel.cur_x, s3->accel.cur_y, s3->accel.maj_axis_pcnt & 0xfff, s3->accel.multifunc[0] & 0xfff, clip_l, clip_t, clip_r, clip_b, s3->accel.multifunc[0xe] & 0x20); +// else pclog(" S3 command %i, %i, %08x %08x\n", s3->accel.cmd >> 13, count, mix_dat, cpu_dat); + + if (!cpu_input) s3->accel.dat_count = 0; + if (cpu_input && (s3->accel.multifunc[0xa] & 0xc0) != 0x80) + { + if (s3->bpp == 3 && count == 2) + { + if (s3->accel.dat_count) + { + cpu_dat = ((cpu_dat & 0xffff) << 16) | s3->accel.dat_buf; + count = 4; + s3->accel.dat_count = 0; + } + else + { + s3->accel.dat_buf = cpu_dat & 0xffff; + s3->accel.dat_count = 1; + } + } + if (s3->bpp == 1) count >>= 1; + if (s3->bpp == 3) count >>= 2; + } + + switch (s3->accel.cmd & 0x600) + { + case 0x000: mix_mask = 0x80; break; + case 0x200: mix_mask = 0x8000; break; + case 0x400: mix_mask = 0x80000000; break; + case 0x600: mix_mask = 0x80000000; break; + } + + if (s3->bpp == 0) compare &= 0xff; + if (s3->bpp == 1) compare &= 0xffff; + switch (s3->accel.cmd >> 13) + { + case 1: /*Draw line*/ + if (!cpu_input) /*!cpu_input is trigger to start operation*/ + { + s3->accel.cx = s3->accel.cur_x; + if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff; + s3->accel.cy = s3->accel.cur_y; + if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; + + s3->accel.sy = s3->accel.maj_axis_pcnt; + } + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + + if (s3->accel.cmd & 8) /*Radial*/ + { + while (count-- && s3->accel.sy >= 0) + { + if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r && + s3->accel.cy >= clip_t && s3->accel.cy <= clip_b) + { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: src_dat = 0; break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); + + MIX + + WRITE((s3->accel.cy * s3->width) + s3->accel.cx); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + if (!s3->accel.sy) + break; + + switch (s3->accel.cmd & 0xe0) + { + case 0x00: s3->accel.cx++; break; + case 0x20: s3->accel.cx++; s3->accel.cy--; break; + case 0x40: s3->accel.cy--; break; + case 0x60: s3->accel.cx--; s3->accel.cy--; break; + case 0x80: s3->accel.cx--; break; + case 0xa0: s3->accel.cx--; s3->accel.cy++; break; + case 0xc0: s3->accel.cy++; break; + case 0xe0: s3->accel.cx++; s3->accel.cy++; break; + } + s3->accel.sy--; + } + s3->accel.cur_x = s3->accel.cx; + s3->accel.cur_y = s3->accel.cy; + } + else /*Bresenham*/ + { + while (count-- && s3->accel.sy >= 0) + { + if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r && + s3->accel.cy >= clip_t && s3->accel.cy <= clip_b) + { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: src_dat = 0; break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ((s3->accel.cy * s3->width) + s3->accel.cx, dest_dat); + +// pclog("Line : %04i, %04i (%06X) - %02X (%02X %04X %05X) %02X (%02X %02X) ", s3->accel.cx, s3->accel.cy, s3->accel.dest + s3->accel.cx, src_dat, vram[s3->accel.src + s3->accel.cx], mix_dat & mix_mask, s3->accel.src + s3->accel.cx, dest_dat, s3->accel.frgd_color, s3->accel.bkgd_color); + + MIX + +// pclog("%02X\n", dest_dat); + + WRITE((s3->accel.cy * s3->width) + s3->accel.cx); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + +// pclog("%i, %i - %i %i %i %i\n", s3->accel.cx, s3->accel.cy, s3->accel.err_term, s3->accel.maj_axis_pcnt, s3->accel.desty_axstp, s3->accel.destx_distp); + + if (!s3->accel.sy) + break; + + if (s3->accel.err_term >= s3->accel.maj_axis_pcnt) + { + s3->accel.err_term += s3->accel.destx_distp; + /*Step minor axis*/ + switch (s3->accel.cmd & 0xe0) + { + case 0x00: s3->accel.cy--; break; + case 0x20: s3->accel.cy--; break; + case 0x40: s3->accel.cx--; break; + case 0x60: s3->accel.cx++; break; + case 0x80: s3->accel.cy++; break; + case 0xa0: s3->accel.cy++; break; + case 0xc0: s3->accel.cx--; break; + case 0xe0: s3->accel.cx++; break; + } + } + else + s3->accel.err_term += s3->accel.desty_axstp; + + /*Step major axis*/ + switch (s3->accel.cmd & 0xe0) + { + case 0x00: s3->accel.cx--; break; + case 0x20: s3->accel.cx++; break; + case 0x40: s3->accel.cy--; break; + case 0x60: s3->accel.cy--; break; + case 0x80: s3->accel.cx--; break; + case 0xa0: s3->accel.cx++; break; + case 0xc0: s3->accel.cy++; break; + case 0xe0: s3->accel.cy++; break; + } + s3->accel.sy--; + } + s3->accel.cur_x = s3->accel.cx; + s3->accel.cur_y = s3->accel.cy; + } + break; + + case 2: /*Rectangle fill*/ + if (!cpu_input) /*!cpu_input is trigger to start operation*/ + { + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + s3->accel.sy = s3->accel.multifunc[0] & 0xfff; + s3->accel.cx = s3->accel.cur_x; + if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff; + s3->accel.cy = s3->accel.cur_y; + if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; + + s3->accel.dest = s3->accel.cy * s3->width; + +// pclog("Dest %08X (%i, %i) %04X %04X\n", s3->accel.dest, s3->accel.cx, s3->accel.cy, s3->accel.cur_x, s3->accel.cur_x & 0x1000); + } + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ +// if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !cpu_input) /*Mix data from CPU*/ +// return; + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + + while (count-- && s3->accel.sy >= 0) + { + if (s3->accel.cx >= clip_l && s3->accel.cx <= clip_r && + s3->accel.cy >= clip_t && s3->accel.cy <= clip_b) + { + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: src_dat = 0; break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ(s3->accel.dest + s3->accel.cx, dest_dat); + + +// if (CS != 0xc000) pclog("Write %05X %02X %02X %04X (%02X %02X) ", s3->accel.dest + s3->accel.cx, src_dat, dest_dat, mix_dat, s3->accel.frgd_mix, s3->accel.bkgd_mix); + + MIX + +// if (CS != 0xc000) pclog("%02X\n", dest_dat); + + WRITE(s3->accel.dest + s3->accel.cx); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + if (s3->accel.cmd & 0x20) s3->accel.cx++; + else s3->accel.cx--; + s3->accel.sx--; + if (s3->accel.sx < 0) + { + if (s3->accel.cmd & 0x20) s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + else s3->accel.cx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; +// s3->accel.dest -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + +// s3->accel.dest += s3_width; + if (s3->accel.cmd & 0x80) s3->accel.cy++; + else s3->accel.cy--; + + s3->accel.dest = s3->accel.cy * s3->width; + s3->accel.sy--; + + if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return; + if (s3->accel.sy < 0) + { + s3->accel.cur_x = s3->accel.cx; + s3->accel.cur_y = s3->accel.cy; + return; + } + } + } + break; + + case 6: /*BitBlt*/ + if (!cpu_input) /*!cpu_input is trigger to start operation*/ + { + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + s3->accel.sy = s3->accel.multifunc[0] & 0xfff; + + s3->accel.dx = s3->accel.destx_distp & 0xfff; + if (s3->accel.destx_distp & 0x1000) s3->accel.dx |= ~0xfff; + s3->accel.dy = s3->accel.desty_axstp & 0xfff; + if (s3->accel.desty_axstp & 0x1000) s3->accel.dy |= ~0xfff; + + s3->accel.cx = s3->accel.cur_x & 0xfff; + if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff; + s3->accel.cy = s3->accel.cur_y & 0xfff; + if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; + + s3->accel.src = s3->accel.cy * s3->width; + s3->accel.dest = s3->accel.dy * s3->width; + +// pclog("Source %08X Dest %08X (%i, %i) - (%i, %i)\n", s3->accel.src, s3->accel.dest, s3->accel.cx, s3->accel.cy, s3->accel.dx, s3->accel.dy); + } + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ +// if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !cpu_input) /*Mix data from CPU*/ +// return; + + if (s3->accel.sy < 0) + return; + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + + if (!cpu_input && frgd_mix == 3 && !vram_mask && !compare_mode && + (s3->accel.cmd & 0xa0) == 0xa0 && (s3->accel.frgd_mix & 0xf) == 7) + { + while (1) + { + if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r && + s3->accel.dy >= clip_t && s3->accel.dy <= clip_b) + { + READ(s3->accel.src + s3->accel.cx, src_dat); + + dest_dat = src_dat; + + WRITE(s3->accel.dest + s3->accel.dx); + } + + s3->accel.cx++; + s3->accel.dx++; + s3->accel.sx--; + if (s3->accel.sx < 0) + { + s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + + s3->accel.cy++; + s3->accel.dy++; + + s3->accel.src = s3->accel.cy * s3->width; + s3->accel.dest = s3->accel.dy * s3->width; + + s3->accel.sy--; + + if (s3->accel.sy < 0) + { + s3->accel.cur_x = s3->accel.cx; + s3->accel.cur_y = s3->accel.cy; + return; + } + } + } + } + else + { + while (count-- && s3->accel.sy >= 0) + { + if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r && + s3->accel.dy >= clip_t && s3->accel.dy <= clip_b) + { + if (vram_mask) + { + READ(s3->accel.src + s3->accel.cx, mix_dat) + mix_dat = mix_dat ? mix_mask : 0; + } + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: READ(s3->accel.src + s3->accel.cx, src_dat); break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ(s3->accel.dest + s3->accel.dx, dest_dat); + +// pclog("BitBlt : %04i, %04i (%06X) - %02X (%02X %04X %05X) %02X ", s3->accel.dx, s3->accel.dy, s3->accel.dest + s3->accel.dx, src_dat, vram[s3->accel.src + s3->accel.cx], mix_dat, s3->accel.src + s3->accel.cx, dest_dat); + + MIX + +// pclog("%02X\n", dest_dat); + + WRITE(s3->accel.dest + s3->accel.dx); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + if (s3->accel.cmd & 0x20) + { + s3->accel.cx++; + s3->accel.dx++; + } + else + { + s3->accel.cx--; + s3->accel.dx--; + } + s3->accel.sx--; + if (s3->accel.sx < 0) + { + if (s3->accel.cmd & 0x20) + { + s3->accel.cx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + } + else + { + s3->accel.cx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; + s3->accel.dx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; + } + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + + if (s3->accel.cmd & 0x80) + { + s3->accel.cy++; + s3->accel.dy++; + } + else + { + s3->accel.cy--; + s3->accel.dy--; + } + + s3->accel.src = s3->accel.cy * s3->width; + s3->accel.dest = s3->accel.dy * s3->width; + + s3->accel.sy--; + + if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return; + if (s3->accel.sy < 0) + { +// s3->accel.cur_x = s3->accel.cx; +// s3->accel.cur_y = s3->accel.cy; + return; + } + } + } + } + break; + + case 7: /*Pattern fill - BitBlt but with source limited to 8x8*/ + if (!cpu_input) /*!cpu_input is trigger to start operation*/ + { + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + s3->accel.sy = s3->accel.multifunc[0] & 0xfff; + + s3->accel.dx = s3->accel.destx_distp & 0xfff; + if (s3->accel.destx_distp & 0x1000) s3->accel.dx |= ~0xfff; + s3->accel.dy = s3->accel.desty_axstp & 0xfff; + if (s3->accel.desty_axstp & 0x1000) s3->accel.dy |= ~0xfff; + + s3->accel.cx = s3->accel.cur_x & 0xfff; + if (s3->accel.cur_x & 0x1000) s3->accel.cx |= ~0xfff; + s3->accel.cy = s3->accel.cur_y & 0xfff; + if (s3->accel.cur_y & 0x1000) s3->accel.cy |= ~0xfff; + + /*Align source with destination*/ +// s3->accel.cx = (s3->accel.cx & ~7) | (s3->accel.dx & 7); +// s3->accel.cy = (s3->accel.cy & ~7) | (s3->accel.dy & 7); + + s3->accel.pattern = (s3->accel.cy * s3->width) + s3->accel.cx; + s3->accel.dest = s3->accel.dy * s3->width; + + s3->accel.cx = s3->accel.dx & 7; + s3->accel.cy = s3->accel.dy & 7; + + s3->accel.src = s3->accel.pattern + (s3->accel.cy * s3->width); + +// pclog("Source %08X Dest %08X (%i, %i) - (%i, %i)\n", s3->accel.src, s3->accel.dest, s3->accel.cx, s3->accel.cy, s3->accel.dx, s3->accel.dy); +// dumpregs(); +// exit(-1); + } + if ((s3->accel.cmd & 0x100) && !cpu_input) return; /*Wait for data from CPU*/ +// if ((s3->accel.multifunc[0xa] & 0xc0) == 0x80 && !cpu_input) /*Mix data from CPU*/ +// return; + + frgd_mix = (s3->accel.frgd_mix >> 5) & 3; + bkgd_mix = (s3->accel.bkgd_mix >> 5) & 3; + + while (count-- && s3->accel.sy >= 0) + { + if (s3->accel.dx >= clip_l && s3->accel.dx <= clip_r && + s3->accel.dy >= clip_t && s3->accel.dy <= clip_b) + { + if (vram_mask) + { + READ(s3->accel.src + s3->accel.cx, mix_dat) + mix_dat = mix_dat ? mix_mask : 0; + } + switch ((mix_dat & mix_mask) ? frgd_mix : bkgd_mix) + { + case 0: src_dat = s3->accel.bkgd_color; break; + case 1: src_dat = s3->accel.frgd_color; break; + case 2: src_dat = cpu_dat; break; + case 3: READ(s3->accel.src + s3->accel.cx, src_dat); break; + } + + if ((compare_mode == 2 && src_dat != compare) || + (compare_mode == 3 && src_dat == compare) || + compare_mode < 2) + { + READ(s3->accel.dest + s3->accel.dx, dest_dat); + +// pclog("Pattern fill : %04i, %04i (%06X) - %02X (%02X %04X %05X) %02X ", s3->accel.dx, s3->accel.dy, s3->accel.dest + s3->accel.dx, src_dat, vram[s3->accel.src + s3->accel.cx], mix_dat, s3->accel.src + s3->accel.cx, dest_dat); + + MIX + +// pclog("%02X\n", dest_dat); + + WRITE(s3->accel.dest + s3->accel.dx); + } + } + + mix_dat <<= 1; + mix_dat |= 1; + if (s3->bpp == 0) cpu_dat >>= 8; + else cpu_dat >>= 16; + + if (s3->accel.cmd & 0x20) + { + s3->accel.cx = ((s3->accel.cx + 1) & 7) | (s3->accel.cx & ~7); + s3->accel.dx++; + } + else + { + s3->accel.cx = ((s3->accel.cx - 1) & 7) | (s3->accel.cx & ~7); + s3->accel.dx--; + } + s3->accel.sx--; + if (s3->accel.sx < 0) + { + if (s3->accel.cmd & 0x20) + { + s3->accel.cx = ((s3->accel.cx - ((s3->accel.maj_axis_pcnt & 0xfff) + 1)) & 7) | (s3->accel.cx & ~7); + s3->accel.dx -= (s3->accel.maj_axis_pcnt & 0xfff) + 1; + } + else + { + s3->accel.cx = ((s3->accel.cx + ((s3->accel.maj_axis_pcnt & 0xfff) + 1)) & 7) | (s3->accel.cx & ~7); + s3->accel.dx += (s3->accel.maj_axis_pcnt & 0xfff) + 1; + } + s3->accel.sx = s3->accel.maj_axis_pcnt & 0xfff; + + if (s3->accel.cmd & 0x80) + { + s3->accel.cy = ((s3->accel.cy + 1) & 7) | (s3->accel.cy & ~7); + s3->accel.dy++; + } + else + { + s3->accel.cy = ((s3->accel.cy - 1) & 7) | (s3->accel.cy & ~7); + s3->accel.dy--; + } + + s3->accel.src = s3->accel.pattern + (s3->accel.cy * s3->width); + s3->accel.dest = s3->accel.dy * s3->width; + + s3->accel.sy--; + + if (cpu_input/* && (s3->accel.multifunc[0xa] & 0xc0) == 0x80*/) return; + if (s3->accel.sy < 0) + return; + } + } + break; + } +} + +void s3_hwcursor_draw(svga_t *svga, int displine) +{ + int x; + uint16_t dat[2]; + int xx; + int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; + int y_add = enable_overscan ? 16 : 0; + int x_add = enable_overscan ? 8 : 0; + + if (svga->interlace && svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += 16; + +// pclog("HWcursor %i %i\n", svga->hwcursor_latch.x, svga->hwcursor_latch.y); + for (x = 0; x < 64; x += 16) + { + dat[0] = (svga->vram[svga->hwcursor_latch.addr] << 8) | svga->vram[svga->hwcursor_latch.addr + 1]; + dat[1] = (svga->vram[svga->hwcursor_latch.addr + 2] << 8) | svga->vram[svga->hwcursor_latch.addr + 3]; + for (xx = 0; xx < 16; xx++) + { + if (offset >= svga->hwcursor_latch.x) + { + if (!(dat[0] & 0x8000)) + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = (dat[1] & 0x8000) ? 0xffffff : 0; + else if (dat[1] & 0x8000) + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] ^= 0xffffff; +// pclog("Plot %i, %i (%i %i) %04X %04X\n", offset, displine, x+xx, svga_hwcursor_on, dat[0], dat[1]); + } + + offset++; + dat[0] <<= 1; + dat[1] <<= 1; + } + svga->hwcursor_latch.addr += 4; + } + if (svga->interlace && !svga->hwcursor_oddeven) + svga->hwcursor_latch.addr += 16; +} + + +static void s3_io_remove(s3_t *s3) +{ + io_removehandler(0x03c0, 0x0020, s3_in, NULL, NULL, s3_out, NULL, NULL, s3); + + io_removehandler(0x42e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x46e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x4ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x82e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x86e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x8ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x8ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x92e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x96e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x9ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0x9ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xa2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xa6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xaae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xaee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xb2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xb6e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xbae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xbee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_removehandler(0xe2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); +} + +static void s3_io_set(s3_t *s3) +{ + s3_io_remove(s3); + + io_sethandler(0x03c0, 0x0020, s3_in, NULL, NULL, s3_out, NULL, NULL, s3); + + io_sethandler(0x42e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x46e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x4ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x82e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x86e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x8ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x92e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x96e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x9ae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0x9ee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xa2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xa6e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xaae8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xaee8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xb2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xb6e8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xbae8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xbee8, 0x0002, s3_accel_in, NULL, NULL, s3_accel_out, NULL, NULL, s3); + io_sethandler(0xe2e8, 0x0004, s3_accel_in, NULL, NULL, s3_accel_out, s3_accel_out_w, s3_accel_out_l, s3); +} + + +uint8_t s3_pci_read(int func, int addr, void *p) +{ + s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; +// pclog("S3 PCI read %08X\n", addr); + switch (addr) + { + case 0x00: return 0x33; /*'S3'*/ + case 0x01: return 0x53; + + case 0x02: return s3->id_ext_pci; + case 0x03: return 0x88; + + case PCI_REG_COMMAND: + return s3->pci_regs[PCI_REG_COMMAND]; /*Respond to IO and memory accesses*/ + + case 0x07: return 1 << 1; /*Medium DEVSEL timing*/ + + case 0x08: return 0; /*Revision ID*/ + case 0x09: return 0; /*Programming interface*/ + + case 0x0a: return 0x00; /*Supports VGA interface*/ + case 0x0b: return 0x03; + + case 0x10: return 0x00; /*Linear frame buffer address*/ + case 0x11: return 0x00; + case 0x12: return svga->crtc[0x5a] & 0x80; + case 0x13: return svga->crtc[0x59]; + + case 0x30: return s3->pci_regs[0x30] & 0x01; /*BIOS ROM address*/ + case 0x31: return 0x00; + case 0x32: return s3->pci_regs[0x32]; + case 0x33: return s3->pci_regs[0x33]; + } + return 0; +} + +void s3_pci_write(int func, int addr, uint8_t val, void *p) +{ + s3_t *s3 = (s3_t *)p; + svga_t *svga = &s3->svga; +// pclog("s3_pci_write: addr=%02x val=%02x\n", addr, val); + switch (addr) + { + case PCI_REG_COMMAND: + if (romset == ROM_KN97) return; + s3->pci_regs[PCI_REG_COMMAND] = val & 0x27; + if (val & PCI_COMMAND_IO) + s3_io_set(s3); + else + s3_io_remove(s3); + s3_updatemapping(s3); + break; + + case 0x12: + svga->crtc[0x5a] = val & 0x80; + s3_updatemapping(s3); + break; + case 0x13: + svga->crtc[0x59] = val; + s3_updatemapping(s3); + break; + + case 0x30: case 0x32: case 0x33: + s3->pci_regs[addr] = val; + if (s3->pci_regs[0x30] & 0x01) + { + uint32_t addr = (s3->pci_regs[0x32] << 16) | (s3->pci_regs[0x33] << 24); +// pclog("S3 bios_rom enabled at %08x\n", addr); + mem_mapping_set_addr(&s3->bios_rom.mapping, addr, 0x8000); + } + else + { +// pclog("S3 bios_rom disabled\n"); + mem_mapping_disable(&s3->bios_rom.mapping); + } + return; + } +} + +static int vram_sizes[] = +{ + 7, /*512 kB*/ + 6, /*1 MB*/ + 4, /*2 MB*/ + 0, + 0, /*4 MB*/ + 0, + 0, + 0, + 3 /*8 MB*/ +}; + +static void *s3_init(char *bios_fn, int chip) +{ + s3_t *s3 = malloc(sizeof(s3_t)); + svga_t *svga = &s3->svga; + int vram; + uint32_t vram_size; + + memset(s3, 0, sizeof(s3_t)); + + vram = device_get_config_int("memory"); + if (vram) + vram_size = vram << 20; + else + vram_size = 512 << 10; + s3->vram_mask = vram_size - 1; + + rom_init(&s3->bios_rom, bios_fn, 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + if (PCI) + mem_mapping_disable(&s3->bios_rom.mapping); + + mem_mapping_add(&s3->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL, MEM_MAPPING_EXTERNAL, &s3->svga); + mem_mapping_add(&s3->mmio_mapping, 0xa0000, 0x10000, s3_accel_read, NULL, NULL, s3_accel_write, s3_accel_write_w, s3_accel_write_l, NULL, MEM_MAPPING_EXTERNAL, s3); + mem_mapping_disable(&s3->mmio_mapping); + + svga_init(&s3->svga, s3, vram_size, /*4mb - 864 supports 8mb but buggy VESA driver reports 0mb*/ + s3_recalctimings, + s3_in, s3_out, + s3_hwcursor_draw, + NULL); + + if (PCI) + svga->crtc[0x36] = 2 | (3 << 2) | (1 << 4) | (vram_sizes[vram] << 5); + else + svga->crtc[0x36] = 1 | (3 << 2) | (1 << 4) | (vram_sizes[vram] << 5); + svga->crtc[0x37] = 1 | (7 << 5); + + s3_io_set(s3); + + pci_add(s3_pci_read, s3_pci_write, s3); + + s3->pci_regs[0x04] = 7; + + s3->pci_regs[0x30] = 0x00; + s3->pci_regs[0x32] = 0x0c; + s3->pci_regs[0x33] = 0x00; + + s3->chip = chip; + + s3->wake_fifo_thread = thread_create_event(); + s3->fifo_not_full_event = thread_create_event(); + s3->fifo_thread = thread_create(fifo_thread, s3); + + return s3; +} + +void *s3_bahamas64_init() +{ + s3_t *s3 = s3_init("roms/bahamas64.BIN", S3_VISION864); + + s3->id = 0xc1; /*Vision864P*/ + s3->id_ext = s3->id_ext_pci = 0xc1; + s3->packed_mmio = 0; + + s3->getclock = sdac_getclock; + s3->getclock_p = &s3->ramdac; + + return s3; +} + +int s3_bahamas64_available() +{ + return rom_present("roms/bahamas64.BIN"); +} + +void *s3_9fx_init() +{ + s3_t *s3 = s3_init("roms/s3_764.bin", S3_TRIO64); + + s3->id = 0xe1; /*Trio64*/ + s3->id_ext = s3->id_ext_pci = 0x11; + s3->packed_mmio = 1; + + s3->getclock = s3_trio64_getclock; + s3->getclock_p = s3; + + return s3; +} + +int s3_9fx_available() +{ + return rom_present("roms/s3_764.bin"); +} + +void *s3_phoenix_trio32_init() +{ + s3_t *s3 = s3_init("roms/86C732P.bin", S3_TRIO32); + svga_t *svga = &s3->svga; + + s3->id = 0xe1; /*Trio32*/ + s3->id_ext = 0x10; + s3->id_ext_pci = 0x11; + s3->packed_mmio = 1; + + s3->getclock = s3_trio64_getclock; + s3->getclock_p = s3; + + return s3; +} + +int s3_phoenix_trio32_available() +{ + return rom_present("roms/86C732P.bin"); +} + +void *s3_phoenix_trio64_init() +{ + s3_t *s3 = s3_init("roms/86c764x1.bin", S3_TRIO64); + svga_t *svga = &s3->svga; + + s3->id = 0xe1; /*Trio64*/ + s3->id_ext = s3->id_ext_pci = 0x11; + s3->packed_mmio = 1; + + s3->getclock = s3_trio64_getclock; + s3->getclock_p = s3; + + return s3; +} + +int s3_phoenix_trio64_available() +{ + return rom_present("roms/86c764x1.bin"); +} + +void *s3_miro_vision964_init() +{ + s3_t *s3 = s3_init("roms/VISION864P.BIN", S3_VISION864); + + s3->id = 0xc1; /*Vision864P*/ + s3->id_ext = s3->id_ext_pci = 0xc1; + s3->packed_mmio = 1; + + s3->getclock = sdac_getclock; + s3->getclock_p = &s3->ramdac; + + return s3; +} + +int s3_miro_vision964_available() +{ + return rom_present("roms/VISION864P.BIN"); +} + +void s3_close(void *p) +{ + s3_t *s3 = (s3_t *)p; + + svga_close(&s3->svga); + + free(s3); +} + +void s3_speed_changed(void *p) +{ + s3_t *s3 = (s3_t *)p; + + svga_recalctimings(&s3->svga); +} + +void s3_force_redraw(void *p) +{ + s3_t *s3 = (s3_t *)p; + + s3->svga.fullchange = changeframecount; +} + +void s3_add_status_info(char *s, int max_len, void *p) +{ + s3_t *s3 = (s3_t *)p; + char temps[256]; + uint64_t new_time = timer_read(); + uint64_t status_diff = new_time - s3->status_time; + s3->status_time = new_time; + + if (!status_diff) + status_diff = 1; + + svga_add_status_info(s, max_len, &s3->svga); + sprintf(temps, "%f%% CPU\n%f%% CPU (real)\n\n", ((double)s3->blitter_time * 100.0) / timer_freq, ((double)s3->blitter_time * 100.0) / status_diff); + strncat(s, temps, max_len); + + s3->blitter_time = 0; +} + +static device_config_t s3_bahamas64_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + /*Vision864 also supports 8 MB, however the Paradise BIOS is buggy (VESA modes don't work correctly)*/ + { + .description = "" + } + }, + .default_int = 4 + }, + { + .type = -1 + } +}; + +static device_config_t s3_9fx_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + /*Trio64 also supports 4 MB, however the Number Nine BIOS does not*/ + { + .description = "" + } + }, + .default_int = 2 + }, + { + .type = -1 + } +}; + +static device_config_t s3_phoenix_trio32_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "512 KB", + .value = 0 + }, + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "" + } + }, + .default_int = 2 + }, + { + .type = -1 + } +}; + +static device_config_t s3_phoenix_trio64_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "512 KB", + .value = 0 + }, + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } + }, + .default_int = 2 + }, + { + .type = -1 + } +}; + +static device_config_t s3_miro_vision964_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "3 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "6 MB", + .value = 4 + }, + { + .description = "8 MB", + .value = 8 + }, + /*Vision864 also supports 8 MB, however the Paradise BIOS is buggy (VESA modes don't work correctly)*/ + { + .description = "" + } + }, + .default_int = 4 + }, + { + .type = -1 + } +}; + +device_t s3_bahamas64_device = +{ + "Paradise Bahamas 64 (S3 Vision864)", + 0, + s3_bahamas64_init, + s3_close, + s3_bahamas64_available, + s3_speed_changed, + s3_force_redraw, + s3_add_status_info, + s3_bahamas64_config +}; + +device_t s3_9fx_device = +{ + "Number 9 9FX (S3 Trio64)", + 0, + s3_9fx_init, + s3_close, + s3_9fx_available, + s3_speed_changed, + s3_force_redraw, + s3_add_status_info, + s3_9fx_config +}; + +device_t s3_phoenix_trio32_device = +{ + "Phoenix S3 Trio32", + 0, + s3_phoenix_trio32_init, + s3_close, + s3_phoenix_trio32_available, + s3_speed_changed, + s3_force_redraw, + s3_add_status_info, + s3_phoenix_trio32_config +}; + +device_t s3_phoenix_trio64_device = +{ + "Phoenix S3 Trio64", + 0, + s3_phoenix_trio64_init, + s3_close, + s3_phoenix_trio64_available, + s3_speed_changed, + s3_force_redraw, + s3_add_status_info, + s3_phoenix_trio64_config +}; + +device_t s3_miro_vision964_device = +{ + "Micro Crystal S3 Vision964", + 0, + s3_miro_vision964_init, + s3_close, + s3_miro_vision964_available, + s3_speed_changed, + s3_force_redraw, + s3_add_status_info, + s3_miro_vision964_config +}; diff --git a/src/vid_s3.h b/src/vid_s3.h new file mode 100644 index 000000000..fe10bf7be --- /dev/null +++ b/src/vid_s3.h @@ -0,0 +1,5 @@ +device_t s3_bahamas64_device; +device_t s3_9fx_device; +device_t s3_phoenix_trio32_device; +device_t s3_phoenix_trio64_device; +device_t s3_miro_vision964_device; diff --git a/src/vid_s3_virge.c b/src/vid_s3_virge.c new file mode 100644 index 000000000..fe0cb1f09 --- /dev/null +++ b/src/vid_s3_virge.c @@ -0,0 +1,4071 @@ +/*S3 ViRGE emulation*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "pci.h" +#include "rom.h" +#include "thread.h" +#include "video.h" +#include "vid_s3_virge.h" +#include "vid_svga.h" +#include "vid_svga_render.h" + +static uint64_t virge_time = 0; +static uint64_t status_time = 0; +static int reg_writes = 0, reg_reads = 0; + +static int dither[4][4] = +{ + 0, 4, 1, 5, + 6, 2, 7, 3, + 1, 5, 0, 4, + 7, 3, 6, 2, +}; + +#define RB_SIZE 256 +#define RB_MASK (RB_SIZE - 1) + +#define RB_ENTRIES (virge->s3d_write_idx - virge->s3d_read_idx) +#define RB_FULL (RB_ENTRIES == RB_SIZE) +#define RB_EMPTY (!RB_ENTRIES) + +#define FIFO_SIZE 65536 +#define FIFO_MASK (FIFO_SIZE - 1) +#define FIFO_ENTRY_SIZE (1 << 31) + +#define FIFO_ENTRIES (virge->fifo_write_idx - virge->fifo_read_idx) +#define FIFO_FULL ((virge->fifo_write_idx - virge->fifo_read_idx) >= FIFO_SIZE) +#define FIFO_EMPTY (virge->fifo_read_idx == virge->fifo_write_idx) + +#define FIFO_TYPE 0xff000000 +#define FIFO_ADDR 0x00ffffff + +enum +{ + FIFO_INVALID = (0x00 << 24), + FIFO_WRITE_BYTE = (0x01 << 24), + FIFO_WRITE_WORD = (0x02 << 24), + FIFO_WRITE_DWORD = (0x03 << 24), +}; + +typedef struct +{ + uint32_t addr_type; + uint32_t val; +} fifo_entry_t; + +typedef struct s3d_t +{ + uint32_t cmd_set; + int clip_l, clip_r, clip_t, clip_b; + + uint32_t dest_base; + uint32_t dest_str; + + uint32_t z_base; + uint32_t z_str; + + uint32_t tex_base; + uint32_t tex_bdr_clr; + uint32_t tbv, tbu; + int32_t TdVdX, TdUdX; + int32_t TdVdY, TdUdY; + uint32_t tus, tvs; + + int32_t TdZdX, TdZdY; + uint32_t tzs; + + int32_t TdWdX, TdWdY; + uint32_t tws; + + int32_t TdDdX, TdDdY; + uint32_t tds; + + int16_t TdGdX, TdBdX, TdRdX, TdAdX; + int16_t TdGdY, TdBdY, TdRdY, TdAdY; + uint32_t tgs, tbs, trs, tas; + + uint32_t TdXdY12; + uint32_t txend12; + uint32_t TdXdY01; + uint32_t txend01; + uint32_t TdXdY02; + uint32_t txs; + uint32_t tys; + int ty01, ty12, tlr; +} s3d_t; + +typedef struct virge_t +{ + mem_mapping_t linear_mapping; + mem_mapping_t mmio_mapping; + mem_mapping_t new_mmio_mapping; + + rom_t bios_rom; + + svga_t svga; + + uint8_t bank; + uint8_t ma_ext; + int width; + int bpp; + + uint8_t virge_id, virge_id_high, virge_id_low, virge_rev; + + uint32_t linear_base, linear_size; + + uint8_t pci_regs[256]; + + int is_375; + + int bilinear_enabled; + int dithering_enabled; + int memory_size; + + int pixel_count, tri_count; + + thread_t *render_thread; + event_t *wake_render_thread; + event_t *wake_main_thread; + event_t *not_full_event; + + uint32_t hwcursor_col[2]; + int hwcursor_col_pos; + + struct + { + uint32_t src_base; + uint32_t dest_base; + int clip_l, clip_r, clip_t, clip_b; + int dest_str, src_str; + uint32_t mono_pat_0; + uint32_t mono_pat_1; + uint32_t pat_bg_clr; + uint32_t pat_fg_clr; + uint32_t src_bg_clr; + uint32_t src_fg_clr; + uint32_t cmd_set; + int r_width, r_height; + int rsrc_x, rsrc_y; + int rdest_x, rdest_y; + + int lxend0, lxend1; + int32_t ldx; + uint32_t lxstart, lystart; + int lycnt; + int line_dir; + + int src_x, src_y; + int dest_x, dest_y; + int w, h; + uint8_t rop; + + int data_left_count; + uint32_t data_left; + + uint32_t pattern_8[8*8]; + uint32_t pattern_16[8*8]; + uint32_t pattern_32[8*8]; + + uint32_t prdx; + uint32_t prxstart; + uint32_t pldx; + uint32_t plxstart; + uint32_t pystart; + uint32_t pycnt; + uint32_t dest_l, dest_r; + } s3d; + + s3d_t s3d_tri; + + s3d_t s3d_buffer[RB_SIZE]; + int s3d_read_idx, s3d_write_idx; + int s3d_busy; + + struct + { + uint32_t pri_ctrl; + uint32_t chroma_ctrl; + uint32_t sec_ctrl; + uint32_t chroma_upper_bound; + uint32_t sec_filter; + uint32_t blend_ctrl; + uint32_t pri_fb0, pri_fb1; + uint32_t pri_stride; + uint32_t buffer_ctrl; + uint32_t sec_fb0, sec_fb1; + uint32_t sec_stride; + uint32_t overlay_ctrl; + int32_t k1_vert_scale; + int32_t k2_vert_scale; + int32_t dda_vert_accumulator; + int32_t k1_horiz_scale; + int32_t k2_horiz_scale; + int32_t dda_horiz_accumulator; + uint32_t fifo_ctrl; + uint32_t pri_start; + uint32_t pri_size; + uint32_t sec_start; + uint32_t sec_size; + + int sdif; + + int pri_x, pri_y, pri_w, pri_h; + int sec_x, sec_y, sec_w, sec_h; + } streams; + + fifo_entry_t fifo[FIFO_SIZE]; + volatile int fifo_read_idx, fifo_write_idx; + + thread_t *fifo_thread; + event_t *wake_fifo_thread; + event_t *fifo_not_full_event; + + int virge_busy; +} virge_t; + +static inline void wake_fifo_thread(virge_t *virge) +{ + thread_set_event(virge->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +static void queue_triangle(virge_t *virge); + +static void s3_virge_recalctimings(svga_t *svga); +static void s3_virge_updatemapping(virge_t *virge); + +static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat); + +static uint8_t s3_virge_mmio_read(uint32_t addr, void *p); +static uint16_t s3_virge_mmio_read_w(uint32_t addr, void *p); +static uint32_t s3_virge_mmio_read_l(uint32_t addr, void *p); +static void s3_virge_mmio_write(uint32_t addr, uint8_t val, void *p); +static void s3_virge_mmio_write_w(uint32_t addr, uint16_t val, void *p); +static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p); + +enum +{ + CMD_SET_AE = 1, + CMD_SET_HC = (1 << 1), + + CMD_SET_FORMAT_MASK = (7 << 2), + CMD_SET_FORMAT_8 = (0 << 2), + CMD_SET_FORMAT_16 = (1 << 2), + CMD_SET_FORMAT_24 = (2 << 2), + + CMD_SET_MS = (1 << 6), + CMD_SET_IDS = (1 << 7), + CMD_SET_MP = (1 << 8), + CMD_SET_TP = (1 << 9), + + CMD_SET_ITA_MASK = (3 << 10), + CMD_SET_ITA_BYTE = (0 << 10), + CMD_SET_ITA_WORD = (1 << 10), + CMD_SET_ITA_DWORD = (2 << 10), + + CMD_SET_ZUP = (1 << 23), + + CMD_SET_ZB_MODE = (3 << 24), + + CMD_SET_XP = (1 << 25), + CMD_SET_YP = (1 << 26), + + CMD_SET_COMMAND_MASK = (15 << 27) +}; + +#define CMD_SET_ABC_SRC (1 << 18) +#define CMD_SET_ABC_ENABLE (1 << 19) +#define CMD_SET_TWE (1 << 26) + +enum +{ + CMD_SET_COMMAND_BITBLT = (0 << 27), + CMD_SET_COMMAND_RECTFILL = (2 << 27), + CMD_SET_COMMAND_LINE = (3 << 27), + CMD_SET_COMMAND_POLY = (5 << 27), + CMD_SET_COMMAND_NOP = (15 << 27) +}; + +static void s3_virge_out(uint16_t addr, uint8_t val, void *p) +{ + virge_t *virge = (virge_t *)p; + svga_t *svga = &virge->svga; + uint8_t old; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + +// pclog("S3 out %04X %02X %04X:%08X %04X %04X %i\n", addr, val, CS, pc, ES, BX, ins); + + switch (addr) + { + case 0x3c5: + if (svga->seqaddr >= 0x10) + { + svga->seqregs[svga->seqaddr & 0x1f]=val; + svga_recalctimings(svga); + return; + } + if (svga->seqaddr == 4) /*Chain-4 - update banking*/ + { + if (val & 8) svga->write_bank = svga->read_bank = virge->bank << 16; + else svga->write_bank = svga->read_bank = virge->bank << 14; + } + break; + + //case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: +// pclog("Write RAMDAC %04X %02X %04X:%04X\n", addr, val, CS, pc); + //sdac_ramdac_out(addr,val); + //return; + + case 0x3d4: + svga->crtcreg = val;// & 0x7f; + return; + case 0x3d5: + //pclog("Write CRTC R%02X %02X %04x(%08x):%08x\n", svga->crtcreg, val, CS, cs, pc); + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + if (svga->crtcreg >= 0x20 && svga->crtcreg != 0x38 && (svga->crtc[0x38] & 0xcc) != 0x48) + return; + if (svga->crtcreg >= 0x80) + return; + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + switch (svga->crtcreg) + { + case 0x31: + virge->ma_ext = (virge->ma_ext & 0x1c) | ((val & 0x30) >> 4); + break; + case 0x32: + if ((svga->crtc[0x67] & 0xc) != 0xc) + svga->vrammask = (val & 0x40) ? 0x3ffff : ((virge->memory_size << 20) - 1); + break; + + case 0x50: + switch (svga->crtc[0x50] & 0xc1) + { + case 0x00: virge->width = (svga->crtc[0x31] & 2) ? 2048 : 1024; break; + case 0x01: virge->width = 1152; break; + case 0x40: virge->width = 640; break; + case 0x80: virge->width = 800; break; + case 0x81: virge->width = 1600; break; + case 0xc0: virge->width = 1280; break; + } + virge->bpp = (svga->crtc[0x50] >> 4) & 3; + break; + case 0x69: + virge->ma_ext = val & 0x1f; + break; + + case 0x35: + virge->bank = (virge->bank & 0x70) | (val & 0xf); +// pclog("CRTC write R35 %02X\n", val); + if (svga->chain4) svga->write_bank = svga->read_bank = virge->bank << 16; + else svga->write_bank = svga->read_bank = virge->bank << 14; + break; + case 0x51: + virge->bank = (virge->bank & 0x4f) | ((val & 0xc) << 2); + if (svga->chain4) svga->write_bank = svga->read_bank = virge->bank << 16; + else svga->write_bank = svga->read_bank = virge->bank << 14; + virge->ma_ext = (virge->ma_ext & ~0xc) | ((val & 3) << 2); + break; + case 0x6a: + virge->bank = val; +// pclog("CRTC write R6a %02X\n", val); + if (svga->chain4) svga->write_bank = svga->read_bank = virge->bank << 16; + else svga->write_bank = svga->read_bank = virge->bank << 14; + break; + + case 0x3a: + if (val & 0x10) svga->gdcreg[5] |= 0x40; /*Horrible cheat*/ + break; + + case 0x45: + svga->hwcursor.ena = val & 1; + break; + case 0x46: case 0x47: case 0x48: case 0x49: + case 0x4c: case 0x4d: case 0x4e: case 0x4f: + svga->hwcursor.x = ((svga->crtc[0x46] << 8) | svga->crtc[0x47]) & 0x7ff; + svga->hwcursor.y = ((svga->crtc[0x48] << 8) | svga->crtc[0x49]) & 0x7ff; + svga->hwcursor.xoff = svga->crtc[0x4e] & 63; + svga->hwcursor.yoff = svga->crtc[0x4f] & 63; + svga->hwcursor.addr = ((((svga->crtc[0x4c] << 8) | svga->crtc[0x4d]) & 0xfff) * 1024) + (svga->hwcursor.yoff * 16); + break; + + case 0x4a: + virge->hwcursor_col[1] = (virge->hwcursor_col[1] & ~(0xff << (virge->hwcursor_col_pos * 8))) | + (val << (virge->hwcursor_col_pos * 8)); + virge->hwcursor_col_pos++; + virge->hwcursor_col_pos &= 3; + break; + case 0x4b: + virge->hwcursor_col[0] = (virge->hwcursor_col[0] & ~(0xff << (virge->hwcursor_col_pos * 8))) | + (val << (virge->hwcursor_col_pos * 8)); + virge->hwcursor_col_pos++; + virge->hwcursor_col_pos &= 3; + break; + + case 0x53: + case 0x58: case 0x59: case 0x5a: + s3_virge_updatemapping(virge); + break; + + case 0x67: + switch (val >> 4) + { + case 3: svga->bpp = 15; break; + case 5: svga->bpp = 16; break; + case 7: svga->bpp = 24; break; + case 13: svga->bpp = 32; break; + default: svga->bpp = 8; break; + } + break; + //case 0x55: case 0x43: +// pclog("Write CRTC R%02X %02X\n", crtcreg, val); + } + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +static uint8_t s3_virge_in(uint16_t addr, void *p) +{ + virge_t *virge = (virge_t *)p; + svga_t *svga = &virge->svga; + uint8_t ret; + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + +// if (addr != 0x3da) pclog("S3 in %04X %04X:%08X ", addr, CS, pc); + switch (addr) + { + case 0x3c1: + if (svga->attraddr > 0x14) + ret = 0xff; + else + ret = svga_in(addr, svga); + break; + //case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: +// pclog("Read RAMDAC %04X %04X:%04X\n", addr, CS, pc); + //return sdac_ramdac_in(addr); + + case 0x3c5: + if (svga->seqaddr >= 8) + ret = svga->seqregs[svga->seqaddr & 0x1f]; + else if (svga->seqaddr <= 4) + ret = svga_in(addr, svga); + else + ret = 0xff; + break; + + case 0x3D4: + ret = svga->crtcreg; + break; + case 0x3D5: + //pclog("Read CRTC R%02X %04X:%04X (%02x)\n", svga->crtcreg, CS, pc, svga->crtc[svga->crtcreg]); + switch (svga->crtcreg) + { + case 0x2d: ret = virge->virge_id_high; break; /*Extended chip ID*/ + case 0x2e: ret = virge->virge_id_low; break; /*New chip ID*/ + case 0x2f: ret = virge->virge_rev; break; + case 0x30: ret = virge->virge_id; break; /*Chip ID*/ + case 0x31: ret = (svga->crtc[0x31] & 0xcf) | ((virge->ma_ext & 3) << 4); break; + case 0x35: ret = (svga->crtc[0x35] & 0xf0) | (virge->bank & 0xf); break; + case 0x36: ret = (svga->crtc[0x36] & 0xfc) | 2; break; /*PCI bus*/ + case 0x45: virge->hwcursor_col_pos = 0; ret = svga->crtc[0x45]; break; + case 0x51: ret = (svga->crtc[0x51] & 0xf0) | ((virge->bank >> 2) & 0xc) | ((virge->ma_ext >> 2) & 3); break; + case 0x69: ret = virge->ma_ext; break; + case 0x6a: ret = virge->bank; break; + default: ret = svga->crtc[svga->crtcreg]; break; + } + break; + + default: + ret = svga_in(addr, svga); + break; + } +// if (addr != 0x3da) pclog("%02X\n", ret); + return ret; +} + +static void s3_virge_recalctimings(svga_t *svga) +{ + virge_t *virge = (virge_t *)svga->p; + + if (svga->crtc[0x5d] & 0x01) svga->htotal += 0x100; + if (svga->crtc[0x5d] & 0x02) svga->hdisp += 0x100; + if (svga->crtc[0x5e] & 0x01) svga->vtotal += 0x400; + if (svga->crtc[0x5e] & 0x02) svga->dispend += 0x400; + if (svga->crtc[0x5e] & 0x04) svga->vblankstart += 0x400; + if (svga->crtc[0x5e] & 0x10) svga->vsyncstart += 0x400; + if (svga->crtc[0x5e] & 0x40) svga->split += 0x400; + svga->interlace = svga->crtc[0x42] & 0x20; + + if ((svga->crtc[0x67] & 0xc) != 0xc) /*VGA mode*/ + { + svga->ma_latch |= (virge->ma_ext << 16); +//pclog("VGA mode\n"); + if (svga->crtc[0x51] & 0x30) svga->rowoffset += (svga->crtc[0x51] & 0x30) << 4; + else if (svga->crtc[0x43] & 0x04) svga->rowoffset += 0x100; + if (!svga->rowoffset) svga->rowoffset = 256; + + if ((svga->gdcreg[5] & 0x40) && (svga->crtc[0x3a] & 0x10)) + { + switch (svga->bpp) + { + case 8: + svga->render = svga_render_8bpp_highres; + break; + case 15: + svga->render = svga_render_15bpp_highres; + break; + case 16: + svga->render = svga_render_16bpp_highres; + break; + case 24: + svga->render = svga_render_24bpp_highres; + break; + case 32: + svga->render = svga_render_32bpp_highres; + break; + } + } + +// pclog("svga->rowoffset = %i bpp=%i\n", svga->rowoffset, svga->bpp); + if (svga->bpp == 15 || svga->bpp == 16) + { + svga->htotal >>= 1; + svga->hdisp >>= 1; + } + if (svga->bpp == 24) + { + svga->rowoffset = (svga->rowoffset * 3) / 4; /*Hack*/ + } + svga->vrammask = (svga->crtc[0x32] & 0x40) ? 0x3ffff : ((virge->memory_size << 20) - 1); +//pclog("VGA mode x_disp=%i dispend=%i vtotal=%i\n", svga->hdisp, svga->dispend, svga->vtotal); + } + else /*Streams mode*/ + { + if (virge->streams.buffer_ctrl & 1) + svga->ma_latch = virge->streams.pri_fb1 >> 2; + else + svga->ma_latch = virge->streams.pri_fb0 >> 2; + + svga->hdisp = virge->streams.pri_w + 1; + if (virge->streams.pri_h < svga->dispend) + svga->dispend = virge->streams.pri_h; + + svga->overlay.x = virge->streams.sec_x - virge->streams.pri_x; + svga->overlay.y = virge->streams.sec_y - virge->streams.pri_y; + svga->overlay.ysize = virge->streams.sec_h; + + if (virge->streams.buffer_ctrl & 2) + svga->overlay.addr = virge->streams.sec_fb1; + else + svga->overlay.addr = virge->streams.sec_fb0; + + svga->overlay.ena = (svga->overlay.x >= 0); + svga->overlay.v_acc = virge->streams.dda_vert_accumulator; +//pclog("Streams mode x_disp=%i dispend=%i vtotal=%i x=%i y=%i ysize=%i\n", svga->hdisp, svga->dispend, svga->vtotal, svga->overlay.x, svga->overlay.y, svga->overlay.ysize); + svga->rowoffset = virge->streams.pri_stride >> 3; + + switch ((virge->streams.pri_ctrl >> 24) & 0x7) + { + case 0: /*RGB-8 (CLUT)*/ + svga->render = svga_render_8bpp_highres; + break; + case 3: /*KRGB-16 (1.5.5.5)*/ + svga->htotal >>= 1; + svga->render = svga_render_15bpp_highres; + break; + case 5: /*RGB-16 (5.6.5)*/ + svga->htotal >>= 1; + svga->render = svga_render_16bpp_highres; + break; + case 6: /*RGB-24 (8.8.8)*/ + svga->render = svga_render_24bpp_highres; + break; + case 7: /*XRGB-32 (X.8.8.8)*/ + svga->render = svga_render_32bpp_highres; + break; + } + svga->vrammask = (virge->memory_size << 20) - 1; + } + + if (((svga->miscout >> 2) & 3) == 3) + { + int n = svga->seqregs[0x12] & 0x1f; + int r = (svga->seqregs[0x12] >> 5) & (virge->is_375 ? 7 : 3); + int m = svga->seqregs[0x13] & 0x7f; + double freq = (((double)m + 2) / (((double)n + 2) * (double)(1 << r))) * 14318184.0; + + svga->clock = cpuclock / freq; + } +} + +static void s3_virge_updatemapping(virge_t *virge) +{ + svga_t *svga = &virge->svga; + + if (!(virge->pci_regs[PCI_REG_COMMAND] & PCI_COMMAND_MEM)) + { +// pclog("Update mapping - PCI disabled\n"); + mem_mapping_disable(&svga->mapping); + mem_mapping_disable(&virge->linear_mapping); + mem_mapping_disable(&virge->mmio_mapping); + mem_mapping_disable(&virge->new_mmio_mapping); + return; + } + + pclog("Update mapping - bank %02X ", svga->gdcreg[6] & 0xc); + switch (svga->gdcreg[6] & 0xc) /*Banked framebuffer*/ + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + + virge->linear_base = (svga->crtc[0x5a] << 16) | (svga->crtc[0x59] << 24); + + pclog("Linear framebuffer %02X ", svga->crtc[0x58] & 0x10); + if (svga->crtc[0x58] & 0x10) /*Linear framebuffer*/ + { + switch (svga->crtc[0x58] & 3) + { + case 0: /*64k*/ + virge->linear_size = 0x10000; + break; + case 1: /*1mb*/ + virge->linear_size = 0x100000; + break; + case 2: /*2mb*/ + virge->linear_size = 0x200000; + break; + case 3: /*8mb*/ + virge->linear_size = 0x400000; + break; + } + virge->linear_base &= ~(virge->linear_size - 1); +// pclog("%08X %08X %02X %02X %02X\n", linear_base, linear_size, crtc[0x58], crtc[0x59], crtc[0x5a]); + pclog("Linear framebuffer at %08X size %08X\n", virge->linear_base, virge->linear_size); + if (virge->linear_base == 0xa0000) + { + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + mem_mapping_disable(&virge->linear_mapping); + } + else + mem_mapping_set_addr(&virge->linear_mapping, virge->linear_base, virge->linear_size); + svga->fb_only = 1; + } + else + { + mem_mapping_disable(&virge->linear_mapping); + svga->fb_only = 0; + } + + pclog("Memory mapped IO %02X\n", svga->crtc[0x53] & 0x18); + if (svga->crtc[0x53] & 0x10) /*Old MMIO*/ + { + if (svga->crtc[0x53] & 0x20) + mem_mapping_set_addr(&virge->mmio_mapping, 0xb8000, 0x8000); + else + mem_mapping_set_addr(&virge->mmio_mapping, 0xa0000, 0x10000); + } + else + mem_mapping_disable(&virge->mmio_mapping); + + if (svga->crtc[0x53] & 0x08) /*New MMIO*/ + mem_mapping_set_addr(&virge->new_mmio_mapping, virge->linear_base + 0x1000000, 0x10000); + else + mem_mapping_disable(&virge->new_mmio_mapping); + +} + +static void s3_virge_wait_fifo_idle(virge_t *virge) +{ + while (!FIFO_EMPTY) + { + wake_fifo_thread(virge); + thread_wait_event(virge->fifo_not_full_event, 1); + } +} + +static uint8_t s3_virge_mmio_read(uint32_t addr, void *p) +{ + virge_t *virge = (virge_t *)p; + uint8_t ret; + + reg_reads++; +// pclog("New MMIO readb %08X\n", addr); + switch (addr & 0xffff) + { + case 0x8505: + if (virge->s3d_busy || virge->virge_busy || !FIFO_EMPTY) + ret = 0x10; + else + ret = 0x10 | (1 << 5); + if (!virge->virge_busy) + wake_fifo_thread(virge); + return ret; + + case 0x83b0: case 0x83b1: case 0x83b2: case 0x83b3: + case 0x83b4: case 0x83b5: case 0x83b6: case 0x83b7: + case 0x83b8: case 0x83b9: case 0x83ba: case 0x83bb: + case 0x83bc: case 0x83bd: case 0x83be: case 0x83bf: + case 0x83c0: case 0x83c1: case 0x83c2: case 0x83c3: + case 0x83c4: case 0x83c5: case 0x83c6: case 0x83c7: + case 0x83c8: case 0x83c9: case 0x83ca: case 0x83cb: + case 0x83cc: case 0x83cd: case 0x83ce: case 0x83cf: + case 0x83d0: case 0x83d1: case 0x83d2: case 0x83d3: + case 0x83d4: case 0x83d5: case 0x83d6: case 0x83d7: + case 0x83d8: case 0x83d9: case 0x83da: case 0x83db: + case 0x83dc: case 0x83dd: case 0x83de: case 0x83df: + return s3_virge_in(addr & 0x3ff, p); + } + return 0xff; +} +static uint16_t s3_virge_mmio_read_w(uint32_t addr, void *p) +{ + reg_reads++; +// pclog("New MMIO readw %08X\n", addr); + switch (addr & 0xfffe) + { + default: + return s3_virge_mmio_read(addr, p) | (s3_virge_mmio_read(addr + 1, p) << 8); + } + return 0xffff; +} +static uint32_t s3_virge_mmio_read_l(uint32_t addr, void *p) +{ + virge_t *virge = (virge_t *)p; + uint32_t ret = 0xffffffff; + reg_reads++; +// pclog("New MMIO readl %08X %04X(%08X):%08X ", addr, CS, cs, pc); + switch (addr & 0xfffc) + { + case 0x8180: + ret = virge->streams.pri_ctrl; + break; + case 0x8184: + ret = virge->streams.chroma_ctrl; + break; + case 0x8190: + ret = virge->streams.sec_ctrl; + break; + case 0x8194: + ret = virge->streams.chroma_upper_bound; + break; + case 0x8198: + ret = virge->streams.sec_filter; + break; + case 0x81a0: + ret = virge->streams.blend_ctrl; + break; + case 0x81c0: + ret = virge->streams.pri_fb0; + break; + case 0x81c4: + ret = virge->streams.pri_fb1; + break; + case 0x81c8: + ret = virge->streams.pri_stride; + break; + case 0x81cc: + ret = virge->streams.buffer_ctrl; + break; + case 0x81d0: + ret = virge->streams.sec_fb0; + break; + case 0x81d4: + ret = virge->streams.sec_fb1; + break; + case 0x81d8: + ret = virge->streams.sec_stride; + break; + case 0x81dc: + ret = virge->streams.overlay_ctrl; + break; + case 0x81e0: + ret = virge->streams.k1_vert_scale; + break; + case 0x81e4: + ret = virge->streams.k2_vert_scale; + break; + case 0x81e8: + ret = virge->streams.dda_vert_accumulator; + break; + case 0x81ec: + ret = virge->streams.fifo_ctrl; + break; + case 0x81f0: + ret = virge->streams.pri_start; + break; + case 0x81f4: + ret = virge->streams.pri_size; + break; + case 0x81f8: + ret = virge->streams.sec_start; + break; + case 0x81fc: + ret = virge->streams.sec_size; + break; + + case 0x8504: + if (virge->s3d_busy || virge->virge_busy || !FIFO_EMPTY) + ret = (0x10 << 8); + else + ret = (0x10 << 8) | (1 << 13); + if (!virge->virge_busy) + wake_fifo_thread(virge); +// pclog("Read status %04x %i\n", ret, virge->s3d_busy); + break; + case 0xa4d4: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.src_base; + break; + case 0xa4d8: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.dest_base; + break; + case 0xa4dc: + s3_virge_wait_fifo_idle(virge); + ret = (virge->s3d.clip_l << 16) | virge->s3d.clip_r; + break; + case 0xa4e0: + s3_virge_wait_fifo_idle(virge); + ret = (virge->s3d.clip_t << 16) | virge->s3d.clip_b; + break; + case 0xa4e4: + s3_virge_wait_fifo_idle(virge); + ret = (virge->s3d.dest_str << 16) | virge->s3d.src_str; + break; + case 0xa4e8: case 0xace8: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.mono_pat_0; + break; + case 0xa4ec: case 0xacec: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.mono_pat_1; + break; + case 0xa4f0: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.pat_bg_clr; + break; + case 0xa4f4: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.pat_fg_clr; + break; + case 0xa4f8: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.src_bg_clr; + break; + case 0xa4fc: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.src_fg_clr; + break; + case 0xa500: + s3_virge_wait_fifo_idle(virge); + ret = virge->s3d.cmd_set; + break; + case 0xa504: + s3_virge_wait_fifo_idle(virge); + ret = (virge->s3d.r_width << 16) | virge->s3d.r_height; + break; + case 0xa508: + s3_virge_wait_fifo_idle(virge); + ret = (virge->s3d.rsrc_x << 16) | virge->s3d.rsrc_y; + break; + case 0xa50c: + s3_virge_wait_fifo_idle(virge); + ret = (virge->s3d.rdest_x << 16) | virge->s3d.rdest_y; + break; + + default: + ret = s3_virge_mmio_read_w(addr, p) | (s3_virge_mmio_read_w(addr + 2, p) << 16); + } +// /*if ((addr & 0xfffc) != 0x8504) */pclog("%02x\n", ret); + return ret; +} + +static void fifo_thread(void *param) +{ + virge_t *virge = (virge_t *)param; + + while (1) + { + thread_set_event(virge->fifo_not_full_event); + thread_wait_event(virge->wake_fifo_thread, -1); + thread_reset_event(virge->wake_fifo_thread); + virge->virge_busy = 1; + while (!FIFO_EMPTY) + { + uint64_t start_time = timer_read(); + uint64_t end_time; + fifo_entry_t *fifo = &virge->fifo[virge->fifo_read_idx & FIFO_MASK]; + uint32_t val = fifo->val; + + switch (fifo->addr_type & FIFO_TYPE) + { + case FIFO_WRITE_BYTE: + if (((fifo->addr_type & FIFO_ADDR) & 0xfffc) < 0x8000) + s3_virge_bitblt(virge, 8, val); + break; + case FIFO_WRITE_WORD: + if (((fifo->addr_type & FIFO_ADDR) & 0xfffc) < 0x8000) + { + if (virge->s3d.cmd_set & CMD_SET_MS) + s3_virge_bitblt(virge, 16, ((val >> 8) | (val << 8)) << 16); + else + s3_virge_bitblt(virge, 16, val); + } + break; + case FIFO_WRITE_DWORD: + if (((fifo->addr_type & FIFO_ADDR) & 0xfffc) < 0x8000) + { + if (virge->s3d.cmd_set & CMD_SET_MS) + s3_virge_bitblt(virge, 32, ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24)); + else + s3_virge_bitblt(virge, 32, val); + } + else + { + switch ((fifo->addr_type & FIFO_ADDR) & 0xfffc) + { + case 0xa000: case 0xa004: case 0xa008: case 0xa00c: + case 0xa010: case 0xa014: case 0xa018: case 0xa01c: + case 0xa020: case 0xa024: case 0xa028: case 0xa02c: + case 0xa030: case 0xa034: case 0xa038: case 0xa03c: + case 0xa040: case 0xa044: case 0xa048: case 0xa04c: + case 0xa050: case 0xa054: case 0xa058: case 0xa05c: + case 0xa060: case 0xa064: case 0xa068: case 0xa06c: + case 0xa070: case 0xa074: case 0xa078: case 0xa07c: + case 0xa080: case 0xa084: case 0xa088: case 0xa08c: + case 0xa090: case 0xa094: case 0xa098: case 0xa09c: + case 0xa0a0: case 0xa0a4: case 0xa0a8: case 0xa0ac: + case 0xa0b0: case 0xa0b4: case 0xa0b8: case 0xa0bc: + case 0xa0c0: case 0xa0c4: case 0xa0c8: case 0xa0cc: + case 0xa0d0: case 0xa0d4: case 0xa0d8: case 0xa0dc: + case 0xa0e0: case 0xa0e4: case 0xa0e8: case 0xa0ec: + case 0xa0f0: case 0xa0f4: case 0xa0f8: case 0xa0fc: + case 0xa100: case 0xa104: case 0xa108: case 0xa10c: + case 0xa110: case 0xa114: case 0xa118: case 0xa11c: + case 0xa120: case 0xa124: case 0xa128: case 0xa12c: + case 0xa130: case 0xa134: case 0xa138: case 0xa13c: + case 0xa140: case 0xa144: case 0xa148: case 0xa14c: + case 0xa150: case 0xa154: case 0xa158: case 0xa15c: + case 0xa160: case 0xa164: case 0xa168: case 0xa16c: + case 0xa170: case 0xa174: case 0xa178: case 0xa17c: + case 0xa180: case 0xa184: case 0xa188: case 0xa18c: + case 0xa190: case 0xa194: case 0xa198: case 0xa19c: + case 0xa1a0: case 0xa1a4: case 0xa1a8: case 0xa1ac: + case 0xa1b0: case 0xa1b4: case 0xa1b8: case 0xa1bc: + case 0xa1c0: case 0xa1c4: case 0xa1c8: case 0xa1cc: + case 0xa1d0: case 0xa1d4: case 0xa1d8: case 0xa1dc: + case 0xa1e0: case 0xa1e4: case 0xa1e8: case 0xa1ec: + case 0xa1f0: case 0xa1f4: case 0xa1f8: case 0xa1fc: + { + int x = (fifo->addr_type & FIFO_ADDR) & 4; + int y = ((fifo->addr_type & FIFO_ADDR) >> 3) & 7; + virge->s3d.pattern_8[y*8 + x] = val & 0xff; + virge->s3d.pattern_8[y*8 + x + 1] = val >> 8; + virge->s3d.pattern_8[y*8 + x + 2] = val >> 16; + virge->s3d.pattern_8[y*8 + x + 3] = val >> 24; + + x = ((fifo->addr_type & FIFO_ADDR) >> 1) & 6; + y = ((fifo->addr_type & FIFO_ADDR) >> 4) & 7; + virge->s3d.pattern_16[y*8 + x] = val & 0xffff; + virge->s3d.pattern_16[y*8 + x + 1] = val >> 16; + + x = ((fifo->addr_type & FIFO_ADDR) >> 2) & 7; + y = ((fifo->addr_type & FIFO_ADDR) >> 5) & 7; + virge->s3d.pattern_32[y*8 + x] = val & 0xffffff; + } + break; + + case 0xa4d4: case 0xa8d4: + virge->s3d.src_base = val & 0x3ffff8; + break; + case 0xa4d8: case 0xa8d8: + virge->s3d.dest_base = val & 0x3ffff8; + break; + case 0xa4dc: case 0xa8dc: + virge->s3d.clip_l = (val >> 16) & 0x7ff; + virge->s3d.clip_r = val & 0x7ff; + break; + case 0xa4e0: case 0xa8e0: + virge->s3d.clip_t = (val >> 16) & 0x7ff; + virge->s3d.clip_b = val & 0x7ff; + break; + case 0xa4e4: case 0xa8e4: + virge->s3d.dest_str = (val >> 16) & 0xff8; + virge->s3d.src_str = val & 0xff8; + break; + case 0xa4e8: case 0xace8: + virge->s3d.mono_pat_0 = val; + break; + case 0xa4ec: case 0xacec: + virge->s3d.mono_pat_1 = val; + break; + case 0xa4f0: case 0xacf0: + virge->s3d.pat_bg_clr = val; + break; + case 0xa4f4: case 0xa8f4: case 0xacf4: + virge->s3d.pat_fg_clr = val; + break; + case 0xa4f8: + virge->s3d.src_bg_clr = val; + break; + case 0xa4fc: + virge->s3d.src_fg_clr = val; + break; + case 0xa500: case 0xa900: + virge->s3d.cmd_set = val; + if (!(val & CMD_SET_AE)) + s3_virge_bitblt(virge, -1, 0); + break; + case 0xa504: + virge->s3d.r_width = (val >> 16) & 0x7ff; + virge->s3d.r_height = val & 0x7ff; + break; + case 0xa508: + virge->s3d.rsrc_x = (val >> 16) & 0x7ff; + virge->s3d.rsrc_y = val & 0x7ff; + break; + case 0xa50c: + virge->s3d.rdest_x = (val >> 16) & 0x7ff; + virge->s3d.rdest_y = val & 0x7ff; + if (virge->s3d.cmd_set & CMD_SET_AE) + s3_virge_bitblt(virge, -1, 0); + break; + case 0xa96c: + virge->s3d.lxend0 = (val >> 16) & 0x7ff; + virge->s3d.lxend1 = val & 0x7ff; + break; + case 0xa970: + virge->s3d.ldx = (int32_t)val; + break; + case 0xa974: + virge->s3d.lxstart = val; + break; + case 0xa978: + virge->s3d.lystart = val & 0x7ff; + break; + case 0xa97c: + virge->s3d.lycnt = val & 0x7ff; + virge->s3d.line_dir = val >> 31; + if (virge->s3d.cmd_set & CMD_SET_AE) + s3_virge_bitblt(virge, -1, 0); + break; + + case 0xad00: + virge->s3d.cmd_set = val; + if (!(val & CMD_SET_AE)) + s3_virge_bitblt(virge, -1, 0); + break; + case 0xad68: + virge->s3d.prdx = val; + break; + case 0xad6c: + virge->s3d.prxstart = val; + break; + case 0xad70: + virge->s3d.pldx = val; + break; + case 0xad74: + virge->s3d.plxstart = val; + break; + case 0xad78: + virge->s3d.pystart = val & 0x7ff; + break; + case 0xad7c: + virge->s3d.pycnt = val & 0x300007ff; + if (virge->s3d.cmd_set & CMD_SET_AE) + s3_virge_bitblt(virge, -1, 0); + break; + + case 0xb4d4: + virge->s3d_tri.z_base = val & 0x3ffff8; + break; + case 0xb4d8: + virge->s3d_tri.dest_base = val & 0x3ffff8; + break; + case 0xb4dc: + virge->s3d_tri.clip_l = (val >> 16) & 0x7ff; + virge->s3d_tri.clip_r = val & 0x7ff; + break; + case 0xb4e0: + virge->s3d_tri.clip_t = (val >> 16) & 0x7ff; + virge->s3d_tri.clip_b = val & 0x7ff; + break; + case 0xb4e4: + virge->s3d_tri.dest_str = (val >> 16) & 0xff8; + virge->s3d.src_str = val & 0xff8; + break; + case 0xb4e8: + virge->s3d_tri.z_str = val & 0xff8; + break; + case 0xb4ec: + virge->s3d_tri.tex_base = val & 0x3ffff8; + break; + case 0xb4f0: + virge->s3d_tri.tex_bdr_clr = val & 0xffffff; + break; + case 0xb500: + virge->s3d_tri.cmd_set = val; + if (!(val & CMD_SET_AE)) + queue_triangle(virge); + break; + case 0xb504: + virge->s3d_tri.tbv = val & 0xfffff; + break; + case 0xb508: + virge->s3d_tri.tbu = val & 0xfffff; + break; + case 0xb50c: + virge->s3d_tri.TdWdX = val; + break; + case 0xb510: + virge->s3d_tri.TdWdY = val; + break; + case 0xb514: + virge->s3d_tri.tws = val; + break; + case 0xb518: + virge->s3d_tri.TdDdX = val; + break; + case 0xb51c: + virge->s3d_tri.TdVdX = val; + break; + case 0xb520: + virge->s3d_tri.TdUdX = val; + break; + case 0xb524: + virge->s3d_tri.TdDdY = val; + break; + case 0xb528: + virge->s3d_tri.TdVdY = val; + break; + case 0xb52c: + virge->s3d_tri.TdUdY = val; + break; + case 0xb530: + virge->s3d_tri.tds = val; + break; + case 0xb534: + virge->s3d_tri.tvs = val; + break; + case 0xb538: + virge->s3d_tri.tus = val; + break; + case 0xb53c: + virge->s3d_tri.TdGdX = val >> 16; + virge->s3d_tri.TdBdX = val & 0xffff; + break; + case 0xb540: + virge->s3d_tri.TdAdX = val >> 16; + virge->s3d_tri.TdRdX = val & 0xffff; + break; + case 0xb544: + virge->s3d_tri.TdGdY = val >> 16; + virge->s3d_tri.TdBdY = val & 0xffff; + break; + case 0xb548: + virge->s3d_tri.TdAdY = val >> 16; + virge->s3d_tri.TdRdY = val & 0xffff; + break; + case 0xb54c: + virge->s3d_tri.tgs = (val >> 16) & 0xffff; + virge->s3d_tri.tbs = val & 0xffff; + break; + case 0xb550: + virge->s3d_tri.tas = (val >> 16) & 0xffff; + virge->s3d_tri.trs = val & 0xffff; + break; + + case 0xb554: + virge->s3d_tri.TdZdX = val; + break; + case 0xb558: + virge->s3d_tri.TdZdY = val; + break; + case 0xb55c: + virge->s3d_tri.tzs = val; + break; + case 0xb560: + virge->s3d_tri.TdXdY12 = val; + break; + case 0xb564: + virge->s3d_tri.txend12 = val; + break; + case 0xb568: + virge->s3d_tri.TdXdY01 = val; + break; + case 0xb56c: + virge->s3d_tri.txend01 = val; + break; + case 0xb570: + virge->s3d_tri.TdXdY02 = val; + break; + case 0xb574: + virge->s3d_tri.txs = val; + break; + case 0xb578: + virge->s3d_tri.tys = val; + break; + case 0xb57c: + virge->s3d_tri.ty01 = (val >> 16) & 0x7ff; + virge->s3d_tri.ty12 = val & 0x7ff; + virge->s3d_tri.tlr = val >> 31; + if (virge->s3d_tri.cmd_set & CMD_SET_AE) + queue_triangle(virge); + break; + } + } + break; + } + + virge->fifo_read_idx++; + fifo->addr_type = FIFO_INVALID; + + if (FIFO_ENTRIES > 0xe000) + thread_set_event(virge->fifo_not_full_event); + + end_time = timer_read(); + virge_time += end_time - start_time; + } + virge->virge_busy = 0; + } +} + +static void s3_virge_queue(virge_t *virge, uint32_t addr, uint32_t val, uint32_t type) +{ + fifo_entry_t *fifo = &virge->fifo[virge->fifo_write_idx & FIFO_MASK]; + int c; + + if (FIFO_FULL) + { + thread_reset_event(virge->fifo_not_full_event); + if (FIFO_FULL) + { + thread_wait_event(virge->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ + } + } + + fifo->val = val; + fifo->addr_type = (addr & FIFO_ADDR) | type; + + virge->fifo_write_idx++; + + /* if (FIFO_ENTRIES > 0xe000) + wake_fifo_thread(virge); */ + if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8) + wake_fifo_thread(virge); +} + +static void s3_virge_mmio_write(uint32_t addr, uint8_t val, void *p) +{ + virge_t *virge = (virge_t *)p; + svga_t *svga = &virge->svga; + +// pclog("New MMIO writeb %08X %02X %04x(%08x):%08x\n", addr, val, CS, cs, pc); + reg_writes++; + if ((addr & 0xfffc) < 0x8000) + { + s3_virge_queue(virge, addr, val, FIFO_WRITE_BYTE); + } + else switch (addr & 0xffff) + { + case 0x83b0: case 0x83b1: case 0x83b2: case 0x83b3: + case 0x83b4: case 0x83b5: case 0x83b6: case 0x83b7: + case 0x83b8: case 0x83b9: case 0x83ba: case 0x83bb: + case 0x83bc: case 0x83bd: case 0x83be: case 0x83bf: + case 0x83c0: case 0x83c1: case 0x83c2: case 0x83c3: + case 0x83c4: case 0x83c5: case 0x83c6: case 0x83c7: + case 0x83c8: case 0x83c9: case 0x83ca: case 0x83cb: + case 0x83cc: case 0x83cd: case 0x83ce: case 0x83cf: + case 0x83d0: case 0x83d1: case 0x83d2: case 0x83d3: + case 0x83d4: case 0x83d5: case 0x83d6: case 0x83d7: + case 0x83d8: case 0x83d9: case 0x83da: case 0x83db: + case 0x83dc: case 0x83dd: case 0x83de: case 0x83df: + s3_virge_out(addr & 0x3ff, val, p); + break; + } + + +} +static void s3_virge_mmio_write_w(uint32_t addr, uint16_t val, void *p) +{ + virge_t *virge = (virge_t *)p; + reg_writes++; +// pclog("New MMIO writew %08X %04X %04x(%08x):%08x\n", addr, val, CS, cs, pc); + if ((addr & 0xfffc) < 0x8000) + { + s3_virge_queue(virge, addr, val, FIFO_WRITE_WORD); + } + else switch (addr & 0xfffe) + { + case 0x83d4: + s3_virge_mmio_write(addr, val, p); + s3_virge_mmio_write(addr + 1, val >> 8, p); + break; + } +} +static void s3_virge_mmio_write_l(uint32_t addr, uint32_t val, void *p) +{ + virge_t *virge = (virge_t *)p; + svga_t *svga = &virge->svga; + reg_writes++; +// if ((addr & 0xfffc) >= 0xb400 && (addr & 0xfffc) < 0xb800) +// pclog("New MMIO writel %08X %08X %04x(%08x):%08x\n", addr, val, CS, cs, pc); + + if ((addr & 0xfffc) < 0x8000) + { + s3_virge_queue(virge, addr, val, FIFO_WRITE_DWORD); + } + else if ((addr & 0xe000) == 0xa000) + { + s3_virge_queue(virge, addr, val, FIFO_WRITE_DWORD); + } + else switch (addr & 0xfffc) + { + case 0x8180: + virge->streams.pri_ctrl = val; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x8184: + virge->streams.chroma_ctrl = val; + break; + case 0x8190: + virge->streams.sec_ctrl = val; + virge->streams.dda_horiz_accumulator = val & 0xfff; + if (val & (1 << 11)) + virge->streams.dda_horiz_accumulator |= 0xfffff800; + virge->streams.sdif = (val >> 24) & 7; + break; + case 0x8194: + virge->streams.chroma_upper_bound = val; + break; + case 0x8198: + virge->streams.sec_filter = val; + virge->streams.k1_horiz_scale = val & 0x7ff; + if (val & (1 << 10)) + virge->streams.k1_horiz_scale |= 0xfffff800; + virge->streams.k2_horiz_scale = (val >> 16) & 0x7ff; + if ((val >> 16) & (1 << 10)) + virge->streams.k2_horiz_scale |= 0xfffff800; + break; + case 0x81a0: + virge->streams.blend_ctrl = val; + break; + case 0x81c0: +// pclog("Write pri_fb0 %08x\n", val); + virge->streams.pri_fb0 = val & 0x3fffff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81c4: +// pclog("Write pri_fb1 %08x\n", val); + virge->streams.pri_fb1 = val & 0x3fffff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81c8: + virge->streams.pri_stride = val & 0xfff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81cc: +// pclog("Write buffer_ctrl %08x\n", val); + virge->streams.buffer_ctrl = val; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81d0: + virge->streams.sec_fb0 = val; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81d4: + virge->streams.sec_fb1 = val; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81d8: + virge->streams.sec_stride = val; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81dc: + virge->streams.overlay_ctrl = val; + break; + case 0x81e0: + virge->streams.k1_vert_scale = val & 0x7ff; + if (val & (1 << 10)) + virge->streams.k1_vert_scale |= 0xfffff800; + break; + case 0x81e4: + virge->streams.k2_vert_scale = val & 0x7ff; + if (val & (1 << 10)) + virge->streams.k2_vert_scale |= 0xfffff800; + break; + case 0x81e8: + virge->streams.dda_vert_accumulator = val & 0xfff; + if (val & (1 << 11)) + virge->streams.dda_vert_accumulator |= 0xfffff800; + break; + case 0x81ec: + virge->streams.fifo_ctrl = val; + break; + case 0x81f0: + virge->streams.pri_start = val; + virge->streams.pri_x = (val >> 16) & 0x7ff; + virge->streams.pri_y = val & 0x7ff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81f4: + virge->streams.pri_size = val; + virge->streams.pri_w = (val >> 16) & 0x7ff; + virge->streams.pri_h = val & 0x7ff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81f8: + virge->streams.sec_start = val; + virge->streams.sec_x = (val >> 16) & 0x7ff; + virge->streams.sec_y = val & 0x7ff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + case 0x81fc: + virge->streams.sec_size = val; + virge->streams.sec_w = (val >> 16) & 0x7ff; + virge->streams.sec_h = val & 0x7ff; + svga_recalctimings(svga); + svga->fullchange = changeframecount; + break; + + case 0xa000: case 0xa004: case 0xa008: case 0xa00c: + case 0xa010: case 0xa014: case 0xa018: case 0xa01c: + case 0xa020: case 0xa024: case 0xa028: case 0xa02c: + case 0xa030: case 0xa034: case 0xa038: case 0xa03c: + case 0xa040: case 0xa044: case 0xa048: case 0xa04c: + case 0xa050: case 0xa054: case 0xa058: case 0xa05c: + case 0xa060: case 0xa064: case 0xa068: case 0xa06c: + case 0xa070: case 0xa074: case 0xa078: case 0xa07c: + case 0xa080: case 0xa084: case 0xa088: case 0xa08c: + case 0xa090: case 0xa094: case 0xa098: case 0xa09c: + case 0xa0a0: case 0xa0a4: case 0xa0a8: case 0xa0ac: + case 0xa0b0: case 0xa0b4: case 0xa0b8: case 0xa0bc: + case 0xa0c0: case 0xa0c4: case 0xa0c8: case 0xa0cc: + case 0xa0d0: case 0xa0d4: case 0xa0d8: case 0xa0dc: + case 0xa0e0: case 0xa0e4: case 0xa0e8: case 0xa0ec: + case 0xa0f0: case 0xa0f4: case 0xa0f8: case 0xa0fc: + case 0xa100: case 0xa104: case 0xa108: case 0xa10c: + case 0xa110: case 0xa114: case 0xa118: case 0xa11c: + case 0xa120: case 0xa124: case 0xa128: case 0xa12c: + case 0xa130: case 0xa134: case 0xa138: case 0xa13c: + case 0xa140: case 0xa144: case 0xa148: case 0xa14c: + case 0xa150: case 0xa154: case 0xa158: case 0xa15c: + case 0xa160: case 0xa164: case 0xa168: case 0xa16c: + case 0xa170: case 0xa174: case 0xa178: case 0xa17c: + case 0xa180: case 0xa184: case 0xa188: case 0xa18c: + case 0xa190: case 0xa194: case 0xa198: case 0xa19c: + case 0xa1a0: case 0xa1a4: case 0xa1a8: case 0xa1ac: + case 0xa1b0: case 0xa1b4: case 0xa1b8: case 0xa1bc: + case 0xa1c0: case 0xa1c4: case 0xa1c8: case 0xa1cc: + case 0xa1d0: case 0xa1d4: case 0xa1d8: case 0xa1dc: + case 0xa1e0: case 0xa1e4: case 0xa1e8: case 0xa1ec: + case 0xa1f0: case 0xa1f4: case 0xa1f8: case 0xa1fc: + { + int x = addr & 4; + int y = (addr >> 3) & 7; + virge->s3d.pattern_8[y*8 + x] = val & 0xff; + virge->s3d.pattern_8[y*8 + x + 1] = val >> 8; + virge->s3d.pattern_8[y*8 + x + 2] = val >> 16; + virge->s3d.pattern_8[y*8 + x + 3] = val >> 24; + + x = (addr >> 1) & 6; + y = (addr >> 4) & 7; + virge->s3d.pattern_16[y*8 + x] = val & 0xffff; + virge->s3d.pattern_16[y*8 + x + 1] = val >> 16; + + x = (addr >> 2) & 7; + y = (addr >> 5) & 7; + virge->s3d.pattern_32[y*8 + x] = val & 0xffffff; + } + break; + + case 0xa4d4: case 0xa8d4: + virge->s3d.src_base = val & 0x3ffff8; + break; + case 0xa4d8: case 0xa8d8: + virge->s3d.dest_base = val & 0x3ffff8; + break; + case 0xa4dc: case 0xa8dc: + virge->s3d.clip_l = (val >> 16) & 0x7ff; + virge->s3d.clip_r = val & 0x7ff; + break; + case 0xa4e0: case 0xa8e0: + virge->s3d.clip_t = (val >> 16) & 0x7ff; + virge->s3d.clip_b = val & 0x7ff; + break; + case 0xa4e4: case 0xa8e4: + virge->s3d.dest_str = (val >> 16) & 0xff8; + virge->s3d.src_str = val & 0xff8; + break; + case 0xa4e8: case 0xace8: + virge->s3d.mono_pat_0 = val; + break; + case 0xa4ec: case 0xacec: + virge->s3d.mono_pat_1 = val; + break; + case 0xa4f0: case 0xacf0: + virge->s3d.pat_bg_clr = val; + break; + case 0xa4f4: case 0xa8f4: case 0xacf4: + virge->s3d.pat_fg_clr = val; + break; + case 0xa4f8: + virge->s3d.src_bg_clr = val; + break; + case 0xa4fc: + virge->s3d.src_fg_clr = val; + break; + case 0xa500: case 0xa900: + virge->s3d.cmd_set = val; + if (!(val & CMD_SET_AE)) + s3_virge_bitblt(virge, -1, 0); + break; + case 0xa504: + virge->s3d.r_width = (val >> 16) & 0x7ff; + virge->s3d.r_height = val & 0x7ff; + break; + case 0xa508: + virge->s3d.rsrc_x = (val >> 16) & 0x7ff; + virge->s3d.rsrc_y = val & 0x7ff; + break; + case 0xa50c: + virge->s3d.rdest_x = (val >> 16) & 0x7ff; + virge->s3d.rdest_y = val & 0x7ff; + if (virge->s3d.cmd_set & CMD_SET_AE) + s3_virge_bitblt(virge, -1, 0); + break; + case 0xa96c: + virge->s3d.lxend0 = (val >> 16) & 0x7ff; + virge->s3d.lxend1 = val & 0x7ff; + break; + case 0xa970: + virge->s3d.ldx = (int32_t)val; + break; + case 0xa974: + virge->s3d.lxstart = val; + break; + case 0xa978: + virge->s3d.lystart = val & 0x7ff; + break; + case 0xa97c: + virge->s3d.lycnt = val & 0x7ff; + virge->s3d.line_dir = val >> 31; + if (virge->s3d.cmd_set & CMD_SET_AE) + s3_virge_bitblt(virge, -1, 0); + break; + + case 0xad00: + virge->s3d.cmd_set = val; + if (!(val & CMD_SET_AE)) + s3_virge_bitblt(virge, -1, 0); + break; + case 0xad68: + virge->s3d.prdx = val; + break; + case 0xad6c: + virge->s3d.prxstart = val; + break; + case 0xad70: + virge->s3d.pldx = val; + break; + case 0xad74: + virge->s3d.plxstart = val; + break; + case 0xad78: + virge->s3d.pystart = val & 0x7ff; + break; + case 0xad7c: + virge->s3d.pycnt = val & 0x300007ff; + if (virge->s3d.cmd_set & CMD_SET_AE) + s3_virge_bitblt(virge, -1, 0); + break; + + case 0xb4d4: + virge->s3d_tri.z_base = val & 0x3ffff8; + break; + case 0xb4d8: + virge->s3d_tri.dest_base = val & 0x3ffff8; + break; + case 0xb4dc: + virge->s3d_tri.clip_l = (val >> 16) & 0x7ff; + virge->s3d_tri.clip_r = val & 0x7ff; + break; + case 0xb4e0: + virge->s3d_tri.clip_t = (val >> 16) & 0x7ff; + virge->s3d_tri.clip_b = val & 0x7ff; + break; + case 0xb4e4: + virge->s3d_tri.dest_str = (val >> 16) & 0xff8; + virge->s3d.src_str = val & 0xff8; + break; + case 0xb4e8: + virge->s3d_tri.z_str = val & 0xff8; + break; + case 0xb4ec: + virge->s3d_tri.tex_base = val & 0x3ffff8; + break; + case 0xb4f0: + virge->s3d_tri.tex_bdr_clr = val & 0xffffff; + break; + case 0xb500: + virge->s3d_tri.cmd_set = val; + if (!(val & CMD_SET_AE)) + queue_triangle(virge); +/* { + thread_set_event(virge->wake_render_thread); + thread_wait_event(virge->wake_main_thread, -1); + } */ +// s3_virge_triangle(virge); + break; + case 0xb504: + virge->s3d_tri.tbv = val & 0xfffff; + break; + case 0xb508: + virge->s3d_tri.tbu = val & 0xfffff; + break; + case 0xb50c: + virge->s3d_tri.TdWdX = val; + break; + case 0xb510: + virge->s3d_tri.TdWdY = val; + break; + case 0xb514: + virge->s3d_tri.tws = val; + break; + case 0xb518: + virge->s3d_tri.TdDdX = val; + break; + case 0xb51c: + virge->s3d_tri.TdVdX = val; + break; + case 0xb520: + virge->s3d_tri.TdUdX = val; + break; + case 0xb524: + virge->s3d_tri.TdDdY = val; + break; + case 0xb528: + virge->s3d_tri.TdVdY = val; + break; + case 0xb52c: + virge->s3d_tri.TdUdY = val; + break; + case 0xb530: + virge->s3d_tri.tds = val; + break; + case 0xb534: + virge->s3d_tri.tvs = val; + break; + case 0xb538: + virge->s3d_tri.tus = val; + break; + case 0xb53c: + virge->s3d_tri.TdGdX = val >> 16; + virge->s3d_tri.TdBdX = val & 0xffff; + break; + case 0xb540: + virge->s3d_tri.TdAdX = val >> 16; + virge->s3d_tri.TdRdX = val & 0xffff; + break; + case 0xb544: + virge->s3d_tri.TdGdY = val >> 16; + virge->s3d_tri.TdBdY = val & 0xffff; + break; + case 0xb548: + virge->s3d_tri.TdAdY = val >> 16; + virge->s3d_tri.TdRdY = val & 0xffff; + break; + case 0xb54c: + virge->s3d_tri.tgs = (val >> 16) & 0xffff; + virge->s3d_tri.tbs = val & 0xffff; + break; + case 0xb550: + virge->s3d_tri.tas = (val >> 16) & 0xffff; + virge->s3d_tri.trs = val & 0xffff; + break; + + case 0xb554: + virge->s3d_tri.TdZdX = val; + break; + case 0xb558: + virge->s3d_tri.TdZdY = val; + break; + case 0xb55c: + virge->s3d_tri.tzs = val; + break; + case 0xb560: + virge->s3d_tri.TdXdY12 = val; + break; + case 0xb564: + virge->s3d_tri.txend12 = val; + break; + case 0xb568: + virge->s3d_tri.TdXdY01 = val; + break; + case 0xb56c: + virge->s3d_tri.txend01 = val; + break; + case 0xb570: + virge->s3d_tri.TdXdY02 = val; + break; + case 0xb574: + virge->s3d_tri.txs = val; + break; + case 0xb578: + virge->s3d_tri.tys = val; + break; + case 0xb57c: + virge->s3d_tri.ty01 = (val >> 16) & 0x7ff; + virge->s3d_tri.ty12 = val & 0x7ff; + virge->s3d_tri.tlr = val >> 31; + if (virge->s3d_tri.cmd_set & CMD_SET_AE) + queue_triangle(virge); +/* { + thread_set_event(virge->wake_render_thread); + thread_wait_event(virge->wake_main_thread, -1); + }*/ + +// s3_virge_triangle(virge); + break; + } +} + +#define READ(addr, val) \ + do \ + { \ + switch (bpp) \ + { \ + case 0: /*8 bpp*/ \ + val = vram[addr & 0x3fffff]; \ + break; \ + case 1: /*16 bpp*/ \ + val = *(uint16_t *)&vram[addr & 0x3fffff]; \ + break; \ + case 2: /*24 bpp*/ \ + val = (*(uint32_t *)&vram[addr & 0x3fffff]) & 0xffffff; \ + break; \ + } \ + } while (0) + +#define Z_READ(addr) *(uint16_t *)&vram[addr & 0x3fffff] + +#define Z_WRITE(addr, val) if (!(s3d_tri->cmd_set & CMD_SET_ZB_MODE)) *(uint16_t *)&vram[addr & 0x3fffff] = val + +#define CLIP(x, y) \ + do \ + { \ + if ((virge->s3d.cmd_set & CMD_SET_HC) && \ + (x < virge->s3d.clip_l || \ + x > virge->s3d.clip_r || \ + y < virge->s3d.clip_t || \ + y > virge->s3d.clip_b)) \ + update = 0; \ + } while (0) + +#define CLIP_3D(x, y) \ + do \ + { \ + if ((s3d_tri->cmd_set & CMD_SET_HC) && \ + (x < s3d_tri->clip_l || \ + x > s3d_tri->clip_r || \ + y < s3d_tri->clip_t || \ + y > s3d_tri->clip_b)) \ + update = 0; \ + } while (0) + +#define Z_CLIP(Zzb, Zs) \ + do \ + { \ + if (!(s3d_tri->cmd_set & CMD_SET_ZB_MODE)) \ + switch ((s3d_tri->cmd_set >> 20) & 7) \ + { \ + case 0: update = 0; break; \ + case 1: if (Zs <= Zzb) update = 0; else Zzb = Zs; break; \ + case 2: if (Zs != Zzb) update = 0; else Zzb = Zs; break; \ + case 3: if (Zs < Zzb) update = 0; else Zzb = Zs; break; \ + case 4: if (Zs >= Zzb) update = 0; else Zzb = Zs; break; \ + case 5: if (Zs == Zzb) update = 0; else Zzb = Zs; break; \ + case 6: if (Zs > Zzb) update = 0; else Zzb = Zs; break; \ + case 7: update = 1; Zzb = Zs; break; \ + } \ + } while (0) + +#define MIX() \ + do \ + { \ + int c; \ + for (c = 0; c < 24; c++) \ + { \ + int d = (dest & (1 << c)) ? 1 : 0; \ + if (source & (1 << c)) d |= 2; \ + if (pattern & (1 << c)) d |= 4; \ + if (virge->s3d.rop & (1 << d)) out |= (1 << c); \ + } \ + } while (0) + +#define WRITE(addr, val) \ + do \ + { \ + switch (bpp) \ + { \ + case 0: /*8 bpp*/ \ + vram[addr & 0x3fffff] = val; \ + virge->svga.changedvram[(addr & 0x3fffff) >> 12] = changeframecount; \ + break; \ + case 1: /*16 bpp*/ \ + *(uint16_t *)&vram[addr & 0x3fffff] = val; \ + virge->svga.changedvram[(addr & 0x3fffff) >> 12] = changeframecount; \ + break; \ + case 2: /*24 bpp*/ \ + *(uint32_t *)&vram[addr & 0x3fffff] = (val & 0xffffff) | \ + (vram[(addr + 3) & 0x3fffff] << 24); \ + virge->svga.changedvram[(addr & 0x3fffff) >> 12] = changeframecount; \ + break; \ + } \ + } while (0) + +static void s3_virge_bitblt(virge_t *virge, int count, uint32_t cpu_dat) +{ + int cpu_input = (count != -1); + uint8_t *vram = virge->svga.vram; + uint32_t mono_pattern[64]; + int count_mask; + int x_inc = (virge->s3d.cmd_set & CMD_SET_XP) ? 1 : -1; + int y_inc = (virge->s3d.cmd_set & CMD_SET_YP) ? 1 : -1; + int bpp; + int x_mul; + int cpu_dat_shift; + uint32_t *pattern_data; + + switch (virge->s3d.cmd_set & CMD_SET_FORMAT_MASK) + { + case CMD_SET_FORMAT_8: + bpp = 0; + x_mul = 1; + cpu_dat_shift = 8; + pattern_data = virge->s3d.pattern_8; + break; + case CMD_SET_FORMAT_16: + bpp = 1; + x_mul = 2; + cpu_dat_shift = 16; + pattern_data = virge->s3d.pattern_16; + break; + case CMD_SET_FORMAT_24: + default: + bpp = 2; + x_mul = 3; + cpu_dat_shift = 24; + pattern_data = virge->s3d.pattern_32; + break; + } + if (virge->s3d.cmd_set & CMD_SET_MP) + pattern_data = mono_pattern; + + switch (virge->s3d.cmd_set & CMD_SET_ITA_MASK) + { + case CMD_SET_ITA_BYTE: + count_mask = ~0x7; + break; + case CMD_SET_ITA_WORD: + count_mask = ~0xf; + break; + case CMD_SET_ITA_DWORD: + default: + count_mask = ~0x1f; + break; + } + if (virge->s3d.cmd_set & CMD_SET_MP) + { + int x, y; + for (y = 0; y < 4; y++) + { + for (x = 0; x < 8; x++) + { + if (virge->s3d.mono_pat_0 & (1 << (x + y*8))) + mono_pattern[y*8 + x] = virge->s3d.pat_fg_clr; + else + mono_pattern[y*8 + x] = virge->s3d.pat_bg_clr; + if (virge->s3d.mono_pat_1 & (1 << (x + y*8))) + mono_pattern[(y+4)*8 + x] = virge->s3d.pat_fg_clr; + else + mono_pattern[(y+4)*8 + x] = virge->s3d.pat_bg_clr; + } + } + } + switch (virge->s3d.cmd_set & CMD_SET_COMMAND_MASK) + { + case CMD_SET_COMMAND_NOP: + break; + + case CMD_SET_COMMAND_BITBLT: + if (count == -1) + { + virge->s3d.src_x = virge->s3d.rsrc_x; + virge->s3d.src_y = virge->s3d.rsrc_y; + virge->s3d.dest_x = virge->s3d.rdest_x; + virge->s3d.dest_y = virge->s3d.rdest_y; + virge->s3d.w = virge->s3d.r_width; + virge->s3d.h = virge->s3d.r_height; + virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; + virge->s3d.data_left_count = 0; + +/* pclog("BitBlt start %i,%i %i,%i %i,%i %02X %x %x\n", + virge->s3d.src_x, + virge->s3d.src_y, + virge->s3d.dest_x, + virge->s3d.dest_y, + virge->s3d.w, + virge->s3d.h, + virge->s3d.rop, + virge->s3d.src_base, + virge->s3d.dest_base);*/ + + if (virge->s3d.cmd_set & CMD_SET_IDS) + return; + } + if (!virge->s3d.h) + return; + while (count) + { + uint32_t src_addr = virge->s3d.src_base + (virge->s3d.src_x * x_mul) + (virge->s3d.src_y * virge->s3d.src_str); + uint32_t dest_addr = virge->s3d.dest_base + (virge->s3d.dest_x * x_mul) + (virge->s3d.dest_y * virge->s3d.dest_str); + uint32_t source, dest, pattern; + uint32_t out = 0; + int update = 1; + + switch (virge->s3d.cmd_set & (CMD_SET_MS | CMD_SET_IDS)) + { + case 0: + case CMD_SET_MS: + READ(src_addr, source); + if ((virge->s3d.cmd_set & CMD_SET_TP) && source == virge->s3d.src_fg_clr) + update = 0; + break; + case CMD_SET_IDS: + if (virge->s3d.data_left_count) + { + /*Handle shifting for 24-bit data*/ + source = virge->s3d.data_left; + source |= ((cpu_dat << virge->s3d.data_left_count) & ~0xff000000); + cpu_dat >>= (cpu_dat_shift - virge->s3d.data_left_count); + count -= (cpu_dat_shift - virge->s3d.data_left_count); + virge->s3d.data_left_count = 0; + if (count < cpu_dat_shift) + { + virge->s3d.data_left = cpu_dat; + virge->s3d.data_left_count = count; + count = 0; + } + } + else + { + source = cpu_dat; + cpu_dat >>= cpu_dat_shift; + count -= cpu_dat_shift; + if (count < cpu_dat_shift) + { + virge->s3d.data_left = cpu_dat; + virge->s3d.data_left_count = count; + count = 0; + } + } + if ((virge->s3d.cmd_set & CMD_SET_TP) && source == virge->s3d.src_fg_clr) + update = 0; + break; + case CMD_SET_IDS | CMD_SET_MS: + source = (cpu_dat & (1 << 31)) ? virge->s3d.src_fg_clr : virge->s3d.src_bg_clr; + if ((virge->s3d.cmd_set & CMD_SET_TP) && !(cpu_dat & (1 << 31))) + update = 0; + cpu_dat <<= 1; + count--; + break; + } + + CLIP(virge->s3d.dest_x, virge->s3d.dest_y); + + if (update) + { + READ(dest_addr, dest); + pattern = pattern_data[(virge->s3d.dest_y & 7)*8 + (virge->s3d.dest_x & 7)]; + MIX(); + + WRITE(dest_addr, out); + } + + virge->s3d.src_x += x_inc; + virge->s3d.src_x &= 0x7ff; + virge->s3d.dest_x += x_inc; + virge->s3d.dest_x &= 0x7ff; + if (!virge->s3d.w) + { + virge->s3d.src_x = virge->s3d.rsrc_x; + virge->s3d.dest_x = virge->s3d.rdest_x; + virge->s3d.w = virge->s3d.r_width; + + virge->s3d.src_y += y_inc; + virge->s3d.dest_y += y_inc; + virge->s3d.h--; + + switch (virge->s3d.cmd_set & (CMD_SET_MS | CMD_SET_IDS)) + { + case CMD_SET_IDS: + cpu_dat >>= (count - (count & count_mask)); + count &= count_mask; + virge->s3d.data_left_count = 0; + break; + + case CMD_SET_IDS | CMD_SET_MS: + cpu_dat <<= (count - (count & count_mask)); + count &= count_mask; + break; + } + if (!virge->s3d.h) + { + return; + } + } + else + virge->s3d.w--; + } + break; + + case CMD_SET_COMMAND_RECTFILL: + /*No source, pattern = pat_fg_clr*/ + if (count == -1) + { + virge->s3d.src_x = virge->s3d.rsrc_x; + virge->s3d.src_y = virge->s3d.rsrc_y; + virge->s3d.dest_x = virge->s3d.rdest_x; + virge->s3d.dest_y = virge->s3d.rdest_y; + virge->s3d.w = virge->s3d.r_width; + virge->s3d.h = virge->s3d.r_height; + virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; + +/* pclog("RctFll start %i,%i %i,%i %02X %08x\n", virge->s3d.dest_x, + virge->s3d.dest_y, + virge->s3d.w, + virge->s3d.h, + virge->s3d.rop, virge->s3d.dest_base);*/ + } + + while (count && virge->s3d.h) + { + uint32_t dest_addr = virge->s3d.dest_base + (virge->s3d.dest_x * x_mul) + (virge->s3d.dest_y * virge->s3d.dest_str); + uint32_t source = 0, dest, pattern = virge->s3d.pat_fg_clr; + uint32_t out = 0; + int update = 1; + + CLIP(virge->s3d.dest_x, virge->s3d.dest_y); + + if (update) + { + READ(dest_addr, dest); + + MIX(); + + WRITE(dest_addr, out); + } + + virge->s3d.src_x += x_inc; + virge->s3d.src_x &= 0x7ff; + virge->s3d.dest_x += x_inc; + virge->s3d.dest_x &= 0x7ff; + if (!virge->s3d.w) + { + virge->s3d.src_x = virge->s3d.rsrc_x; + virge->s3d.dest_x = virge->s3d.rdest_x; + virge->s3d.w = virge->s3d.r_width; + + virge->s3d.src_y += y_inc; + virge->s3d.dest_y += y_inc; + virge->s3d.h--; + if (!virge->s3d.h) + { + return; + } + } + else + virge->s3d.w--; + count--; + } + break; + + case CMD_SET_COMMAND_LINE: + if (count == -1) + { + virge->s3d.dest_x = virge->s3d.lxstart; + virge->s3d.dest_y = virge->s3d.lystart; + virge->s3d.h = virge->s3d.lycnt; + virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; + } + while (virge->s3d.h) + { + int x; + int new_x; + int first_pixel = 1; + + x = virge->s3d.dest_x >> 20; + + if (virge->s3d.h == virge->s3d.lycnt && + ((virge->s3d.line_dir && x > virge->s3d.lxend0) || + (!virge->s3d.line_dir && x < virge->s3d.lxend0))) + x = virge->s3d.lxend0; + + if (virge->s3d.h == 1) + new_x = virge->s3d.lxend1 + (virge->s3d.line_dir ? 1 : -1); + else + new_x = (virge->s3d.dest_x + virge->s3d.ldx) >> 20; + + + if ((virge->s3d.line_dir && x > new_x) || + (!virge->s3d.line_dir && x < new_x)) + goto skip_line; + + do + { + uint32_t dest_addr = virge->s3d.dest_base + (x * x_mul) + (virge->s3d.dest_y * virge->s3d.dest_str); + uint32_t source = 0, dest, pattern; + uint32_t out = 0; + int update = 1; + + if ((virge->s3d.h == virge->s3d.lycnt || !first_pixel) && + ((virge->s3d.line_dir && x < virge->s3d.lxend0) || + (!virge->s3d.line_dir && x > virge->s3d.lxend0))) + update = 0; + + if ((virge->s3d.h == 1 || !first_pixel) && + ((virge->s3d.line_dir && x > virge->s3d.lxend1) || + (!virge->s3d.line_dir && x < virge->s3d.lxend1))) + update = 0; + + CLIP(x, virge->s3d.dest_y); + + if (update) + { + READ(dest_addr, dest); + pattern = virge->s3d.pat_fg_clr; + + MIX(); + + WRITE(dest_addr, out); + } + + if (x < new_x) + x++; + else if (x > new_x) + x--; + first_pixel = 0; + } while (x != new_x); + +skip_line: + virge->s3d.dest_x += virge->s3d.ldx; + virge->s3d.dest_y--; + virge->s3d.h--; + } + break; + + case CMD_SET_COMMAND_POLY: + /*No source*/ + if (virge->s3d.pycnt & (1 << 28)) + virge->s3d.dest_r = virge->s3d.prxstart; + if (virge->s3d.pycnt & (1 << 29)) + virge->s3d.dest_l = virge->s3d.plxstart; + virge->s3d.h = virge->s3d.pycnt & 0x7ff; + virge->s3d.rop = (virge->s3d.cmd_set >> 17) & 0xff; + //pclog("Start poly - l=%08x r=%08x h=%i rop=%02x\n", virge->s3d.dest_l, virge->s3d.dest_r, virge->s3d.h, virge->s3d.rop); + while (virge->s3d.h) + { + int x = virge->s3d.dest_l >> 20; + int xend = virge->s3d.dest_r >> 20; + int y = virge->s3d.pystart & 0x7ff; + int xdir = (x < xend) ? 1 : -1; + //pclog(" %03i: %i - %i %08x-%08x\n", y, x, xend, virge->s3d.dest_l, virge->s3d.dest_r); + do + { + uint32_t dest_addr = virge->s3d.dest_base + (x * x_mul) + (y * virge->s3d.dest_str); + uint32_t source = 0, dest, pattern; + uint32_t out = 0; + int update = 1; + + CLIP(x, y); + + if (update) + { + READ(dest_addr, dest); + pattern = pattern_data[(y & 7)*8 + (x & 7)]; + MIX(); + + WRITE(dest_addr, out); + } + + x = (x + xdir) & 0x7ff; + } + while (x != (xend + xdir)); + + virge->s3d.dest_l += virge->s3d.pldx; + virge->s3d.dest_r += virge->s3d.prdx; + virge->s3d.h--; + virge->s3d.pystart = (virge->s3d.pystart - 1) & 0x7ff; + } + break; + + default: + fatal("s3_virge_bitblt : blit command %i %08x\n", (virge->s3d.cmd_set >> 27) & 0xf, virge->s3d.cmd_set); + } +} + +#define RGB15_TO_24(val, r, g, b) b = ((val & 0x001f) << 3) | ((val & 0x001f) >> 2); \ + g = ((val & 0x03e0) >> 2) | ((val & 0x03e0) >> 7); \ + r = ((val & 0x7c00) >> 7) | ((val & 0x7c00) >> 12); + +#define RGB24_TO_24(val, r, g, b) b = val & 0xff; \ + g = (val & 0xff00) >> 8; \ + r = (val & 0xff0000) >> 16 + +#define RGB15(r, g, b, dest) \ + if (virge->dithering_enabled) \ + { \ + int add = dither[_y & 3][_x & 3]; \ + int _r = (r > 248) ? 248 : r+add; \ + int _g = (g > 248) ? 248 : g+add; \ + int _b = (b > 248) ? 248 : b+add; \ + dest = ((_b >> 3) & 0x1f) | (((_g >> 3) & 0x1f) << 5) | (((_r >> 3) & 0x1f) << 10); \ + } \ + else \ + dest = ((b >> 3) & 0x1f) | (((g >> 3) & 0x1f) << 5) | (((r >> 3) & 0x1f) << 10) + +#define RGB24(r, g, b) ((b) | ((g) << 8) | ((r) << 16)) + +typedef struct rgba_t +{ + int r, g, b, a; +} rgba_t; + +typedef struct s3d_state_t +{ + int32_t r, g, b, a, u, v, d, w; + + int32_t base_r, base_g, base_b, base_a, base_u, base_v, base_d, base_w; + + uint32_t base_z; + + uint32_t tbu, tbv; + + uint32_t cmd_set; + int max_d; + + uint16_t *texture[10]; + + uint32_t tex_bdr_clr; + + int32_t x1, x2; + int y; + + rgba_t dest_rgba; +} s3d_state_t; + +typedef struct s3d_texture_state_t +{ + int level; + int texture_shift; + + int32_t u, v; +} s3d_texture_state_t; + +static void (*tex_read)(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out); +static void (*tex_sample)(s3d_state_t *state); +static void (*dest_pixel)(s3d_state_t *state); + +#define MAX(a, b) ((a) > (b) ? (a) : (b)) +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +static int _x, _y; + +static void tex_ARGB1555(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ + int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); + uint16_t val = state->texture[texture_state->level][offset]; + + out->r = ((val & 0x7c00) >> 7) | ((val & 0x7000) >> 12); + out->g = ((val & 0x03e0) >> 2) | ((val & 0x0380) >> 7); + out->b = ((val & 0x001f) << 3) | ((val & 0x001c) >> 2); + out->a = (val & 0x8000) ? 0xff : 0; +} + +static void tex_ARGB1555_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ + int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); + uint16_t val = state->texture[texture_state->level][offset]; + + if (((texture_state->u | texture_state->v) & 0xf8000000) == 0xf8000000) + val = state->tex_bdr_clr; + + out->r = ((val & 0x7c00) >> 7) | ((val & 0x7000) >> 12); + out->g = ((val & 0x03e0) >> 2) | ((val & 0x0380) >> 7); + out->b = ((val & 0x001f) << 3) | ((val & 0x001c) >> 2); + out->a = (val & 0x8000) ? 0xff : 0; +} + +static void tex_ARGB4444(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ + int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); + uint16_t val = state->texture[texture_state->level][offset]; + + out->r = ((val & 0x0f00) >> 4) | ((val & 0x0f00) >> 8); + out->g = (val & 0x00f0) | ((val & 0x00f0) >> 4); + out->b = ((val & 0x000f) << 4) | (val & 0x000f); + out->a = ((val & 0xf000) >> 8) | ((val & 0xf000) >> 12); +} + +static void tex_ARGB4444_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ + int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); + uint16_t val = state->texture[texture_state->level][offset]; + + if (((texture_state->u | texture_state->v) & 0xf8000000) == 0xf8000000) + val = state->tex_bdr_clr; + + out->r = ((val & 0x0f00) >> 4) | ((val & 0x0f00) >> 8); + out->g = (val & 0x00f0) | ((val & 0x00f0) >> 4); + out->b = ((val & 0x000f) << 4) | (val & 0x000f); + out->a = ((val & 0xf000) >> 8) | ((val & 0xf000) >> 12); +} + +static void tex_ARGB8888(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ + int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); + uint32_t val = ((uint32_t *)state->texture[texture_state->level])[offset]; + + out->r = (val >> 16) & 0xff; + out->g = (val >> 8) & 0xff; + out->b = val & 0xff; + out->a = (val >> 24) & 0xff; +} +static void tex_ARGB8888_nowrap(s3d_state_t *state, s3d_texture_state_t *texture_state, rgba_t *out) +{ + int offset = ((texture_state->u & 0x7fc0000) >> texture_state->texture_shift) + + (((texture_state->v & 0x7fc0000) >> texture_state->texture_shift) << texture_state->level); + uint32_t val = ((uint32_t *)state->texture[texture_state->level])[offset]; + + if (((texture_state->u | texture_state->v) & 0xf8000000) == 0xf8000000) + val = state->tex_bdr_clr; + + out->r = (val >> 16) & 0xff; + out->g = (val >> 8) & 0xff; + out->b = val & 0xff; + out->a = (val >> 24) & 0xff; +} + +static void tex_sample_normal(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + + texture_state.level = state->max_d; + texture_state.texture_shift = 18 + (9 - texture_state.level); + texture_state.u = state->u + state->tbu; + texture_state.v = state->v + state->tbv; + + tex_read(state, &texture_state, &state->dest_rgba); +} + +static void tex_sample_normal_filter(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int tex_offset; + rgba_t tex_samples[4]; + int du, dv; + int d[4]; + + texture_state.level = state->max_d; + texture_state.texture_shift = 18 + (9 - texture_state.level); + tex_offset = 1 << texture_state.texture_shift; + + texture_state.u = state->u + state->tbu; + texture_state.v = state->v + state->tbv; + tex_read(state, &texture_state, &tex_samples[0]); + du = (texture_state.u >> (texture_state.texture_shift - 8)) & 0xff; + dv = (texture_state.v >> (texture_state.texture_shift - 8)) & 0xff; + + texture_state.u = state->u + state->tbu + tex_offset; + texture_state.v = state->v + state->tbv; + tex_read(state, &texture_state, &tex_samples[1]); + + texture_state.u = state->u + state->tbu; + texture_state.v = state->v + state->tbv + tex_offset; + tex_read(state, &texture_state, &tex_samples[2]); + + texture_state.u = state->u + state->tbu + tex_offset; + texture_state.v = state->v + state->tbv + tex_offset; + tex_read(state, &texture_state, &tex_samples[3]); + + d[0] = (256 - du) * (256 - dv); + d[1] = du * (256 - dv); + d[2] = (256 - du) * dv; + d[3] = du * dv; + + state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16; + state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16; + state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16; + state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16; +} + +static void tex_sample_mipmap(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + + texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); + if (texture_state.level < 0) + texture_state.level = 0; + texture_state.texture_shift = 18 + (9 - texture_state.level); + texture_state.u = state->u + state->tbu; + texture_state.v = state->v + state->tbv; + + tex_read(state, &texture_state, &state->dest_rgba); +} + +static void tex_sample_mipmap_filter(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int tex_offset; + rgba_t tex_samples[4]; + int du, dv; + int d[4]; + + texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); + if (texture_state.level < 0) + texture_state.level = 0; + texture_state.texture_shift = 18 + (9 - texture_state.level); + tex_offset = 1 << texture_state.texture_shift; + + texture_state.u = state->u + state->tbu; + texture_state.v = state->v + state->tbv; + tex_read(state, &texture_state, &tex_samples[0]); + du = (texture_state.u >> (texture_state.texture_shift - 8)) & 0xff; + dv = (texture_state.v >> (texture_state.texture_shift - 8)) & 0xff; + + texture_state.u = state->u + state->tbu + tex_offset; + texture_state.v = state->v + state->tbv; + tex_read(state, &texture_state, &tex_samples[1]); + + texture_state.u = state->u + state->tbu; + texture_state.v = state->v + state->tbv + tex_offset; + tex_read(state, &texture_state, &tex_samples[2]); + + texture_state.u = state->u + state->tbu + tex_offset; + texture_state.v = state->v + state->tbv + tex_offset; + tex_read(state, &texture_state, &tex_samples[3]); + + d[0] = (256 - du) * (256 - dv); + d[1] = du * (256 - dv); + d[2] = (256 - du) * dv; + d[3] = du * dv; + + state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16; + state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16; + state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16; + state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16; +} + +static void tex_sample_persp_normal(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int32_t w = 0; + + if (state->w) + w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + + texture_state.level = state->max_d; + texture_state.texture_shift = 18 + (9 - texture_state.level); + texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu; + texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv; + + tex_read(state, &texture_state, &state->dest_rgba); +} + +static void tex_sample_persp_normal_filter(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int32_t w = 0, u, v; + int tex_offset; + rgba_t tex_samples[4]; + int du, dv; + int d[4]; + + if (state->w) + w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + + u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu; + v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv; + + texture_state.level = state->max_d; + texture_state.texture_shift = 18 + (9 - texture_state.level); + tex_offset = 1 << texture_state.texture_shift; + + texture_state.u = u; + texture_state.v = v; + tex_read(state, &texture_state, &tex_samples[0]); + du = (u >> (texture_state.texture_shift - 8)) & 0xff; + dv = (v >> (texture_state.texture_shift - 8)) & 0xff; + + texture_state.u = u + tex_offset; + texture_state.v = v; + tex_read(state, &texture_state, &tex_samples[1]); + + texture_state.u = u; + texture_state.v = v + tex_offset; + tex_read(state, &texture_state, &tex_samples[2]); + + texture_state.u = u + tex_offset; + texture_state.v = v + tex_offset; + tex_read(state, &texture_state, &tex_samples[3]); + + d[0] = (256 - du) * (256 - dv); + d[1] = du * (256 - dv); + d[2] = (256 - du) * dv; + d[3] = du * dv; + + state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16; + state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16; + state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16; + state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16; +} + +static void tex_sample_persp_normal_375(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int32_t w = 0; + + if (state->w) + w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + + texture_state.level = state->max_d; + texture_state.texture_shift = 18 + (9 - texture_state.level); + texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu; + texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv; + + tex_read(state, &texture_state, &state->dest_rgba); +} + +static void tex_sample_persp_normal_filter_375(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int32_t w = 0, u, v; + int tex_offset; + rgba_t tex_samples[4]; + int du, dv; + int d[4]; + + if (state->w) + w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + + u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu; + v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv; + + texture_state.level = state->max_d; + texture_state.texture_shift = 18 + (9 - texture_state.level); + tex_offset = 1 << texture_state.texture_shift; + + texture_state.u = u; + texture_state.v = v; + tex_read(state, &texture_state, &tex_samples[0]); + du = (u >> (texture_state.texture_shift - 8)) & 0xff; + dv = (v >> (texture_state.texture_shift - 8)) & 0xff; + + texture_state.u = u + tex_offset; + texture_state.v = v; + tex_read(state, &texture_state, &tex_samples[1]); + + texture_state.u = u; + texture_state.v = v + tex_offset; + tex_read(state, &texture_state, &tex_samples[2]); + + texture_state.u = u + tex_offset; + texture_state.v = v + tex_offset; + tex_read(state, &texture_state, &tex_samples[3]); + + d[0] = (256 - du) * (256 - dv); + d[1] = du * (256 - dv); + d[2] = (256 - du) * dv; + d[3] = du * dv; + + state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16; + state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16; + state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16; + state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16; +} + + +static void tex_sample_persp_mipmap(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int32_t w = 0; + + if (state->w) + w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + + texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); + if (texture_state.level < 0) + texture_state.level = 0; + texture_state.texture_shift = 18 + (9 - texture_state.level); + texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu; + texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv; + + tex_read(state, &texture_state, &state->dest_rgba); +} + +static void tex_sample_persp_mipmap_filter(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int32_t w = 0, u, v; + int tex_offset; + rgba_t tex_samples[4]; + int du, dv; + int d[4]; + + if (state->w) + w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + + u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (12 + state->max_d)) + state->tbu; + v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (12 + state->max_d)) + state->tbv; + + texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); + if (texture_state.level < 0) + texture_state.level = 0; + texture_state.texture_shift = 18 + (9 - texture_state.level); + tex_offset = 1 << texture_state.texture_shift; + + texture_state.u = u; + texture_state.v = v; + tex_read(state, &texture_state, &tex_samples[0]); + du = (u >> (texture_state.texture_shift - 8)) & 0xff; + dv = (v >> (texture_state.texture_shift - 8)) & 0xff; + + texture_state.u = u + tex_offset; + texture_state.v = v; + tex_read(state, &texture_state, &tex_samples[1]); + + texture_state.u = u; + texture_state.v = v + tex_offset; + tex_read(state, &texture_state, &tex_samples[2]); + + texture_state.u = u + tex_offset; + texture_state.v = v + tex_offset; + tex_read(state, &texture_state, &tex_samples[3]); + + d[0] = (256 - du) * (256 - dv); + d[1] = du * (256 - dv); + d[2] = (256 - du) * dv; + d[3] = du * dv; + + state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16; + state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16; + state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16; + state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16; +} + +static void tex_sample_persp_mipmap_375(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int32_t w = 0; + + if (state->w) + w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + + texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); + if (texture_state.level < 0) + texture_state.level = 0; + texture_state.texture_shift = 18 + (9 - texture_state.level); + texture_state.u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu; + texture_state.v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv; + + tex_read(state, &texture_state, &state->dest_rgba); +} + +static void tex_sample_persp_mipmap_filter_375(s3d_state_t *state) +{ + s3d_texture_state_t texture_state; + int32_t w = 0, u, v; + int tex_offset; + rgba_t tex_samples[4]; + int du, dv; + int d[4]; + + if (state->w) + w = (int32_t)(((1ULL << 27) << 19) / (int64_t)state->w); + + u = (int32_t)(((int64_t)state->u * (int64_t)w) >> (8 + state->max_d)) + state->tbu; + v = (int32_t)(((int64_t)state->v * (int64_t)w) >> (8 + state->max_d)) + state->tbv; + + texture_state.level = (state->d < 0) ? state->max_d : state->max_d - ((state->d >> 27) & 0xf); + if (texture_state.level < 0) + texture_state.level = 0; + texture_state.texture_shift = 18 + (9 - texture_state.level); + tex_offset = 1 << texture_state.texture_shift; + + texture_state.u = u; + texture_state.v = v; + tex_read(state, &texture_state, &tex_samples[0]); + du = (u >> (texture_state.texture_shift - 8)) & 0xff; + dv = (v >> (texture_state.texture_shift - 8)) & 0xff; + + texture_state.u = u + tex_offset; + texture_state.v = v; + tex_read(state, &texture_state, &tex_samples[1]); + + texture_state.u = u; + texture_state.v = v + tex_offset; + tex_read(state, &texture_state, &tex_samples[2]); + + texture_state.u = u + tex_offset; + texture_state.v = v + tex_offset; + tex_read(state, &texture_state, &tex_samples[3]); + + d[0] = (256 - du) * (256 - dv); + d[1] = du * (256 - dv); + d[2] = (256 - du) * dv; + d[3] = du * dv; + + state->dest_rgba.r = (tex_samples[0].r * d[0] + tex_samples[1].r * d[1] + tex_samples[2].r * d[2] + tex_samples[3].r * d[3]) >> 16; + state->dest_rgba.g = (tex_samples[0].g * d[0] + tex_samples[1].g * d[1] + tex_samples[2].g * d[2] + tex_samples[3].g * d[3]) >> 16; + state->dest_rgba.b = (tex_samples[0].b * d[0] + tex_samples[1].b * d[1] + tex_samples[2].b * d[2] + tex_samples[3].b * d[3]) >> 16; + state->dest_rgba.a = (tex_samples[0].a * d[0] + tex_samples[1].a * d[1] + tex_samples[2].a * d[2] + tex_samples[3].a * d[3]) >> 16; +} + + +#define CLAMP(x) do \ + { \ + if ((x) & ~0xff) \ + x = ((x) < 0) ? 0 : 0xff; \ + } \ + while (0) + +#define CLAMP_RGBA(r, g, b, a) \ + if ((r) & ~0xff) \ + r = ((r) < 0) ? 0 : 0xff; \ + if ((g) & ~0xff) \ + g = ((g) < 0) ? 0 : 0xff; \ + if ((b) & ~0xff) \ + b = ((b) < 0) ? 0 : 0xff; \ + if ((a) & ~0xff) \ + a = ((a) < 0) ? 0 : 0xff; + +#define CLAMP_RGB(r, g, b) do \ + { \ + if ((r) < 0) \ + r = 0; \ + if ((r) > 0xff) \ + r = 0xff; \ + if ((g) < 0) \ + g = 0; \ + if ((g) > 0xff) \ + g = 0xff; \ + if ((b) < 0) \ + b = 0; \ + if ((b) > 0xff) \ + b = 0xff; \ + } \ + while (0) + +static void dest_pixel_gouraud_shaded_triangle(s3d_state_t *state) +{ + state->dest_rgba.r = state->r >> 7; + CLAMP(state->dest_rgba.r); + + state->dest_rgba.g = state->g >> 7; + CLAMP(state->dest_rgba.g); + + state->dest_rgba.b = state->b >> 7; + CLAMP(state->dest_rgba.b); + + state->dest_rgba.a = state->a >> 7; + CLAMP(state->dest_rgba.a); +} + +static void dest_pixel_unlit_texture_triangle(s3d_state_t *state) +{ + tex_sample(state); + + if (state->cmd_set & CMD_SET_ABC_SRC) + state->dest_rgba.a = state->a >> 7; +} + +static void dest_pixel_lit_texture_decal(s3d_state_t *state) +{ + tex_sample(state); + + if (state->cmd_set & CMD_SET_ABC_SRC) + state->dest_rgba.a = state->a >> 7; +} + +static void dest_pixel_lit_texture_reflection(s3d_state_t *state) +{ + tex_sample(state); + + state->dest_rgba.r += (state->r >> 7); + state->dest_rgba.g += (state->g >> 7); + state->dest_rgba.b += (state->b >> 7); + if (state->cmd_set & CMD_SET_ABC_SRC) + state->dest_rgba.a += (state->a >> 7); + + CLAMP_RGBA(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b, state->dest_rgba.a); +} + +static void dest_pixel_lit_texture_modulate(s3d_state_t *state) +{ + int r = state->r >> 7, g = state->g >> 7, b = state->b >> 7, a = state->a >> 7; + + tex_sample(state); + + CLAMP_RGBA(r, g, b, a); + + state->dest_rgba.r = ((state->dest_rgba.r) * r) >> 8; + state->dest_rgba.g = ((state->dest_rgba.g) * g) >> 8; + state->dest_rgba.b = ((state->dest_rgba.b) * b) >> 8; + + if (state->cmd_set & CMD_SET_ABC_SRC) + state->dest_rgba.a = a; +} + +static void tri(virge_t *virge, s3d_t *s3d_tri, s3d_state_t *state, int yc, int32_t dx1, int32_t dx2) +{ + uint8_t *vram = virge->svga.vram; + + int x_dir = s3d_tri->tlr ? 1 : -1; + + int use_z = !(s3d_tri->cmd_set & CMD_SET_ZB_MODE); + + int y_count = yc; + + int bpp = (s3d_tri->cmd_set >> 2) & 7; + + uint32_t dest_offset, z_offset; + + if (s3d_tri->cmd_set & CMD_SET_HC) + { + if (state->y < s3d_tri->clip_t) + return; + if (state->y > s3d_tri->clip_b) + { + int diff_y = state->y - s3d_tri->clip_b; + + if (diff_y > y_count) + diff_y = y_count; + + state->base_u += (s3d_tri->TdUdY * diff_y); + state->base_v += (s3d_tri->TdVdY * diff_y); + state->base_z += (s3d_tri->TdZdY * diff_y); + state->base_r += (s3d_tri->TdRdY * diff_y); + state->base_g += (s3d_tri->TdGdY * diff_y); + state->base_b += (s3d_tri->TdBdY * diff_y); + state->base_a += (s3d_tri->TdAdY * diff_y); + state->base_d += (s3d_tri->TdDdY * diff_y); + state->base_w += (s3d_tri->TdWdY * diff_y); + state->x1 += (dx1 * diff_y); + state->x2 += (dx2 * diff_y); + state->y -= diff_y; + dest_offset -= s3d_tri->dest_str; + z_offset -= s3d_tri->z_str; + y_count -= diff_y; + } + if ((state->y - y_count) < s3d_tri->clip_t) + y_count = state->y - s3d_tri->clip_t; + } + + dest_offset = s3d_tri->dest_base + (state->y * s3d_tri->dest_str); + z_offset = s3d_tri->z_base + (state->y * s3d_tri->z_str); + + for (; y_count > 0; y_count--) + { + int x = (state->x1 + ((1 << 20) - 1)) >> 20; + int xe = (state->x2 + ((1 << 20) - 1)) >> 20; + uint32_t z = (state->base_z > 0) ? (state->base_z << 1) : 0; + if (x_dir < 0) + { + x--; + xe--; + } + + if (x != xe && (x_dir > 0 && x < xe) || (x_dir < 0 && x > xe)) + { + uint32_t dest_addr, z_addr; + int dx = (x_dir > 0) ? ((31 - ((state->x1-1) >> 15)) & 0x1f) : (((state->x1-1) >> 15) & 0x1f); + int x_offset = x_dir * (bpp + 1); + int xz_offset = x_dir << 1; + if (x_dir > 0) + dx += 1; + state->r = state->base_r + ((s3d_tri->TdRdX * dx) >> 5); + state->g = state->base_g + ((s3d_tri->TdGdX * dx) >> 5); + state->b = state->base_b + ((s3d_tri->TdBdX * dx) >> 5); + state->a = state->base_a + ((s3d_tri->TdAdX * dx) >> 5); + state->u = state->base_u + ((s3d_tri->TdUdX * dx) >> 5); + state->v = state->base_v + ((s3d_tri->TdVdX * dx) >> 5); + state->w = state->base_w + ((s3d_tri->TdWdX * dx) >> 5); + state->d = state->base_d + ((s3d_tri->TdDdX * dx) >> 5); + z += ((s3d_tri->TdZdX * dx) >> 5); + +// pclog("Draw Y=%i X=%i to XE=%i %i %08x %08x %08x %08x %08x %08x %08x %08x %i %08x\n", state->y, x, xe, dx, state->x1, state->x2, dx1, virge->s3d.TdWdX, state->u, state->v, virge->s3d.TdUdX, virge->s3d.TdUdY, dx, (virge->s3d.TdUdX * dx) >> 4); + + if (s3d_tri->cmd_set & CMD_SET_HC) + { + if (x_dir > 0) + { + if (x > s3d_tri->clip_r) + goto tri_skip_line; + if (xe < s3d_tri->clip_l) + goto tri_skip_line; + if (xe > s3d_tri->clip_r) + xe = s3d_tri->clip_r; + if (x < s3d_tri->clip_l) + { + int diff_x = s3d_tri->clip_l - x; + + z += (s3d_tri->TdZdX * diff_x); + state->u += (s3d_tri->TdUdX * diff_x); + state->v += (s3d_tri->TdVdX * diff_x); + state->r += (s3d_tri->TdRdX * diff_x); + state->g += (s3d_tri->TdGdX * diff_x); + state->b += (s3d_tri->TdBdX * diff_x); + state->a += (s3d_tri->TdAdX * diff_x); + state->d += (s3d_tri->TdDdX * diff_x); + state->w += (s3d_tri->TdWdX * diff_x); + + x = s3d_tri->clip_l; + } + } + else + { + if (x < s3d_tri->clip_l) + goto tri_skip_line; + if (xe > s3d_tri->clip_r) + goto tri_skip_line; + if (xe < s3d_tri->clip_l) + xe = s3d_tri->clip_l; + if (x > s3d_tri->clip_r) + { + int diff_x = x - s3d_tri->clip_r; + + z += (s3d_tri->TdZdX * diff_x); + state->u += (s3d_tri->TdUdX * diff_x); + state->v += (s3d_tri->TdVdX * diff_x); + state->r += (s3d_tri->TdRdX * diff_x); + state->g += (s3d_tri->TdGdX * diff_x); + state->b += (s3d_tri->TdBdX * diff_x); + state->a += (s3d_tri->TdAdX * diff_x); + state->d += (s3d_tri->TdDdX * diff_x); + state->w += (s3d_tri->TdWdX * diff_x); + + x = s3d_tri->clip_r; + } + } + } + + virge->svga.changedvram[(dest_offset & 0x3fffff) >> 12] = changeframecount; + + dest_addr = dest_offset + (x * (bpp + 1)); + z_addr = z_offset + (x << 1); + + for (; x != xe; x = (x + x_dir) & 0xfff) + { + int update = 1; + uint16_t src_z; + _x = x; _y = state->y; + + if (use_z) + { + src_z = Z_READ(z_addr); + Z_CLIP(src_z, z >> 16); + } + + if (update) + { + uint32_t dest_col; + + dest_pixel(state); + + if (s3d_tri->cmd_set & CMD_SET_ABC_ENABLE) + { + uint32_t src_col; + int src_r, src_g, src_b; + + switch (bpp) + { + case 0: /*8 bpp*/ + /*Not implemented yet*/ + break; + case 1: /*16 bpp*/ + src_col = *(uint16_t *)&vram[dest_addr & 0x3fffff]; + RGB15_TO_24(src_col, src_r, src_g, src_b); + break; + case 2: /*24 bpp*/ + src_col = (*(uint32_t *)&vram[dest_addr & 0x3fffff]) & 0xffffff; + RGB24_TO_24(src_col, src_r, src_g, src_b); + break; + } + + state->dest_rgba.r = ((state->dest_rgba.r * state->dest_rgba.a) + (src_r * (255 - state->dest_rgba.a))) / 255; + state->dest_rgba.g = ((state->dest_rgba.g * state->dest_rgba.a) + (src_g * (255 - state->dest_rgba.a))) / 255; + state->dest_rgba.b = ((state->dest_rgba.b * state->dest_rgba.a) + (src_b * (255 - state->dest_rgba.a))) / 255; + } + + switch (bpp) + { + case 0: /*8 bpp*/ + /*Not implemented yet*/ + break; + case 1: /*16 bpp*/ + RGB15(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b, dest_col); + *(uint16_t *)&vram[dest_addr] = dest_col; + break; + case 2: /*24 bpp*/ + dest_col = RGB24(state->dest_rgba.r, state->dest_rgba.g, state->dest_rgba.b); + *(uint8_t *)&vram[dest_addr] = dest_col & 0xff; + *(uint8_t *)&vram[dest_addr + 1] = (dest_col >> 8) & 0xff; + *(uint8_t *)&vram[dest_addr + 2] = (dest_col >> 16) & 0xff; + break; + } + + if (use_z && (s3d_tri->cmd_set & CMD_SET_ZUP)) + Z_WRITE(z_addr, src_z); + } + + z += s3d_tri->TdZdX; + state->u += s3d_tri->TdUdX; + state->v += s3d_tri->TdVdX; + state->r += s3d_tri->TdRdX; + state->g += s3d_tri->TdGdX; + state->b += s3d_tri->TdBdX; + state->a += s3d_tri->TdAdX; + state->d += s3d_tri->TdDdX; + state->w += s3d_tri->TdWdX; + dest_addr += x_offset; + z_addr += xz_offset; + virge->pixel_count++; + } + } +tri_skip_line: + state->x1 += dx1; + state->x2 += dx2; + state->base_u += s3d_tri->TdUdY; + state->base_v += s3d_tri->TdVdY; + state->base_z += s3d_tri->TdZdY; + state->base_r += s3d_tri->TdRdY; + state->base_g += s3d_tri->TdGdY; + state->base_b += s3d_tri->TdBdY; + state->base_a += s3d_tri->TdAdY; + state->base_d += s3d_tri->TdDdY; + state->base_w += s3d_tri->TdWdY; + state->y--; + dest_offset -= s3d_tri->dest_str; + z_offset -= s3d_tri->z_str; + } +} + +static int tex_size[8] = +{ + 4*2, + 2*2, + 2*2, + 1*2, + 2/1, + 2/1, + 1*2, + 1*2 +}; + +static void s3_virge_triangle(virge_t *virge, s3d_t *s3d_tri) +{ + s3d_state_t state; + + uint32_t tex_base; + int c; + + uint64_t start_time = timer_read(); + uint64_t end_time; + + state.tbu = s3d_tri->tbu << 11; + state.tbv = s3d_tri->tbv << 11; + + state.max_d = (s3d_tri->cmd_set >> 8) & 15; + + state.tex_bdr_clr = s3d_tri->tex_bdr_clr; + + state.cmd_set = s3d_tri->cmd_set; + + state.base_u = s3d_tri->tus; + state.base_v = s3d_tri->tvs; + state.base_z = s3d_tri->tzs; + state.base_r = (int32_t)s3d_tri->trs; + state.base_g = (int32_t)s3d_tri->tgs; + state.base_b = (int32_t)s3d_tri->tbs; + state.base_a = (int32_t)s3d_tri->tas; + state.base_d = s3d_tri->tds; + state.base_w = s3d_tri->tws; + + tex_base = s3d_tri->tex_base; + for (c = 9; c >= 0; c--) + { + state.texture[c] = (uint16_t *)&virge->svga.vram[tex_base]; + if (c <= state.max_d) + tex_base += ((1 << (c*2)) * tex_size[(s3d_tri->cmd_set >> 5) & 7]) / 2; + } + + switch ((s3d_tri->cmd_set >> 27) & 0xf) + { + case 0: + dest_pixel = dest_pixel_gouraud_shaded_triangle; +// pclog("dest_pixel_gouraud_shaded_triangle\n"); + break; + case 1: + case 5: + switch ((s3d_tri->cmd_set >> 15) & 0x3) + { + case 0: + dest_pixel = dest_pixel_lit_texture_reflection; +// pclog("dest_pixel_lit_texture_reflection\n"); + break; + case 1: + dest_pixel = dest_pixel_lit_texture_modulate; +// pclog("dest_pixel_lit_texture_modulate\n"); + break; + case 2: + dest_pixel = dest_pixel_lit_texture_decal; +// pclog("dest_pixel_lit_texture_decal\n"); + break; + default: + pclog("bad triangle type %x\n", (s3d_tri->cmd_set >> 27) & 0xf); + return; + } + break; + case 2: + case 6: + dest_pixel = dest_pixel_unlit_texture_triangle; +// pclog("dest_pixel_unlit_texture_triangle\n"); + break; + default: + pclog("bad triangle type %x\n", (s3d_tri->cmd_set >> 27) & 0xf); + return; + } + + switch (((s3d_tri->cmd_set >> 12) & 7) | ((s3d_tri->cmd_set & (1 << 29)) ? 8 : 0)) + { + case 0: case 1: + tex_sample = tex_sample_mipmap; +// pclog("use tex_sample_mipmap\n"); + break; + case 2: case 3: + tex_sample = virge->bilinear_enabled ? tex_sample_mipmap_filter : tex_sample_mipmap; +// pclog("use tex_sample_mipmap_filter\n"); + break; + case 4: case 5: + tex_sample = tex_sample_normal; +// pclog("use tex_sample_normal\n"); + break; + case 6: case 7: + tex_sample = virge->bilinear_enabled ? tex_sample_normal_filter : tex_sample_normal; +// pclog("use tex_sample_normal_filter\n"); + break; + case (0 | 8): case (1 | 8): + if (virge->is_375) + tex_sample = tex_sample_persp_mipmap_375; + else + tex_sample = tex_sample_persp_mipmap; +// pclog("use tex_sample_persp_mipmap\n"); + break; + case (2 | 8): case (3 | 8): + if (virge->is_375) + tex_sample = virge->bilinear_enabled ? tex_sample_persp_mipmap_filter_375 : tex_sample_persp_mipmap_375; + else + tex_sample = virge->bilinear_enabled ? tex_sample_persp_mipmap_filter : tex_sample_persp_mipmap; +// pclog("use tex_sample_persp_mipmap_filter\n"); + break; + case (4 | 8): case (5 | 8): + if (virge->is_375) + tex_sample = tex_sample_persp_normal_375; + else + tex_sample = tex_sample_persp_normal; +// pclog("use tex_sample_persp_normal\n"); + break; + case (6 | 8): case (7 | 8): + if (virge->is_375) + tex_sample = virge->bilinear_enabled ? tex_sample_persp_normal_filter_375 : tex_sample_persp_normal_375; + else + tex_sample = virge->bilinear_enabled ? tex_sample_persp_normal_filter : tex_sample_persp_normal; +// pclog("use tex_sample_persp_normal_filter\n"); + break; + } + + switch ((s3d_tri->cmd_set >> 5) & 7) + { + case 0: + tex_read = (s3d_tri->cmd_set & CMD_SET_TWE) ? tex_ARGB8888 : tex_ARGB8888_nowrap; + break; + case 1: + tex_read = (s3d_tri->cmd_set & CMD_SET_TWE) ? tex_ARGB4444 : tex_ARGB4444_nowrap; +// pclog("tex_ARGB4444\n"); + break; + case 2: + tex_read = (s3d_tri->cmd_set & CMD_SET_TWE) ? tex_ARGB1555 : tex_ARGB1555_nowrap; +// pclog("tex_ARGB1555 %i\n", (s3d_tri->cmd_set >> 5) & 7); + break; + default: + pclog("bad texture type %i\n", (s3d_tri->cmd_set >> 5) & 7); + tex_read = (s3d_tri->cmd_set & CMD_SET_TWE) ? tex_ARGB1555 : tex_ARGB1555_nowrap; + break; + } + +// pclog("Triangle %i %i,%i to %i,%i %08x\n", y, x1 >> 20, y, s3d_tri->txend01 >> 20, y - (s3d_tri->ty01 + s3d_tri->ty12), state.cmd_set); + + state.y = s3d_tri->tys; + state.x1 = s3d_tri->txs; + state.x2 = s3d_tri->txend01; + tri(virge, s3d_tri, &state, s3d_tri->ty01, s3d_tri->TdXdY02, s3d_tri->TdXdY01); + state.x2 = s3d_tri->txend12; + tri(virge, s3d_tri, &state, s3d_tri->ty12, s3d_tri->TdXdY02, s3d_tri->TdXdY12); + + virge->tri_count++; + + end_time = timer_read(); + + virge_time += end_time - start_time; +} + +static void render_thread(void *param) +{ + virge_t *virge = (virge_t *)param; + + while (1) + { + thread_wait_event(virge->wake_render_thread, -1); + thread_reset_event(virge->wake_render_thread); + virge->s3d_busy = 1; + while (!RB_EMPTY) + { + s3_virge_triangle(virge, &virge->s3d_buffer[virge->s3d_read_idx & RB_MASK]); + virge->s3d_read_idx++; + + if (RB_ENTRIES == RB_SIZE - 1) + thread_set_event(virge->not_full_event); + } + virge->s3d_busy = 0; + } +} + +static void queue_triangle(virge_t *virge) +{ + int c; +// pclog("queue_triangle: read=%i write=%i RB_ENTRIES=%i RB_FULL=%i\n", virge->s3d_read_idx, virge->s3d_write_idx, RB_ENTRIES, RB_FULL); + if (RB_FULL) + { + thread_reset_event(virge->not_full_event); + if (RB_FULL) + thread_wait_event(virge->not_full_event, -1); /*Wait for room in ringbuffer*/ + } +// pclog(" add at read=%i write=%i %i\n", virge->s3d_read_idx, virge->s3d_write_idx, virge->s3d_write_idx & RB_MASK); + virge->s3d_buffer[virge->s3d_write_idx & RB_MASK] = virge->s3d_tri; + virge->s3d_write_idx++; + if (!virge->s3d_busy) + thread_set_event(virge->wake_render_thread); /*Wake up render thread if moving from idle*/ +} + +static void s3_virge_hwcursor_draw(svga_t *svga, int displine) +{ + virge_t *virge = (virge_t *)svga->p; + int x; + uint16_t dat[2]; + int xx; + int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; + int y_add = enable_overscan ? 16 : 0; + int x_add = enable_overscan ? 8 : 0; + +// pclog("HWcursor %i %i\n", svga->hwcursor_latch.x, svga->hwcursor_latch.y); + for (x = 0; x < 64; x += 16) + { + dat[0] = (svga->vram[svga->hwcursor_latch.addr] << 8) | svga->vram[svga->hwcursor_latch.addr + 1]; + dat[1] = (svga->vram[svga->hwcursor_latch.addr + 2] << 8) | svga->vram[svga->hwcursor_latch.addr + 3]; + if (svga->crtc[0x55] & 0x10) + { + /*X11*/ + for (xx = 0; xx < 16; xx++) + { + if (offset >= svga->hwcursor_latch.x) + { + if (dat[0] & 0x8000) + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = virge->hwcursor_col[dat[1] >> 15]; + } + + offset++; + dat[0] <<= 1; + dat[1] <<= 1; + } + } + else + { + /*Windows*/ + for (xx = 0; xx < 16; xx++) + { + if (offset >= svga->hwcursor_latch.x) + { + if (!(dat[0] & 0x8000)) + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = virge->hwcursor_col[dat[1] >> 15]; + else if (dat[1] & 0x8000) + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] ^= 0xffffff; +// pclog("Plot %i, %i (%i %i) %04X %04X\n", offset, displine, x+xx, svga->hwcursor_on, dat[0], dat[1]); + } + + offset++; + dat[0] <<= 1; + dat[1] <<= 1; + } + } + svga->hwcursor_latch.addr += 4; + } +} + +#define DECODE_YCbCr() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 2; c++) \ + { \ + uint8_t y1, y2; \ + int8_t Cr, Cb; \ + int dR, dG, dB; \ + \ + y1 = src[0]; \ + Cr = src[1] - 0x80; \ + y2 = src[2]; \ + Cb = src[3] - 0x80; \ + src += 4; \ + \ + dR = (359*Cr) >> 8; \ + dG = (88*Cb + 183*Cr) >> 8; \ + dB = (453*Cb) >> 8; \ + \ + r[x_write] = y1 + dR; \ + CLAMP(r[x_write]); \ + g[x_write] = y1 - dG; \ + CLAMP(g[x_write]); \ + b[x_write] = y1 + dB; \ + CLAMP(b[x_write]); \ + \ + r[x_write+1] = y2 + dR; \ + CLAMP(r[x_write+1]); \ + g[x_write+1] = y2 - dG; \ + CLAMP(g[x_write+1]); \ + b[x_write+1] = y2 + dB; \ + CLAMP(b[x_write+1]); \ + \ + x_write = (x_write + 2) & 7; \ + } \ + } while (0) + +/*Both YUV formats are untested*/ +#define DECODE_YUV211() \ + do \ + { \ + uint8_t y1, y2, y3, y4; \ + int8_t U, V; \ + int dR, dG, dB; \ + \ + U = src[0] - 0x80; \ + y1 = (298 * (src[1] - 16)) >> 8; \ + y2 = (298 * (src[2] - 16)) >> 8; \ + V = src[3] - 0x80; \ + y3 = (298 * (src[4] - 16)) >> 8; \ + y4 = (298 * (src[5] - 16)) >> 8; \ + src += 6; \ + \ + dR = (309*V) >> 8; \ + dG = (100*U + 208*V) >> 8; \ + dB = (516*U) >> 8; \ + \ + r[x_write] = y1 + dR; \ + CLAMP(r[x_write]); \ + g[x_write] = y1 - dG; \ + CLAMP(g[x_write]); \ + b[x_write] = y1 + dB; \ + CLAMP(b[x_write]); \ + \ + r[x_write+1] = y2 + dR; \ + CLAMP(r[x_write+1]); \ + g[x_write+1] = y2 - dG; \ + CLAMP(g[x_write+1]); \ + b[x_write+1] = y2 + dB; \ + CLAMP(b[x_write+1]); \ + \ + r[x_write+2] = y2 + dR; \ + CLAMP(r[x_write+2]); \ + g[x_write+2] = y2 - dG; \ + CLAMP(g[x_write+2]); \ + b[x_write+2] = y2 + dB; \ + CLAMP(b[x_write+2]); \ + \ + r[x_write+3] = y2 + dR; \ + CLAMP(r[x_write+3]); \ + g[x_write+3] = y2 - dG; \ + CLAMP(g[x_write+3]); \ + b[x_write+3] = y2 + dB; \ + CLAMP(b[x_write+3]); \ + \ + x_write = (x_write + 4) & 7; \ + } while (0) + +#define DECODE_YUV422() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 2; c++) \ + { \ + uint8_t y1, y2; \ + int8_t U, V; \ + int dR, dG, dB; \ + \ + U = src[0] - 0x80; \ + y1 = (298 * (src[1] - 16)) >> 8; \ + V = src[2] - 0x80; \ + y2 = (298 * (src[3] - 16)) >> 8; \ + src += 4; \ + \ + dR = (309*V) >> 8; \ + dG = (100*U + 208*V) >> 8; \ + dB = (516*U) >> 8; \ + \ + r[x_write] = y1 + dR; \ + CLAMP(r[x_write]); \ + g[x_write] = y1 - dG; \ + CLAMP(g[x_write]); \ + b[x_write] = y1 + dB; \ + CLAMP(b[x_write]); \ + \ + r[x_write+1] = y2 + dR; \ + CLAMP(r[x_write+1]); \ + g[x_write+1] = y2 - dG; \ + CLAMP(g[x_write+1]); \ + b[x_write+1] = y2 + dB; \ + CLAMP(b[x_write+1]); \ + \ + x_write = (x_write + 2) & 7; \ + } \ + } while (0) + +#define DECODE_RGB555() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 4; c++) \ + { \ + uint16_t dat; \ + \ + dat = *(uint16_t *)src; \ + src += 2; \ + \ + r[x_write + c] = ((dat & 0x001f) << 3) | ((dat & 0x001f) >> 2); \ + g[x_write + c] = ((dat & 0x03e0) >> 2) | ((dat & 0x03e0) >> 7); \ + b[x_write + c] = ((dat & 0x7c00) >> 7) | ((dat & 0x7c00) >> 12); \ + } \ + x_write = (x_write + 4) & 7; \ + } while (0) + +#define DECODE_RGB565() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 4; c++) \ + { \ + uint16_t dat; \ + \ + dat = *(uint16_t *)src; \ + src += 2; \ + \ + r[x_write + c] = ((dat & 0x001f) << 3) | ((dat & 0x001f) >> 2); \ + g[x_write + c] = ((dat & 0x07e0) >> 3) | ((dat & 0x07e0) >> 9); \ + b[x_write + c] = ((dat & 0xf800) >> 8) | ((dat & 0xf800) >> 13); \ + } \ + x_write = (x_write + 4) & 7; \ + } while (0) + +#define DECODE_RGB888() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 4; c++) \ + { \ + r[x_write + c] = src[0]; \ + g[x_write + c] = src[1]; \ + b[x_write + c] = src[2]; \ + src += 3; \ + } \ + x_write = (x_write + 4) & 7; \ + } while (0) + +#define DECODE_XRGB8888() \ + do \ + { \ + int c; \ + \ + for (c = 0; c < 4; c++) \ + { \ + r[x_write + c] = src[0]; \ + g[x_write + c] = src[1]; \ + b[x_write + c] = src[2]; \ + src += 4; \ + } \ + x_write = (x_write + 4) & 7; \ + } while (0) + +#define OVERLAY_SAMPLE() \ + do \ + { \ + switch (virge->streams.sdif) \ + { \ + case 1: \ + DECODE_YCbCr(); \ + break; \ + case 2: \ + DECODE_YUV422(); \ + break; \ + case 3: \ + DECODE_RGB555(); \ + break; \ + case 4: \ + DECODE_YUV211(); \ + break; \ + case 5: \ + DECODE_RGB565(); \ + break; \ + case 6: \ + DECODE_RGB888(); \ + break; \ + case 7: \ + default: \ + DECODE_XRGB8888(); \ + break; \ + } \ + } while (0) + +static void s3_virge_overlay_draw(svga_t *svga, int displine) +{ + virge_t *virge = (virge_t *)svga->p; + int offset = (virge->streams.sec_x - virge->streams.pri_x) + 1; + int h_acc = virge->streams.dda_horiz_accumulator; + int r[8], g[8], b[8]; + int r_samp[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + int g_samp[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + int b_samp[8] = {0, 0, 0, 0, 0, 0, 0, 0}; + int x_size, x_read = 4, x_write = 4; + int x; + uint32_t *p; + uint8_t *src = &svga->vram[svga->overlay_latch.addr]; + int y_add = enable_overscan ? 16 : 0; + int x_add = enable_overscan ? 8 : 0; + + p = &((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add]; + + if ((offset + virge->streams.sec_w) > virge->streams.pri_w) + x_size = (virge->streams.pri_w - virge->streams.sec_x) + 1; + else + x_size = virge->streams.sec_w + 1; + + OVERLAY_SAMPLE(); + + for (x = 0; x < x_size; x++) + { + *p++ = r[x_read] | (g[x_read] << 8) | (b[x_read] << 16); + + h_acc += virge->streams.k1_horiz_scale; + if (h_acc >= 0) + { + if ((x_read ^ (x_read + 1)) & ~3) + OVERLAY_SAMPLE(); + x_read = (x_read + 1) & 7; + + h_acc += (virge->streams.k2_horiz_scale - virge->streams.k1_horiz_scale); + } + } + + svga->overlay_latch.v_acc += virge->streams.k1_vert_scale; + if (svga->overlay_latch.v_acc >= 0) + { + svga->overlay_latch.v_acc += (virge->streams.k2_vert_scale - virge->streams.k1_vert_scale); + svga->overlay_latch.addr += virge->streams.sec_stride; + } +} + +static uint8_t s3_virge_pci_read(int func, int addr, void *p) +{ + virge_t *virge = (virge_t *)p; + svga_t *svga = &virge->svga; + uint8_t ret = 0; +// pclog("S3 PCI read %08X ", addr); + switch (addr) + { + case 0x00: ret = 0x33; break; /*'S3'*/ + case 0x01: ret = 0x53; break; + + case 0x02: ret = virge->virge_id_low; break; + case 0x03: ret = virge->virge_id_high; break; + + case 0x04: ret = virge->pci_regs[0x04] & 0x27; break; + + case 0x07: ret = virge->pci_regs[0x07] & 0x36; break; + + case 0x08: ret = 0; break; /*Revision ID*/ + case 0x09: ret = 0; break; /*Programming interface*/ + + case 0x0a: ret = 0x00; break; /*Supports VGA interface*/ + case 0x0b: ret = 0x03; /*output = 3; */break; + + case 0x0d: ret = virge->pci_regs[0x0d] & 0xf8; break; + + case 0x10: ret = 0x00; break;/*Linear frame buffer address*/ + case 0x11: ret = 0x00; break; + case 0x12: ret = 0x00; break; + case 0x13: ret = svga->crtc[0x59] & 0xfc; break; + + case 0x30: ret = virge->pci_regs[0x30] & 0x01; break; /*BIOS ROM address*/ + case 0x31: ret = 0x00; break; + case 0x32: ret = virge->pci_regs[0x32]; break; + case 0x33: ret = virge->pci_regs[0x33]; break; + + case 0x3c: ret = virge->pci_regs[0x3c]; break; + + case 0x3d: ret = 0x01; break; /*INTA*/ + + case 0x3e: ret = 0x04; break; + case 0x3f: ret = 0xff; break; + + } +// pclog("%02X\n", ret); + return ret; +} + +static void s3_virge_pci_write(int func, int addr, uint8_t val, void *p) +{ + virge_t *virge = (virge_t *)p; + svga_t *svga = &virge->svga; +// pclog("S3 PCI write %08X %02X %04X:%08X\n", addr, val, CS, pc); + switch (addr) + { + case 0x00: case 0x01: case 0x02: case 0x03: + case 0x08: case 0x09: case 0x0a: case 0x0b: + case 0x3d: case 0x3e: case 0x3f: + return; + + case PCI_REG_COMMAND: + if (romset == ROM_KN97) return; + if (val & PCI_COMMAND_IO) + { + io_removehandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge); + io_sethandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge); + } + else + io_removehandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge); + virge->pci_regs[PCI_REG_COMMAND] = val & 0x27; + s3_virge_updatemapping(virge); + return; + case 0x07: + virge->pci_regs[0x07] = val & 0x3e; + return; + case 0x0d: + virge->pci_regs[0x0d] = val & 0xf8; + return; + + case 0x13: + svga->crtc[0x59] = val & 0xfc; + s3_virge_updatemapping(virge); + return; + + case 0x30: case 0x32: case 0x33: + virge->pci_regs[addr] = val; + if (virge->pci_regs[0x30] & 0x01) + { + uint32_t addr = (virge->pci_regs[0x32] << 16) | (virge->pci_regs[0x33] << 24); +// pclog("Virge bios_rom enabled at %08x\n", addr); + mem_mapping_set_addr(&virge->bios_rom.mapping, addr, 0x8000); + mem_mapping_enable(&virge->bios_rom.mapping); + } + else + { +// pclog("Virge bios_rom disabled\n"); + mem_mapping_disable(&virge->bios_rom.mapping); + } + return; + case 0x3c: + virge->pci_regs[0x3c] = val; + return; + } +} + +static void *s3_virge_init() +{ + virge_t *virge = malloc(sizeof(virge_t)); + memset(virge, 0, sizeof(virge_t)); + + virge->bilinear_enabled = device_get_config_int("bilinear"); + virge->dithering_enabled = device_get_config_int("dithering"); + virge->memory_size = device_get_config_int("memory"); + + svga_init(&virge->svga, virge, virge->memory_size << 20, + s3_virge_recalctimings, + s3_virge_in, s3_virge_out, + s3_virge_hwcursor_draw, + s3_virge_overlay_draw); + + rom_init(&virge->bios_rom, "roms/s3virge.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + if (PCI) + mem_mapping_disable(&virge->bios_rom.mapping); + + mem_mapping_add(&virge->mmio_mapping, 0, 0, s3_virge_mmio_read, + s3_virge_mmio_read_w, + s3_virge_mmio_read_l, + s3_virge_mmio_write, + s3_virge_mmio_write_w, + s3_virge_mmio_write_l, + NULL, + 0, + virge); + mem_mapping_add(&virge->new_mmio_mapping, 0, 0, s3_virge_mmio_read, + s3_virge_mmio_read_w, + s3_virge_mmio_read_l, + s3_virge_mmio_write, + s3_virge_mmio_write_w, + s3_virge_mmio_write_l, + NULL, + 0, + virge); + mem_mapping_add(&virge->linear_mapping, 0, 0, svga_read_linear, + svga_readw_linear, + svga_readl_linear, + svga_write_linear, + svga_writew_linear, + svga_writel_linear, + NULL, + 0, + &virge->svga); + + io_sethandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge); + + virge->pci_regs[4] = 3; + virge->pci_regs[5] = 0; + virge->pci_regs[6] = 0; + virge->pci_regs[7] = 2; + virge->pci_regs[0x32] = 0x0c; + virge->pci_regs[0x3d] = 1; + virge->pci_regs[0x3e] = 4; + virge->pci_regs[0x3f] = 0xff; + + virge->virge_id_high = 0x56; + virge->virge_id_low = 0x31; + virge->virge_rev = 0; + virge->virge_id = 0xe1; + + switch (virge->memory_size) + { + case 2: + virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (4 << 5); + break; + case 4: + default: + virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (0 << 5); + break; + } + + virge->svga.crtc[0x37] = 1;// | (7 << 5); + virge->svga.crtc[0x53] = 1 << 3; + virge->svga.crtc[0x59] = 0x70; + + virge->is_375 = 0; + + pci_add(s3_virge_pci_read, s3_virge_pci_write, virge); + + virge->wake_render_thread = thread_create_event(); + virge->wake_main_thread = thread_create_event(); + virge->not_full_event = thread_create_event(); + virge->render_thread = thread_create(render_thread, virge); + + virge->wake_fifo_thread = thread_create_event(); + virge->fifo_not_full_event = thread_create_event(); + virge->fifo_thread = thread_create(fifo_thread, virge); + + return virge; +} + +static void *s3_virge_375_init() +{ + virge_t *virge = malloc(sizeof(virge_t)); + memset(virge, 0, sizeof(virge_t)); + + virge->bilinear_enabled = device_get_config_int("bilinear"); + virge->dithering_enabled = device_get_config_int("dithering"); + virge->memory_size = device_get_config_int("memory"); + + svga_init(&virge->svga, virge, virge->memory_size << 20, + s3_virge_recalctimings, + s3_virge_in, s3_virge_out, + s3_virge_hwcursor_draw, + s3_virge_overlay_draw); + + rom_init(&virge->bios_rom, "roms/86c375_1.bin", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + if (PCI) + mem_mapping_disable(&virge->bios_rom.mapping); + + mem_mapping_add(&virge->mmio_mapping, 0, 0, s3_virge_mmio_read, + s3_virge_mmio_read_w, + s3_virge_mmio_read_l, + s3_virge_mmio_write, + s3_virge_mmio_write_w, + s3_virge_mmio_write_l, + NULL, + 0, + virge); + mem_mapping_add(&virge->new_mmio_mapping, 0, 0, s3_virge_mmio_read, + s3_virge_mmio_read_w, + s3_virge_mmio_read_l, + s3_virge_mmio_write, + s3_virge_mmio_write_w, + s3_virge_mmio_write_l, + NULL, + 0, + virge); + mem_mapping_add(&virge->linear_mapping, 0, 0, svga_read_linear, + svga_readw_linear, + svga_readl_linear, + svga_write_linear, + svga_writew_linear, + svga_writel_linear, + NULL, + 0, + &virge->svga); + + io_sethandler(0x03c0, 0x0020, s3_virge_in, NULL, NULL, s3_virge_out, NULL, NULL, virge); + + virge->pci_regs[4] = 3; + virge->pci_regs[5] = 0; + virge->pci_regs[6] = 0; + virge->pci_regs[7] = 2; + virge->pci_regs[0x32] = 0x0c; + virge->pci_regs[0x3d] = 1; + virge->pci_regs[0x3e] = 4; + virge->pci_regs[0x3f] = 0xff; + + virge->virge_id_high = 0x8a; + virge->virge_id_low = 0x01; + virge->virge_rev = 0; + virge->virge_id = 0xe1; + + switch (virge->memory_size) + { + case 2: + virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (4 << 5); + break; + case 4: + default: + virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4) | (0 << 5); + break; + } +// virge->svga.crtc[0x36] = 2 | (0 << 2) | (1 << 4); + virge->svga.crtc[0x37] = 1;// | (7 << 5); + virge->svga.crtc[0x53] = 1 << 3; + virge->svga.crtc[0x59] = 0x70; + + virge->svga.crtc[0x6c] = 0x01; + + virge->is_375 = 1; + + pci_add(s3_virge_pci_read, s3_virge_pci_write, virge); + + virge->wake_render_thread = thread_create_event(); + virge->wake_main_thread = thread_create_event(); + virge->not_full_event = thread_create_event(); + virge->render_thread = thread_create(render_thread, virge); + + virge->wake_fifo_thread = thread_create_event(); + virge->fifo_not_full_event = thread_create_event(); + virge->fifo_thread = thread_create(fifo_thread, virge); + + return virge; +} + +static void s3_virge_close(void *p) +{ + virge_t *virge = (virge_t *)p; +#ifndef RELEASE_BUILD + FILE *f = fopen("vram.dmp", "wb"); + fwrite(virge->svga.vram, 4 << 20, 1, f); + fclose(f); +#endif + + thread_kill(virge->render_thread); + thread_destroy_event(virge->not_full_event); + thread_destroy_event(virge->wake_main_thread); + thread_destroy_event(virge->wake_render_thread); + + svga_close(&virge->svga); + + free(virge); +} + +static int s3_virge_available() +{ + return rom_present("roms/s3virge.bin"); +} + +static int s3_virge_375_available() +{ + return rom_present("roms/86c375_1.bin"); +} + +static void s3_virge_speed_changed(void *p) +{ + virge_t *virge = (virge_t *)p; + + svga_recalctimings(&virge->svga); +} + +static void s3_virge_force_redraw(void *p) +{ + virge_t *virge = (virge_t *)p; + + virge->svga.fullchange = changeframecount; +} + +static void s3_virge_add_status_info(char *s, int max_len, void *p) +{ + virge_t *virge = (virge_t *)p; + char temps[256]; + uint64_t new_time = timer_read(); + uint64_t status_diff = new_time - status_time; + status_time = new_time; + + if (!status_diff) + status_diff = 1; + + svga_add_status_info(s, max_len, &virge->svga); + sprintf(temps, "%f Mpixels/sec\n%f ktris/sec\n%f%% CPU\n%f%% CPU (real)\n%d writes %i reads\n\n", (double)virge->pixel_count/1000000.0, (double)virge->tri_count/1000.0, ((double)virge_time * 100.0) / timer_freq, ((double)virge_time * 100.0) / status_diff, reg_writes, reg_reads); + strncat(s, temps, max_len); + + virge->pixel_count = virge->tri_count = 0; + virge_time = 0; + reg_reads = 0; + reg_writes = 0; +} + +static device_config_t s3_virge_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } + }, + .default_int = 4 + }, + { + .name = "bilinear", + .description = "Bilinear filtering", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .name = "dithering", + .description = "Dithering", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .type = -1 + } +}; + +device_t s3_virge_device = +{ + "Diamond Stealth 3D 2000 (S3 ViRGE)", + 0, + s3_virge_init, + s3_virge_close, + s3_virge_available, + s3_virge_speed_changed, + s3_virge_force_redraw, + s3_virge_add_status_info, + s3_virge_config +}; + +device_t s3_virge_375_device = +{ + "S3 ViRGE/DX", + 0, + s3_virge_375_init, + s3_virge_close, + s3_virge_375_available, + s3_virge_speed_changed, + s3_virge_force_redraw, + s3_virge_add_status_info, + s3_virge_config +}; diff --git a/src/vid_s3_virge.h b/src/vid_s3_virge.h new file mode 100644 index 000000000..dce1a2495 --- /dev/null +++ b/src/vid_s3_virge.h @@ -0,0 +1,2 @@ +extern device_t s3_virge_device; +extern device_t s3_virge_375_device; diff --git a/src/vid_sdac_ramdac.c b/src/vid_sdac_ramdac.c new file mode 100644 index 000000000..2094f356d --- /dev/null +++ b/src/vid_sdac_ramdac.c @@ -0,0 +1,169 @@ +/*87C716 'SDAC' true colour RAMDAC emulation*/ +/*Misidentifies as AT&T 21C504*/ +#include "ibm.h" +#include "mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_sdac_ramdac.h" + +void sdac_ramdac_out(uint16_t addr, uint8_t val, sdac_ramdac_t *ramdac, svga_t *svga) +{ +// /*if (CS!=0xC000) */pclog("OUT RAMDAC %04X %02X %i %04X:%04X %i\n",addr,val,sdac_ramdac.magic_count,CS,pc, sdac_ramdac.rs2); + switch (addr) + { + case 0x3C6: + if (val == 0xff) + { + ramdac->rs2 = 0; + ramdac->magic_count = 0; + break; + } + if (ramdac->magic_count < 4) break; + if (ramdac->magic_count == 4) + { + ramdac->command = val; +// pclog("RAMDAC command reg now %02X\n", val); + // 0, 1 = 15 bpp + if (gfxcard == GFX_ET4000W32C) + { + if (ramdac->command & 8) + { + switch (ramdac->regs[3]) + { + case 0: case 5: case 7: svga->bpp = 8; break; + case 1: case 2: case 8: svga->bpp = 15; break; + case 3: case 6: svga->bpp = 16; break; + case 4: case 9: svga->bpp = 24; break; + default: svga->bpp = 8; break; + } + } + else + { + switch (ramdac->command >> 5) + { + case 0: svga->bpp = 8; break; + case 5: svga->bpp = 15; break; + case 6: svga->bpp = 16; break; + case 7: svga->bpp = 24; break; + default: svga->bpp = 8; break; + } + } + } + else + { + switch (val >> 4) + { + case 0x2: case 0x3: case 0xa: svga->bpp = 15; break; + case 0x4: case 0xe: svga->bpp = 24; break; + case 0x5: case 0x6: case 0xc: svga->bpp = 16; break; + case 0x7: svga->bpp = 32; break; + + case 0: case 1: default: svga->bpp = 8; break; + } + } + pclog("SDAC: Value %02X/%02X set to %i bpp\n", val >> 4, val, svga->bpp); + } + //ramdac->magic_count = 0; + break; + + case 0x3C7: + ramdac->magic_count = 0; + if (ramdac->rs2) + ramdac->rindex = val; + break; + case 0x3C8: + ramdac->magic_count = 0; + if (ramdac->rs2) + ramdac->windex = val; + break; + case 0x3C9: + ramdac->magic_count = 0; + if (ramdac->rs2) + { + if (!ramdac->reg_ff) ramdac->regs[ramdac->windex] = (ramdac->regs[ramdac->windex] & 0xff00) | val; + else ramdac->regs[ramdac->windex] = (ramdac->regs[ramdac->windex] & 0x00ff) | (val << 8); + ramdac->reg_ff = !ramdac->reg_ff; +// pclog("RAMDAC reg %02X now %04X\n", ramdac->windex, ramdac->regs[ramdac->windex]); + if (!ramdac->reg_ff) ramdac->windex++; + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t sdac_ramdac_in(uint16_t addr, sdac_ramdac_t *ramdac, svga_t *svga) +{ + uint8_t temp; +// /*if (CS!=0xC000) */pclog("IN RAMDAC %04X %04X:%04X %i\n",addr,CS,pc, ramdac->rs2); + switch (addr) + { + case 0x3C6: + ramdac->reg_ff = 0; + if (ramdac->magic_count < 5) + ramdac->magic_count++; + if (ramdac->magic_count == 4) + { + temp = 0x70; /*SDAC ID*/ + ramdac->rs2 = 1; + } + if (ramdac->magic_count == 5) + { + temp = ramdac->command; + ramdac->magic_count = 0; + } + return temp; + case 0x3C7: +// if (ramdac->magic_count < 4) +// { + ramdac->magic_count=0; +// break; +// } + if (ramdac->rs2) return ramdac->rindex; + break; + case 0x3C8: +// if (ramdac->magic_count < 4) +// { + ramdac->magic_count=0; +// break; +// } + if (ramdac->rs2) return ramdac->windex; + break; + case 0x3C9: +// if (ramdac->magic_count < 4) +// { + ramdac->magic_count=0; +// break; +// } + if (ramdac->rs2) + { + if (!ramdac->reg_ff) temp = ramdac->regs[ramdac->rindex] & 0xff; + else temp = ramdac->regs[ramdac->rindex] >> 8; + ramdac->reg_ff = !ramdac->reg_ff; + if (!ramdac->reg_ff) + { + ramdac->rindex++; + ramdac->magic_count = 0; + } + return temp; + } + break; + } + return svga_in(addr, svga); +} + +float sdac_getclock(int clock, void *p) +{ + sdac_ramdac_t *ramdac = (sdac_ramdac_t *)p; + float t; + int m, n1, n2; +// pclog("SDAC_Getclock %i %04X\n", clock, ramdac->regs[clock]); + if (clock == 0) return 25175000.0; + if (clock == 1) return 28322000.0; + clock ^= 1; /*Clocks 2 and 3 seem to be reversed*/ + m = (ramdac->regs[clock] & 0x7f) + 2; + n1 = ((ramdac->regs[clock] >> 8) & 0x1f) + 2; + n2 = ((ramdac->regs[clock] >> 13) & 0x07); + t = (14318184.0 * ((float)m / (float)n1)) / (float)(1 << n2); +// pclog("SDAC clock %i %i %i %f %04X %f %i\n", m, n1, n2, t, ramdac->regs[2], 14318184.0 * ((float)m / (float)n1), 1 << n2); + return t; +} diff --git a/src/vid_sdac_ramdac.h b/src/vid_sdac_ramdac.h new file mode 100644 index 000000000..3aaf78730 --- /dev/null +++ b/src/vid_sdac_ramdac.h @@ -0,0 +1,14 @@ +typedef struct sdac_ramdac_t +{ + int magic_count; + uint8_t command; + int windex, rindex; + uint16_t regs[256]; + int reg_ff; + int rs2; +} sdac_ramdac_t; + +void sdac_ramdac_out(uint16_t addr, uint8_t val, sdac_ramdac_t *ramdac, svga_t *svga); +uint8_t sdac_ramdac_in(uint16_t addr, sdac_ramdac_t *ramdac, svga_t *svga); + +float sdac_getclock(int clock, void *p); diff --git a/src/vid_stg_ramdac.c b/src/vid_stg_ramdac.c new file mode 100644 index 000000000..6e361d670 --- /dev/null +++ b/src/vid_stg_ramdac.c @@ -0,0 +1,137 @@ +/*STG1702 true colour RAMDAC emulation*/ +#include "ibm.h" +#include "mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_stg_ramdac.h" + +static int stg_state_read[2][8] = {{1,2,3,4,0,0,0,0}, {1,2,3,4,5,6,7,7}}; +static int stg_state_write[8] = {0,0,0,0,0,6,7,7}; + +void stg_ramdac_out(uint16_t addr, uint8_t val, stg_ramdac_t *ramdac, svga_t *svga) +{ + int didwrite; + //if (CS!=0xC000) pclog("OUT RAMDAC %04X %02X %i %04X:%04X\n",addr,val,stg_ramdac.magic_count,CS,pc); + switch (addr) + { + case 0x3c6: + switch (ramdac->magic_count) + { + case 0: case 1: case 2: case 3: + break; + case 4: + ramdac->command = val; + /*pclog("Write RAMDAC command %02X\n",val);*/ + break; + case 5: + ramdac->index = (ramdac->index & 0xff00) | val; + break; + case 6: + ramdac->index = (ramdac->index & 0xff) | (val << 8); + break; + case 7: +#ifndef RELEASE_BUILD + pclog("Write RAMDAC reg %02X %02X\n", ramdac->index, val); +#endif + if (ramdac->index < 0x100) + ramdac->regs[ramdac->index] = val; + ramdac->index++; + break; + } + didwrite = (ramdac->magic_count >= 4); + ramdac->magic_count = stg_state_write[ramdac->magic_count & 7]; + if (ramdac->command & 8) + { + switch (ramdac->regs[3]) + { + case 0: case 5: case 7: svga->bpp = 8; break; + case 1: case 2: case 8: svga->bpp = 15; break; + case 3: case 6: svga->bpp = 16; break; + case 4: case 9: svga->bpp = 24; break; + default: svga->bpp = 8; break; + } + } + else + { + switch (ramdac->command >> 5) + { + case 0: svga->bpp = 8; break; + case 5: svga->bpp = 15; break; + case 6: svga->bpp = 16; break; + case 7: svga->bpp = 24; break; + default: svga->bpp = 8; break; + } + } + if (didwrite) return; + break; + case 0x3c7: case 0x3c8: case 0x3c9: + ramdac->magic_count=0; + break; + } + svga_out(addr, val, svga); +} + +uint8_t stg_ramdac_in(uint16_t addr, stg_ramdac_t *ramdac, svga_t *svga) +{ + uint8_t temp; + //if (CS!=0xC000) pclog("IN RAMDAC %04X %04X:%04X\n",addr,CS,pc); + switch (addr) + { + case 0x3c6: + switch (ramdac->magic_count) + { + case 0: case 1: case 2: case 3: + temp = 0xff; + break; + case 4: + temp = ramdac->command; + break; + case 5: + temp = ramdac->index & 0xff; + break; + case 6: + temp = ramdac->index >> 8; + break; + case 7: +// pclog("Read RAMDAC index %04X\n",stg_ramdac.index); + switch (ramdac->index) + { + case 0: + temp = 0x44; + break; + case 1: + temp = 0x02; + break; + default: + if (ramdac->index < 0x100) temp = ramdac->regs[ramdac->index]; + else temp = 0xff; + break; + } + ramdac->index++; + break; + } + ramdac->magic_count = stg_state_read[(ramdac->command & 0x10) ? 1 : 0][ramdac->magic_count & 7]; + return temp; + case 0x3c8: case 0x3c9: + ramdac->magic_count=0; + break; + } + return svga_in(addr, svga); +} + +float stg_getclock(int clock, void *p) +{ + stg_ramdac_t *ramdac = (stg_ramdac_t *)p; + float t; + int m, n1, n2; +// pclog("STG_Getclock %i %04X\n", clock, ramdac->regs[clock]); + if (clock == 0) return 25175000.0; + if (clock == 1) return 28322000.0; + clock ^= 1; /*Clocks 2 and 3 seem to be reversed*/ + m = (ramdac->regs[clock] & 0x7f) + 2; + n1 = ((ramdac->regs[clock] >> 8) & 0x1f) + 2; + n2 = ((ramdac->regs[clock] >> 13) & 0x07); + t = (14318184.0 * ((float)m / (float)n1)) / (float)(1 << n2); +// pclog("STG clock %i %i %i %f %04X %f %i\n", m, n1, n2, t, ramdac->regs[2], 14318184.0 * ((float)m / (float)n1), 1 << n2); + return t; +} diff --git a/src/vid_stg_ramdac.h b/src/vid_stg_ramdac.h new file mode 100644 index 000000000..2402e46cc --- /dev/null +++ b/src/vid_stg_ramdac.h @@ -0,0 +1,11 @@ +typedef struct stg_ramdac_t +{ + int magic_count; + uint8_t command; + int index; + uint8_t regs[256]; +} stg_ramdac_t; + +void stg_ramdac_out(uint16_t addr, uint8_t val, stg_ramdac_t *ramdac, svga_t *svga); +uint8_t stg_ramdac_in(uint16_t addr, stg_ramdac_t *ramdac, svga_t *svga); +float stg_getclock(int clock, void *p); diff --git a/src/vid_svga.c b/src/vid_svga.c new file mode 100644 index 000000000..b276d44bc --- /dev/null +++ b/src/vid_svga.c @@ -0,0 +1,1634 @@ +/*Generic SVGA handling*/ +/*This is intended to be used by another SVGA driver, and not as a card in it's own right*/ +#include +#include "ibm.h" +#include "mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "io.h" +#include "timer.h" + +#define svga_output 0 + +void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga); + +extern uint8_t edatlookup[4][4]; + +uint8_t svga_rotate[8][256]; + +static uint8_t mask_gdc[9] = {0x0F, 0x0F, 0x0F, 0x1F, 0x03, 0x7B, 0x0F, 0x0F, 0xFF}; +uint8_t mask_crtc[0x19] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0x3F, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xCF, 0xFF, 0xFF, 0x7F, 0xFF, 0x7F, 0xEF, 0xFF}; +static uint8_t mask_seq[5] = {0x03, 0x3D, 0x0F, 0x3F, 0x0E}; + +/*Primary SVGA device. As multiple video cards are not yet supported this is the + only SVGA device.*/ +static svga_t *svga_pri; + +static int old_overscan_color = 0; + +static int sense_switches = 0xE; + +svga_t *svga_get_pri() +{ + return svga_pri; +} +void svga_set_override(svga_t *svga, int val) +{ + if (svga->override && !val) + svga->fullchange = changeframecount; + svga->override = val; +} + +void svga_out(uint16_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + int c; + uint8_t o; +// printf("OUT SVGA %03X %02X %04X:%04X\n",addr,val,CS,pc); + switch (addr) + { + case 0x3C0: + if (!svga->attrff) + { + svga->attraddr = val & 31; + if ((val & 0x20) != svga->attr_palette_enable) + { + svga->fullchange = 3; + svga->attr_palette_enable = val & 0x20; + svga_recalctimings(svga); + } + } + else + { + o = svga->attrregs[svga->attraddr & 31]; + svga->attrregs[svga->attraddr & 31] = val; + if (svga->attraddr < 16) + svga->fullchange = changeframecount; + if (svga->attraddr == 0x10 || svga->attraddr == 0x14 || svga->attraddr < 0x10) + { + for (c = 0; c < 16; c++) + { + /* Proper handling of this, per spec. */ + if (svga->attrregs[0x10] & 0x80) svga->egapal[c] = (svga->attrregs[c] & 0xf) | ((svga->attrregs[0x14] & 3) << 4); + else svga->egapal[c] = (svga->attrregs[c] & 0x3f); + + // if (svga->attrregs[0x10] & 0x40) svga->egapal[c] |= ((svga->attrregs[0x14] & 0x0c) << 4); + /* It seems these should always be enabled. */ + svga->egapal[c] |= ((svga->attrregs[0x14] & 0x0c) << 4); + } + } + /* Recalculate timings on change of attribute register 0x11 (overscan border color) too. */ + if ((svga->attraddr == 0x10) || (svga->attraddr == 0x11)) + { + if (o != val) svga_recalctimings(svga); + } + if (svga->attraddr == 0x12) + { + if ((val & 0xf) != svga->plane_mask) + svga->fullchange = changeframecount; + svga->plane_mask = val & 0xf; + } + } + svga->attrff ^= 1; + break; + case 0x3C2: + svga->miscout = val; + svga->enablevram = (val & 2) ? 1 : 0; + svga->oddeven_page = (val & 0x20) ? 0 : 1; + svga->vidclock = val & 4;// printf("3C2 write %02X\n",val); + if (val & 1) + { +// pclog("Remove mono handler\n"); + io_removehandler(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->p); + } + else + { +// pclog("Set mono handler\n"); + io_sethandler(0x03a0, 0x0020, svga->video_in, NULL, NULL, svga->video_out, NULL, NULL, svga->p); + } + svga_recalctimings(svga); + break; + case 0x3C4: + svga->seqaddr = val; + break; + case 0x3C5: + if (svga->seqaddr > 0xf) return; + o = svga->seqregs[svga->seqaddr & 0xf]; + /* Sanitize value for the first 5 sequencer registers. */ + if ((svga->seqaddr & 0xf) <= 4) + val &= mask_seq[svga->seqaddr & 0xf]; + svga->seqregs[svga->seqaddr & 0xf] = val; + if (o != val && (svga->seqaddr & 0xf) == 1) + svga_recalctimings(svga); + switch (svga->seqaddr & 0xf) + { + case 1: + if (svga->scrblank && !(val & 0x20)) + svga->fullchange = 3; + svga->scrblank = (svga->scrblank & ~0x20) | (val & 0x20); + svga_recalctimings(svga); + break; + case 2: + svga->writemask = val & 0xf; + break; + case 3: + svga->charsetb = (((val >> 2) & 3) * 0x10000) + 2; + svga->charseta = ((val & 3) * 0x10000) + 2; + if (val & 0x10) + svga->charseta += 0x8000; + if (val & 0x20) + svga->charsetb += 0x8000; + break; + case 4: + svga->chain2_write = !(val & 4); + svga->chain4 = val & 8; + svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) && svga->chain4; + svga->extvram = (val & 2) ? 1 : 0; + break; + } + break; + case 0x3c6: + svga->dac_mask = val; + break; + case 0x3C7: + svga->dac_read = val; + svga->dac_pos = 0; + break; + case 0x3C8: + svga->dac_write = val; + svga->dac_pos = 0; + break; + case 0x3C9: + svga->dac_status = 0; + svga->fullchange = changeframecount; + switch (svga->dac_pos) + { + case 0: + svga->dac_r = val; + svga->dac_pos++; + break; + case 1: + svga->dac_g = val; + svga->dac_pos++; + break; + case 2: + svga->vgapal[svga->dac_write].r = svga->dac_r; + svga->vgapal[svga->dac_write].g = svga->dac_g; + svga->vgapal[svga->dac_write].b = val; + if (svga->ramdac_type == RAMDAC_8BIT) + svga->pallook[svga->dac_write] = makecol32(svga->vgapal[svga->dac_write].r, svga->vgapal[svga->dac_write].g, svga->vgapal[svga->dac_write].b); + else + svga->pallook[svga->dac_write] = makecol32((svga->vgapal[svga->dac_write].r & 0x3f) * 4, (svga->vgapal[svga->dac_write].g & 0x3f) * 4, (svga->vgapal[svga->dac_write].b & 0x3f) * 4); + svga->dac_pos = 0; + svga->dac_write = (svga->dac_write + 1) & 255; + break; + } + break; + case 0x3CE: + svga->gdcaddr = val; + break; + case 0x3CF: + /* Sanitize the first 9 GDC registers. */ + if ((svga->gdcaddr & 15) <= 8) + val &= mask_gdc[svga->gdcaddr & 15]; + o = svga->gdcreg[svga->gdcaddr & 15]; + switch (svga->gdcaddr & 15) + { + case 2: svga->colourcompare=val; break; + case 4: svga->readplane=val&3; break; + case 5: + svga->writemode = val & 3; + svga->readmode = val & 8; + svga->chain2_read = val & 0x10; + break; + case 6: +// pclog("svga_out recalcmapping %p\n", svga); + if ((svga->gdcreg[6] & 0xc) != (val & 0xc)) + { +// pclog("Write mapping %02X\n", val); + switch (val&0xC) + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0x1ffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + } + break; + case 7: svga->colournocare=val; break; + } + svga->gdcreg[svga->gdcaddr & 15] = val; + svga->fast = (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) && svga->chain4; + if (((svga->gdcaddr & 15) == 5 && (val ^ o) & 0x70) || ((svga->gdcaddr & 15) == 6 && (val ^ o) & 1)) + svga_recalctimings(svga); + break; + } +} + +uint8_t svga_in(uint16_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + uint8_t temp; +// if (addr!=0x3da) pclog("Read port %04X\n",addr); + switch (addr) + { + case 0x3C0: + return svga->attraddr | svga->attr_palette_enable; + case 0x3C1: + return svga->attrregs[svga->attraddr]; + case 0x3c2: +#if 0 + if ((svga->vgapal[0].r + svga->vgapal[0].g + svga->vgapal[0].b) >= 0x50) + temp = 0; + else + temp = 0x10; +#endif + temp = sense_switches & (1 << ((svga->miscout >> 2) & 3)); + return temp ? 0 : 0x10; + case 0x3C4: + return svga->seqaddr; + case 0x3C5: + return svga->seqregs[svga->seqaddr & 0xF]; + case 0x3c6: return svga->dac_mask; + case 0x3c7: return svga->dac_status; + case 0x3c8: return svga->dac_write; + case 0x3c9: + svga->dac_status = 3; + switch (svga->dac_pos) + { + case 0: + svga->dac_pos++; + return svga->vgapal[svga->dac_read].r; + case 1: + svga->dac_pos++; + return svga->vgapal[svga->dac_read].g; + case 2: + svga->dac_pos=0; + svga->dac_read = (svga->dac_read + 1) & 255; + return svga->vgapal[(svga->dac_read - 1) & 255].b; + } + break; + case 0x3CC: + return svga->miscout; + case 0x3CE: + return svga->gdcaddr; + case 0x3CF: + /* The spec says GDC addresses 0xF8 to 0xFB return the latch. */ + if (svga->gdcaddr == 0xF8) return svga->la; + if (svga->gdcaddr == 0xF9) return svga->lb; + if (svga->gdcaddr == 0xFA) return svga->lc; + if (svga->gdcaddr == 0xFB) return svga->ld; + return svga->gdcreg[svga->gdcaddr & 0xf]; + case 0x3DA: + svga->attrff = 0; + if (svga->cgastat & 0x01) + svga->cgastat &= ~0x30; + else + svga->cgastat ^= 0x30; + return svga->cgastat; + } +// printf("Bad EGA read %04X %04X:%04X\n",addr,cs>>4,pc); + return 0xFF; +} + +void svga_set_ramdac_type(svga_t *svga, int type) +{ + int c; + + if (svga->ramdac_type != type) + { + svga->ramdac_type = type; + + for (c = 0; c < 256; c++) + { + if (svga->ramdac_type == RAMDAC_8BIT) + svga->pallook[c] = makecol32(svga->vgapal[c].r, svga->vgapal[c].g, svga->vgapal[c].b); + else + svga->pallook[c] = makecol32((svga->vgapal[c].r & 0x3f) * 4, (svga->vgapal[c].g & 0x3f) * 4, (svga->vgapal[c].b & 0x3f) * 4); + } + } +} + +void svga_recalctimings(svga_t *svga) +{ + double crtcconst; + double _dispontime, _dispofftime, disptime; + int hdisp_old; + + svga->vtotal = svga->crtc[6]; + svga->dispend = svga->crtc[0x12]; + svga->vsyncstart = svga->crtc[0x10]; + svga->split = svga->crtc[0x18]; + svga->vblankstart = svga->crtc[0x15]; + + if (svga->crtc[7] & 1) svga->vtotal |= 0x100; + if (svga->crtc[7] & 32) svga->vtotal |= 0x200; + svga->vtotal += 2; + + if (svga->crtc[7] & 2) svga->dispend |= 0x100; + if (svga->crtc[7] & 64) svga->dispend |= 0x200; + svga->dispend++; + + if (svga->crtc[7] & 4) svga->vsyncstart |= 0x100; + if (svga->crtc[7] & 128) svga->vsyncstart |= 0x200; + svga->vsyncstart++; + + if (svga->crtc[7] & 0x10) svga->split|=0x100; + if (svga->crtc[9] & 0x40) svga->split|=0x200; + svga->split++; + + if (svga->crtc[7] & 0x08) svga->vblankstart |= 0x100; + if (svga->crtc[9] & 0x20) svga->vblankstart |= 0x200; + svga->vblankstart++; + + svga->hdisp = svga->crtc[1]; + svga->hdisp++; + + svga->htotal = svga->crtc[0]; + svga->htotal += 6; /*+6 is required for Tyrian*/ + + svga->rowoffset = svga->crtc[0x13]; + + svga->clock = (svga->vidclock) ? VGACONST2 : VGACONST1; + + svga->lowres = svga->attrregs[0x10] & 0x40; + + svga->interlace = 0; + + svga->ma_latch = (svga->crtc[0xc] << 8) | svga->crtc[0xd]; + + svga->hdisp_time = svga->hdisp; + svga->render = svga_render_blank; + if (!svga->scrblank && svga->attr_palette_enable) + { + if (!(svga->gdcreg[6] & 1)) /*Text mode*/ + { + if (svga->seqregs[1] & 8) /*40 column*/ + { + svga->render = svga_render_text_40; + svga->hdisp *= (svga->seqregs[1] & 1) ? 16 : 18; + } + else + { + svga->render = svga_render_text_80; + svga->hdisp *= (svga->seqregs[1] & 1) ? 8 : 9; + } + svga->hdisp_old = svga->hdisp; + } + else + { + svga->hdisp *= (svga->seqregs[1] & 8) ? 16 : 8; + svga->hdisp_old = svga->hdisp; + + switch (svga->gdcreg[5] & 0x60) + { + case 0x00: /*16 colours*/ + if (svga->seqregs[1] & 8) /*Low res (320)*/ + svga->render = svga_render_4bpp_lowres; + else + svga->render = svga_render_4bpp_highres; + break; + case 0x20: /*4 colours*/ + if (svga->seqregs[1] & 8) /*Low res (320)*/ + svga->render = svga_render_2bpp_lowres; + else + svga->render = svga_render_2bpp_highres; + break; + case 0x40: case 0x60: /*256+ colours*/ + switch (svga->bpp) + { + case 8: + if (svga->lowres) + svga->render = svga_render_8bpp_lowres; + else + svga->render = svga_render_8bpp_highres; + break; + case 15: + if (svga->lowres) + svga->render = svga_render_15bpp_lowres; + else + svga->render = svga_render_15bpp_highres; + break; + case 16: + if (svga->lowres) + svga->render = svga_render_16bpp_lowres; + else + svga->render = svga_render_16bpp_highres; + break; + case 24: + if (svga->lowres) + svga->render = svga_render_24bpp_lowres; + else + svga->render = svga_render_24bpp_highres; + break; + case 32: + if (svga->lowres) + svga->render = svga_render_32bpp_lowres; + else + svga->render = svga_render_32bpp_highres; + break; + } + break; + } + } + } + +// pclog("svga_render %08X : %08X %08X %08X %08X %08X %i %i %02X %i %i\n", svga_render, svga_render_text_40, svga_render_text_80, svga_render_8bpp_lowres, svga_render_8bpp_highres, svga_render_blank, scrblank,gdcreg[6]&1,gdcreg[5]&0x60,bpp,seqregs[1]&8); + + svga->linedbl = svga->crtc[9] & 0x80; + svga->rowcount = svga->crtc[9] & 31; + if (svga->recalctimings_ex) + svga->recalctimings_ex(svga); + + if (svga->vblankstart < svga->dispend) + svga->dispend = svga->vblankstart; + + crtcconst = (svga->seqregs[1] & 1) ? (svga->clock * 8.0) : (svga->clock * 9.0); + + disptime = svga->htotal; + _dispontime = svga->hdisp_time; + +// printf("Disptime %f dispontime %f hdisp %i\n",disptime,dispontime,crtc[1]*8); + if (svga->seqregs[1] & 8) { disptime *= 2; _dispontime *= 2; } + _dispofftime = disptime - _dispontime; + _dispontime *= crtcconst; + _dispofftime *= crtcconst; + + svga->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + svga->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +/* printf("SVGA horiz total %i display end %i vidclock %f\n",svga->crtc[0],svga->crtc[1],svga->clock); + printf("SVGA vert total %i display end %i max row %i vsync %i\n",svga->vtotal,svga->dispend,(svga->crtc[9]&31)+1,svga->vsyncstart); + printf("total %f on %i cycles off %i cycles frame %i sec %i %02X\n",disptime*crtcconst,svga->dispontime,svga->dispofftime,(svga->dispontime+svga->dispofftime)*svga->vtotal,(svga->dispontime+svga->dispofftime)*svga->vtotal*70,svga->seqregs[1]); + + pclog("svga->render %08X\n", svga->render);*/ +} + +extern int cyc_total; +void svga_poll(void *p) +{ + svga_t *svga = (svga_t *)p; + int x; + + if (!svga->linepos) + { +// if (!(vc & 15)) pclog("VC %i %i\n", vc, GetTickCount()); + if (svga->displine == svga->hwcursor_latch.y && svga->hwcursor_latch.ena) + { + svga->hwcursor_on = 64 - svga->hwcursor_latch.yoff; + svga->hwcursor_oddeven = 0; + } + + if (svga->displine == svga->hwcursor_latch.y+1 && svga->hwcursor_latch.ena && svga->interlace) + { + svga->hwcursor_on = 64 - svga->hwcursor_latch.yoff; + svga->hwcursor_oddeven = 1; + } + + if (svga->displine == svga->overlay_latch.y && svga->overlay_latch.ena) + { + svga->overlay_on = svga->overlay_latch.ysize - svga->overlay_latch.yoff; + svga->overlay_oddeven = 0; + } + if (svga->displine == svga->overlay_latch.y+1 && svga->overlay_latch.ena && svga->interlace) + { + svga->overlay_on = svga->overlay_latch.ysize - svga->overlay_latch.yoff; + svga->overlay_oddeven = 1; + } + + svga->vidtime += svga->dispofftime; +// if (output) printf("Display off %f\n",vidtime); + svga->cgastat |= 1; + svga->linepos = 1; + + if (svga->dispon) + { + svga->hdisp_on=1; + + svga->ma &= svga->vrammask; + if (svga->firstline == 2000) + svga->firstline = svga->displine; + + if (svga->hwcursor_on || svga->overlay_on) + svga->changedvram[svga->ma >> 12] = svga->changedvram[(svga->ma >> 12) + 1] = 2; + + if (!svga->override) + svga->render(svga); + + if (svga->overlay_on) + { + if (!svga->override) + svga->overlay_draw(svga, svga->displine); + svga->overlay_on--; + if (svga->overlay_on && svga->interlace) + svga->overlay_on--; + } + + if (svga->hwcursor_on) + { + if (!svga->override) + svga->hwcursor_draw(svga, svga->displine); + svga->hwcursor_on--; + if (svga->hwcursor_on && svga->interlace) + svga->hwcursor_on--; + } + + if (svga->lastline < svga->displine) + svga->lastline = svga->displine; + } + +// pclog("%03i %06X %06X\n",displine,ma,vrammask); + svga->displine++; + if (svga->interlace) + svga->displine++; + if ((svga->cgastat & 8) && ((svga->displine & 15) == (svga->crtc[0x11] & 15)) && svga->vslines) + { +// printf("Vsync off at line %i\n",displine); + svga->cgastat &= ~8; + } + svga->vslines++; + if (svga->displine > 1500) + svga->displine = 0; +// pclog("Col is %08X %08X %08X %i %i %08X\n",((uint32_t *)buffer32->line[displine])[320],((uint32_t *)buffer32->line[displine])[321],((uint32_t *)buffer32->line[displine])[322], +// displine, vc, ma); + } + else + { +// pclog("VC %i ma %05X\n", svga->vc, svga->ma); + svga->vidtime += svga->dispontime; + +// if (output) printf("Display on %f\n",vidtime); + if (svga->dispon) + svga->cgastat &= ~1; + svga->hdisp_on = 0; + + svga->linepos = 0; + if (svga->sc == (svga->crtc[11] & 31)) + svga->con = 0; + if (svga->dispon) + { + if (svga->linedbl && !svga->linecountff) + { + svga->linecountff = 1; + svga->ma = svga->maback; + } + else if (svga->sc == svga->rowcount) + { + svga->linecountff = 0; + svga->sc = 0; + + svga->maback += (svga->rowoffset << 3); + if (svga->interlace) + svga->maback += (svga->rowoffset << 3); + svga->maback &= svga->vrammask; + svga->ma = svga->maback; + } + else + { + svga->linecountff = 0; + svga->sc++; + svga->sc &= 31; + svga->ma = svga->maback; + } + } + svga->vc++; + svga->vc &= 2047; + + if (svga->vc == svga->split) + { +// pclog("VC split\n"); + svga->ma = svga->maback = 0; + if (svga->attrregs[0x10] & 0x20) + svga->scrollcache = 0; + } + if (svga->vc == svga->dispend) + { +// pclog("VC dispend\n"); + svga->dispon=0; + if (svga->crtc[10] & 0x20) svga->cursoron = 0; + else svga->cursoron = svga->blink & 16; + if (!(svga->gdcreg[6] & 1) && !(svga->blink & 15)) + svga->fullchange = 2; + svga->blink++; + + for (x = 0; x < (svga->vram_limit >> 12); x++) + { + if (svga->changedvram[x]) + svga->changedvram[x]--; + } +// memset(changedvram,0,2048); + if (svga->fullchange) + svga->fullchange--; + } + if (svga->vc == svga->vsyncstart) + { + int wx, wy; +// pclog("VC vsync %i %i\n", svga->firstline_draw, svga->lastline_draw); + svga->dispon=0; + svga->cgastat |= 8; + x = svga->hdisp; + + if (svga->interlace && !svga->oddeven) svga->lastline++; + if (svga->interlace && svga->oddeven) svga->firstline--; + + wx = x; + wy = svga->lastline - svga->firstline; + + if (!svga->override) + svga_doblit(svga->firstline_draw, svga->lastline_draw + 1, wx, wy, svga); + + readflash = 0; + + svga->firstline = 2000; + svga->lastline = 0; + + svga->firstline_draw = 2000; + svga->lastline_draw = 0; + + svga->oddeven ^= 1; + + changeframecount = svga->interlace ? 3 : 2; + svga->vslines = 0; + + if (svga->interlace && svga->oddeven) svga->ma = svga->maback = svga->ma_latch + (svga->rowoffset << 1); + else svga->ma = svga->maback = svga->ma_latch; + svga->ca = (svga->crtc[0xe] << 8) | svga->crtc[0xf]; + + svga->ma <<= 2; + svga->maback <<= 2; + svga->ca <<= 2; + + svga->video_res_x = wx; + svga->video_res_y = wy + 1; +// pclog("%i %i %i\n", svga->video_res_x, svga->video_res_y, svga->lowres); + if (!(svga->gdcreg[6] & 1)) /*Text mode*/ + { + svga->video_res_x /= (svga->seqregs[1] & 1) ? 8 : 9; + svga->video_res_y /= (svga->crtc[9] & 31) + 1; + svga->video_bpp = 0; + } + else + { + if (svga->crtc[9] & 0x80) + svga->video_res_y /= 2; + if (!(svga->crtc[0x17] & 1)) + svga->video_res_y *= 2; + svga->video_res_y /= (svga->crtc[9] & 31) + 1; + if (svga->lowres) + svga->video_res_x /= 2; + + switch (svga->gdcreg[5] & 0x60) + { + case 0x00: svga->video_bpp = 4; break; + case 0x20: svga->video_bpp = 2; break; + case 0x40: case 0x60: svga->video_bpp = svga->bpp; break; + } + } +// if (svga_interlace && oddeven) ma=maback=ma+(svga_rowoffset<<2); + +// pclog("Addr %08X vson %03X vsoff %01X %02X %02X %02X %i %i\n",ma,svga_vsyncstart,crtc[0x11]&0xF,crtc[0xD],crtc[0xC],crtc[0x33], svga_interlace, oddeven); + } + if (svga->vc == svga->vtotal) + { +// pclog("VC vtotal\n"); + + +// printf("Frame over at line %i %i %i %i\n",displine,vc,svga_vsyncstart,svga_dispend); + svga->vc = 0; + svga->sc = 0; + svga->dispon = 1; + svga->displine = (svga->interlace && svga->oddeven) ? 1 : 0; + svga->scrollcache = svga->attrregs[0x13] & 7; + svga->linecountff = 0; + + svga->hwcursor_on = 0; + svga->hwcursor_latch = svga->hwcursor; + + svga->overlay_on = 0; + svga->overlay_latch = svga->overlay; +// pclog("Latch HWcursor addr %08X\n", svga_hwcursor_latch.addr); + +// pclog("ADDR %08X\n",hwcursor_addr); + } + if (svga->sc == (svga->crtc[10] & 31)) + svga->con = 1; + } +// printf("2 %i\n",svga_vsyncstart); +//pclog("svga_poll %i %i %i %i %i %i %i\n", ins, svga->dispofftime, svga->dispontime, svga->vidtime, cyc_total, svga->linepos, svga->vc); +} + +int svga_init(svga_t *svga, void *p, int memsize, + void (*recalctimings_ex)(struct svga_t *svga), + uint8_t (*video_in) (uint16_t addr, void *p), + void (*video_out)(uint16_t addr, uint8_t val, void *p), + void (*hwcursor_draw)(struct svga_t *svga, int displine), + void (*overlay_draw)(struct svga_t *svga, int displine)) +{ + int c, d, e; + + svga->p = p; + + for (c = 0; c < 256; c++) + { + e = c; + for (d = 0; d < 8; d++) + { + svga_rotate[d][c] = e; + e = (e >> 1) | ((e & 1) ? 0x80 : 0); + } + } + svga->readmode = 0; + + svga->attrregs[0x11] = 0; + old_overscan_color = 0; + + overscan_x = 16; + overscan_y = 32; + + svga->crtc[0] = 63; + svga->crtc[6] = 255; + svga->dispontime = 1000 * (1 << TIMER_SHIFT); + svga->dispofftime = 1000 * (1 << TIMER_SHIFT); + svga->bpp = 8; + svga->vram = malloc(memsize); + svga->vram_limit = memsize; + svga->vrammask = memsize - 1; + svga->changedvram = malloc(/*(memsize >> 12) << 1*/0x800000 >> 12); + svga->recalctimings_ex = recalctimings_ex; + svga->video_in = video_in; + svga->video_out = video_out; + svga->hwcursor_draw = hwcursor_draw; + svga->overlay_draw = overlay_draw; +// _svga_recalctimings(svga); + + mem_mapping_add(&svga->mapping, 0xa0000, 0x20000, svga_read, svga_readw, svga_readl, svga_write, svga_writew, svga_writel, NULL, 0, svga); + + timer_add(svga_poll, &svga->vidtime, TIMER_ALWAYS_ENABLED, svga); + vramp = svga->vram; + + svga_pri = svga; + + svga->ramdac_type = RAMDAC_6BIT; + + return 0; +} + +void svga_close(svga_t *svga) +{ + free(svga->changedvram); + free(svga->vram); + + svga_pri = NULL; +} + +#define egacycles 1 +#define egacycles2 1 +void svga_write(uint32_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + uint8_t vala, valb, valc, vald, wm = svga->writemask; + int writemask2 = svga->writemask; + uint32_t raddr = addr; + int plane, mask; + + if (!svga->enablevram) return; + + egawrites++; + + cycles -= video_timing_b; + cycles_lost += video_timing_b; + + if (svga_output) pclog("Writeega %06X ",addr); + addr &= svga->banked_mask; + addr += svga->write_bank; + + if (!(svga->gdcreg[6] & 1)) svga->fullchange=2; + /* Horrible hack, I know, but it's the only way to fix the 440FX BIOS filling the VRAM with garbage until Tom fixes the memory emulation. */ + if ((cs == 0xE0000) && (cpu_state.pc == 0xBF2F) && (romset == ROM_440FX)) return; + if ((cs == 0xE0000) && (cpu_state.pc == 0xBF77) && (romset == ROM_440FX)) return; + if (svga->chain4 || svga->fb_only) + { + writemask2=1<<(addr&3); + addr&=~3; + } + else if (svga->chain2_write) + { + /* Redone because the original code caused problems when using Windows 3.1 EGA driver on (S)VGA card. */ + plane = (svga->readplane & 2) | (addr & 1); + mask = (1 << plane); + if (svga->seqregs[2] & mask) + { + addr = ((addr & ~1) << 2) | plane | (svga->oddeven_page ? 0x10000 : 0); + if ((!svga->extvram) && (addr >= 0x10000)) return; + if (addr >= svga->vram_limit) return; + if ((raddr <= 0xA0000) || (raddr >= 0xBFFFF)) return; + svga->vram[addr] = val; + + svga->changedvram[addr >> 12] = changeframecount; + } + return; + } + else + { + addr<<=2; + } + addr &= 0x7fffff; + + if ((!svga->extvram) && (addr >= 0x10000)) return; + + if (addr >= svga->vram_limit) + return; + + if (svga_output) pclog("%08X (%i, %i) %02X %i %i %i %02X\n", addr, addr & 1023, addr >> 10, val, writemask2, svga->writemode, svga->chain4, svga->gdcreg[8]); + svga->changedvram[addr >> 12] = changeframecount; + + switch (svga->writemode) + { + case 1: + if (writemask2 & 1) svga->vram[addr] = svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = svga->ld; + break; + case 0: + if (svga->gdcreg[3] & 7) + val = svga_rotate[svga->gdcreg[3] & 7][val]; + if (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) + { + if (writemask2 & 1) svga->vram[addr] = val; + if (writemask2 & 2) svga->vram[addr | 0x1] = val; + if (writemask2 & 4) svga->vram[addr | 0x2] = val; + if (writemask2 & 8) svga->vram[addr | 0x3] = val; + } + else + { + if (svga->gdcreg[1] & 1) vala = (svga->gdcreg[0] & 1) ? 0xff : 0; + else vala = val; + if (svga->gdcreg[1] & 2) valb = (svga->gdcreg[0] & 2) ? 0xff : 0; + else valb = val; + if (svga->gdcreg[1] & 4) valc = (svga->gdcreg[0] & 4) ? 0xff : 0; + else valc = val; + if (svga->gdcreg[1] & 8) vald = (svga->gdcreg[0] & 8) ? 0xff : 0; + else vald = val; + + switch (svga->gdcreg[3] & 0x18) + { + case 0: /*Set*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; + break; + } +// pclog("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); + } + break; + case 2: + if (!(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) + { + if (writemask2 & 1) svga->vram[addr] = (((val & 1) ? 0xff : 0) & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (((val & 2) ? 0xff : 0) & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (((val & 4) ? 0xff : 0) & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (((val & 8) ? 0xff : 0) & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); + } + else + { + vala = ((val & 1) ? 0xff : 0); + valb = ((val & 2) ? 0xff : 0); + valc = ((val & 4) ? 0xff : 0); + vald = ((val & 8) ? 0xff : 0); + switch (svga->gdcreg[3] & 0x18) + { + case 0: /*Set*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; + break; + } + } + break; + case 3: + if (svga->gdcreg[3] & 7) + val = svga_rotate[svga->gdcreg[3] & 7][val]; + wm = svga->gdcreg[8]; + svga->gdcreg[8] &= val; + + vala = (svga->gdcreg[0] & 1) ? 0xff : 0; + valb = (svga->gdcreg[0] & 2) ? 0xff : 0; + valc = (svga->gdcreg[0] & 4) ? 0xff : 0; + vald = (svga->gdcreg[0] & 8) ? 0xff : 0; + switch (svga->gdcreg[3] & 0x18) + { + case 0: /*Set*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; + break; + } + svga->gdcreg[8] = wm; + break; + } +} + +uint8_t svga_read(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + uint8_t temp, temp2, temp3, temp4; + uint32_t latch_addr; + int readplane = svga->readplane; + int plane; + + if (!svga->enablevram) return 0xff; + + cycles -= video_timing_b; + cycles_lost += video_timing_b; + + egareads++; +// pclog("Readega %06X ",addr); + addr &= svga->banked_mask; + addr += svga->read_bank; + + latch_addr = (addr << 2) & 0x7fffff; + +// pclog("%05X %i %04X:%04X %02X %02X %i\n",addr,svga->chain4,CS,pc, vram[addr & 0x7fffff], vram[(addr << 2) & 0x7fffff], svga->readmode); +// pclog("%i\n", svga->readmode); + if (svga->chain4 || svga->fb_only) + { + addr &= 0x7fffff; + if (addr >= svga->vram_limit) + return 0xff; + return svga->vram[addr]; + } + else if (svga->chain2_read) + { + /* Redone because the original code caused problems when using Windows 3.1 EGA driver on (S)VGA card. */ + plane = (svga->readplane & 2) | (addr & 1); + addr = ((addr & ~1) << 2) | plane | (svga->oddeven_page ? 0x10000 : 0); + latch_addr = (addr << 2) & 0x7fffff; + if ((!svga->extvram) && (addr >= 0x10000)) return 0xff; + if (addr >= svga->vram_limit) return 0xff; + return svga->vram[addr]; + } + else + addr<<=2; + + addr &= 0x7fffff; + + if ((!svga->extvram) && (addr >= 0x10000)) return 0xff; + + if (addr >= svga->vram_limit) + return 0xff; + + if (latch_addr < svga->vram_limit) + { + svga->la = svga->vram[latch_addr]; + svga->lb = svga->vram[latch_addr | 0x1]; + svga->lc = svga->vram[latch_addr | 0x2]; + svga->ld = svga->vram[latch_addr | 0x3]; + } + else + svga->la = svga->lb = svga->lc = svga->ld = 0xff; + + if (svga->readmode) + { + temp = (svga->colournocare & 1) ? 0xff : 0; + temp &= svga->la; + temp ^= (svga->colourcompare & 1) ? 0xff : 0; + temp2 = (svga->colournocare & 2) ? 0xff : 0; + temp2 &= svga->lb; + temp2 ^= (svga->colourcompare & 2) ? 0xff : 0; + temp3 = (svga->colournocare & 4) ? 0xff : 0; + temp3 &= svga->lc; + temp3 ^= (svga->colourcompare & 4) ? 0xff : 0; + temp4 = (svga->colournocare & 8) ? 0xff : 0; + temp4 &= svga->ld; + temp4 ^= (svga->colourcompare & 8) ? 0xff : 0; + return ~(temp | temp2 | temp3 | temp4); + } +//pclog("Read %02X %04X %04X\n",vram[addr|svga->readplane],addr,svga->readplane); + return svga->vram[addr | readplane]; +} + +void svga_write_linear(uint32_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + uint8_t vala, valb, valc, vald, wm = svga->writemask; + int writemask2 = svga->writemask; + uint32_t raddr = addr; + int plane, mask; + + if (!svga->enablevram) return; + + cycles -= video_timing_b; + cycles_lost += video_timing_b; + + egawrites++; + + if (svga_output) pclog("Write LFB %08X %02X ", addr, val); + if (!(svga->gdcreg[6] & 1)) + svga->fullchange = 2; + if (svga->chain4 || svga->fb_only) + { + writemask2=1<<(addr&3); + addr&=~3; + } + else if (svga->chain2_write) + { + /* Redone because the original code caused problems when using Windows 3.1 EGA driver on (S)VGA card. */ + plane = (svga->readplane & 2) | (addr & 1); + mask = (1 << plane); + if (svga->seqregs[2] & mask) + { + addr = ((addr & ~1) << 2) | plane | (svga->oddeven_page ? 0x10000 : 0); + addr &= 0x7fffff; + if ((!svga->extvram) && (addr >= 0x10000)) return; + if (addr >= svga->vram_limit) return; + if ((raddr <= 0xA0000) || (raddr >= 0xBFFFF)) return; + svga->vram[addr] = val; + + svga->changedvram[addr >> 12] = changeframecount; + } + return; + } + else + { + addr<<=2; + } + addr &= 0x7fffff; + if ((!svga->extvram) && (addr >= 0x10000)) return; + if (addr >= svga->vram_limit) + return; + if (svga_output) pclog("%08X\n", addr); + svga->changedvram[addr >> 12]=changeframecount; + + switch (svga->writemode) + { + case 1: + if (writemask2 & 1) svga->vram[addr] = svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = svga->ld; + break; + case 0: + if (svga->gdcreg[3] & 7) + val = svga_rotate[svga->gdcreg[3] & 7][val]; + if (svga->gdcreg[8] == 0xff && !(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) + { + if (writemask2 & 1) svga->vram[addr] = val; + if (writemask2 & 2) svga->vram[addr | 0x1] = val; + if (writemask2 & 4) svga->vram[addr | 0x2] = val; + if (writemask2 & 8) svga->vram[addr | 0x3] = val; + } + else + { + if (svga->gdcreg[1] & 1) vala = (svga->gdcreg[0] & 1) ? 0xff : 0; + else vala = val; + if (svga->gdcreg[1] & 2) valb = (svga->gdcreg[0] & 2) ? 0xff : 0; + else valb = val; + if (svga->gdcreg[1] & 4) valc = (svga->gdcreg[0] & 4) ? 0xff : 0; + else valc = val; + if (svga->gdcreg[1] & 8) vald = (svga->gdcreg[0] & 8) ? 0xff : 0; + else vald = val; + + switch (svga->gdcreg[3] & 0x18) + { + case 0: /*Set*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; + break; + } +// pclog("- %02X %02X %02X %02X %08X\n",vram[addr],vram[addr|0x1],vram[addr|0x2],vram[addr|0x3],addr); + } + break; + case 2: + if (!(svga->gdcreg[3] & 0x18) && !svga->gdcreg[1]) + { + if (writemask2 & 1) svga->vram[addr] = (((val & 1) ? 0xff : 0) & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (((val & 2) ? 0xff : 0) & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (((val & 4) ? 0xff : 0) & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (((val & 8) ? 0xff : 0) & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); + } + else + { + vala = ((val & 1) ? 0xff : 0); + valb = ((val & 2) ? 0xff : 0); + valc = ((val & 4) ? 0xff : 0); + vald = ((val & 8) ? 0xff : 0); + switch (svga->gdcreg[3] & 0x18) + { + case 0: /*Set*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; + break; + } + } + break; + case 3: + if (svga->gdcreg[3] & 7) + val = svga_rotate[svga->gdcreg[3] & 7][val]; + wm = svga->gdcreg[8]; + svga->gdcreg[8] &= val; + + vala = (svga->gdcreg[0] & 1) ? 0xff : 0; + valb = (svga->gdcreg[0] & 2) ? 0xff : 0; + valc = (svga->gdcreg[0] & 4) ? 0xff : 0; + vald = (svga->gdcreg[0] & 8) ? 0xff : 0; + switch (svga->gdcreg[3] & 0x18) + { + case 0: /*Set*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | (svga->la & ~svga->gdcreg[8]); + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | (svga->lb & ~svga->gdcreg[8]); + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | (svga->lc & ~svga->gdcreg[8]); + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | (svga->ld & ~svga->gdcreg[8]); + break; + case 8: /*AND*/ + if (writemask2 & 1) svga->vram[addr] = (vala | ~svga->gdcreg[8]) & svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb | ~svga->gdcreg[8]) & svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc | ~svga->gdcreg[8]) & svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald | ~svga->gdcreg[8]) & svga->ld; + break; + case 0x10: /*OR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) | svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) | svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) | svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) | svga->ld; + break; + case 0x18: /*XOR*/ + if (writemask2 & 1) svga->vram[addr] = (vala & svga->gdcreg[8]) ^ svga->la; + if (writemask2 & 2) svga->vram[addr | 0x1] = (valb & svga->gdcreg[8]) ^ svga->lb; + if (writemask2 & 4) svga->vram[addr | 0x2] = (valc & svga->gdcreg[8]) ^ svga->lc; + if (writemask2 & 8) svga->vram[addr | 0x3] = (vald & svga->gdcreg[8]) ^ svga->ld; + break; + } + svga->gdcreg[8] = wm; + break; + } +} + +uint8_t svga_read_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + uint8_t temp, temp2, temp3, temp4; + int readplane = svga->readplane; + int plane; + + if (!svga->enablevram) return 0xff; + + cycles -= video_timing_b; + cycles_lost += video_timing_b; + + egareads++; + + if (svga->chain4 || svga->fb_only) + { + addr &= 0x7fffff; + if (addr >= svga->vram_limit) + return 0xff; + return svga->vram[addr & 0x7fffff]; + } + else if (svga->chain2_read) + { + /* Redone because the original code caused problems when using Windows 3.1 EGA driver on (S)VGA card. */ + plane = (svga->readplane & 2) | (addr & 1); + addr = ((addr & ~1) << 2) | plane | (svga->oddeven_page ? 0x10000 : 0); + addr &= 0x7fffff; + if ((!svga->extvram) && (addr >= 0x10000)) return 0xff; + if (addr >= svga->vram_limit) return 0xff; + return svga->vram[addr]; + } + else + addr<<=2; + + addr &= 0x7fffff; + + if ((!svga->extvram) && (addr >= 0x10000)) return 0xff; + + if (addr >= svga->vram_limit) + return 0xff; + + svga->la = svga->vram[addr]; + svga->lb = svga->vram[addr | 0x1]; + svga->lc = svga->vram[addr | 0x2]; + svga->ld = svga->vram[addr | 0x3]; + if (svga->readmode) + { + temp = (svga->colournocare & 1) ? 0xff : 0; + temp &= svga->la; + temp ^= (svga->colourcompare & 1) ? 0xff : 0; + temp2 = (svga->colournocare & 2) ? 0xff : 0; + temp2 &= svga->lb; + temp2 ^= (svga->colourcompare & 2) ? 0xff : 0; + temp3 = (svga->colournocare & 4) ? 0xff : 0; + temp3 &= svga->lc; + temp3 ^= (svga->colourcompare & 4) ? 0xff : 0; + temp4 = (svga->colournocare & 8) ? 0xff : 0; + temp4 &= svga->ld; + temp4 ^= (svga->colourcompare & 8) ? 0xff : 0; + return ~(temp | temp2 | temp3 | temp4); + } +//printf("Read %02X %04X %04X\n",vram[addr|svga->readplane],addr,svga->readplane); + return svga->vram[addr | readplane]; +} + +void svga_doblit(int y1, int y2, int wx, int wy, svga_t *svga) +{ + int y_add = (enable_overscan) ? 32 : 0; + int x_add = (enable_overscan) ? 16 : 0; + uint32_t *p, *q, i, j; + +// pclog("svga_doblit start\n"); + svga->frames++; +// pclog("doblit %i %i\n", y1, y2); +// pclog("svga_doblit %i %i\n", wx, svga->hdisp); + + + if (y1 > y2) + { + video_blit_memtoscreen(32, 0, 0, 0, xsize + x_add, ysize + y_add); + return; + } + + if ((wx!=xsize || wy!=ysize) && !vid_resize) + { + xsize=wx; + ysize=wy+1; + if (xsize<64) xsize=640; + if (ysize<32) ysize=200; + + updatewindowsize(xsize + x_add,ysize + y_add); + } + if (vid_resize) + { + xsize = wx; + ysize = wy + 1; + } + + if (enable_overscan) + { + if ((wx >= 160) && ((wy + 1) >= 120)) + { + for (i = 0; i < 16; i++) + { + p = &((uint32_t *)buffer32->line[i])[32]; + q = &((uint32_t *)buffer32->line[ysize + y_add - 1 - i])[32]; + + for (j = 0; j < (xsize + x_add); j++) + { + p[j] = svga->pallook[svga->attrregs[0x11]]; + q[j] = svga->pallook[svga->attrregs[0x11]]; + } + } + + for (i = 16; i < (ysize + 16); i ++) + { + p = &((uint32_t *)buffer32->line[i])[32]; + + for (j = 0; j < 8; j++) + { + p[j] = svga->pallook[svga->attrregs[0x11]]; + p[xsize + x_add - 1 - j] = svga->pallook[svga->attrregs[0x11]]; + } + } + } + } + + video_blit_memtoscreen(32, 0, y1, y2 + y_add, xsize + x_add, ysize + y_add); +// pclog("svga_doblit end\n"); +} + +void svga_writew(uint32_t addr, uint16_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->enablevram) return; + + if (!svga->fast) + { + svga_write(addr, val, p); + svga_write(addr + 1, val >> 8, p); + return; + } + + egawrites += 2; + + cycles -= video_timing_w; + cycles_lost += video_timing_w; + + if (svga_output) pclog("svga_writew: %05X ", addr); + addr = (addr & svga->banked_mask) + svga->write_bank; + addr &= 0x7FFFFF; + if ((!svga->extvram) && (addr >= 0x10000)) return; + if (addr >= svga->vram_limit) + return; + if (svga_output) pclog("%08X (%i, %i) %04X\n", addr, addr & 1023, addr >> 10, val); + svga->changedvram[addr >> 12] = changeframecount; + *(uint16_t *)&svga->vram[addr] = val; +} + +void svga_writel(uint32_t addr, uint32_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->enablevram) return; + + if (!svga->fast) + { + svga_write(addr, val, p); + svga_write(addr + 1, val >> 8, p); + svga_write(addr + 2, val >> 16, p); + svga_write(addr + 3, val >> 24, p); + return; + } + + egawrites += 4; + + cycles -= video_timing_l; + cycles_lost += video_timing_l; + + if (svga_output) pclog("svga_writel: %05X ", addr); + addr = (addr & svga->banked_mask) + svga->write_bank; + addr &= 0x7FFFFF; + if ((!svga->extvram) && (addr >= 0x10000)) return; + if (addr >= svga->vram_limit) + return; + if (svga_output) pclog("%08X (%i, %i) %08X\n", addr, addr & 1023, addr >> 10, val); + + svga->changedvram[addr >> 12] = changeframecount; + *(uint32_t *)&svga->vram[addr] = val; +} + +uint16_t svga_readw(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->enablevram) return 0xffff; + + if (!svga->fast) + return svga_read(addr, p) | (svga_read(addr + 1, p) << 8); + + egareads += 2; + + cycles -= video_timing_w; + cycles_lost += video_timing_w; + +// pclog("Readw %05X ", addr); + addr = (addr & svga->banked_mask) + svga->read_bank; + addr &= 0x7FFFFF; + if ((!svga->extvram) && (addr >= 0x10000)) return 0xffff; +// pclog("%08X %04X\n", addr, *(uint16_t *)&vram[addr]); + if (addr >= svga->vram_limit) return 0xffff; + + return *(uint16_t *)&svga->vram[addr]; +} + +uint32_t svga_readl(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->enablevram) return 0xffffffff; + + if (!svga->fast) + return svga_read(addr, p) | (svga_read(addr + 1, p) << 8) | (svga_read(addr + 2, p) << 16) | (svga_read(addr + 3, p) << 24); + + egareads += 4; + + cycles -= video_timing_l; + cycles_lost += video_timing_l; + +// pclog("Readl %05X ", addr); + addr = (addr & svga->banked_mask) + svga->read_bank; + addr &= 0x7FFFFF; + if ((!svga->extvram) && (addr >= 0x10000)) return 0xffffffff; +// pclog("%08X %08X\n", addr, *(uint32_t *)&vram[addr]); + if (addr >= svga->vram_limit) return 0xffffffff; + + return *(uint32_t *)&svga->vram[addr]; +} + +void svga_writew_linear(uint32_t addr, uint16_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->enablevram) return; + + if (!svga->fast) + { + svga_write_linear(addr, val, p); + svga_write_linear(addr + 1, val >> 8, p); + return; + } + + egawrites += 2; + + cycles -= video_timing_w; + cycles_lost += video_timing_w; + + if (svga_output) pclog("Write LFBw %08X %04X\n", addr, val); + addr &= 0x7FFFFF; + if ((!svga->extvram) && (addr >= 0x10000)) return; + if (addr >= svga->vram_limit) + return; + svga->changedvram[addr >> 12] = changeframecount; + *(uint16_t *)&svga->vram[addr] = val; +} + +void svga_writel_linear(uint32_t addr, uint32_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->enablevram) return; + + if (!svga->fast) + { + svga_write_linear(addr, val, p); + svga_write_linear(addr + 1, val >> 8, p); + svga_write_linear(addr + 2, val >> 16, p); + svga_write_linear(addr + 3, val >> 24, p); + return; + } + + egawrites += 4; + + cycles -= video_timing_l; + cycles_lost += video_timing_l; + + if (svga_output) pclog("Write LFBl %08X %08X\n", addr, val); + addr &= 0x7fffff; + if ((!svga->extvram) && (addr >= 0x10000)) return; + if (addr >= svga->vram_limit) + return; + svga->changedvram[addr >> 12] = changeframecount; + *(uint32_t *)&svga->vram[addr] = val; +} + +uint16_t svga_readw_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->enablevram) return 0xffff; + + if (!svga->fast) + return svga_read_linear(addr, p) | (svga_read_linear(addr + 1, p) << 8); + + egareads += 2; + + cycles -= video_timing_w; + cycles_lost += video_timing_w; + + addr &= 0x7FFFFF; + if ((!svga->extvram) && (addr >= 0x10000)) return 0xffff; + if (addr >= svga->vram_limit) return 0xffff; + + return *(uint16_t *)&svga->vram[addr]; +} + +uint32_t svga_readl_linear(uint32_t addr, void *p) +{ + svga_t *svga = (svga_t *)p; + + if (!svga->enablevram) return 0xffffffff; + + if (!svga->fast) + return svga_read_linear(addr, p) | (svga_read_linear(addr + 1, p) << 8) | (svga_read_linear(addr + 2, p) << 16) | (svga_read_linear(addr + 3, p) << 24); + + egareads += 4; + + cycles -= video_timing_l; + cycles_lost += video_timing_l; + + addr &= 0x7FFFFF; + if ((!svga->extvram) && (addr >= 0x10000)) return 0xffffffff; + if (addr >= svga->vram_limit) return 0xffffffff; + + return *(uint32_t *)&svga->vram[addr]; +} + + +void svga_add_status_info(char *s, int max_len, void *p) +{ + svga_t *svga = (svga_t *)p; + char temps[128]; + + if (svga->chain4) strcpy(temps, "SVGA chained (possibly mode 13h)\n"); + else strcpy(temps, "SVGA unchained (possibly mode-X)\n"); + strncat(s, temps, max_len); + + if (!svga->video_bpp) strcpy(temps, "SVGA in text mode\n"); + else sprintf(temps, "SVGA colour depth : %i bpp\n", svga->video_bpp); + strncat(s, temps, max_len); + + sprintf(temps, "SVGA resolution : %i x %i\n", svga->video_res_x, svga->video_res_y); + strncat(s, temps, max_len); + + sprintf(temps, "SVGA refresh rate : %i Hz\n\n", svga->frames); + svga->frames = 0; + strncat(s, temps, max_len); +} diff --git a/src/vid_svga.h b/src/vid_svga.h new file mode 100644 index 000000000..5b9644bc0 --- /dev/null +++ b/src/vid_svga.h @@ -0,0 +1,154 @@ +typedef struct svga_t +{ + mem_mapping_t mapping; + + uint8_t crtcreg; + uint8_t crtc[128]; + uint8_t gdcreg[16]; + int gdcaddr; + uint8_t attrregs[32]; + int attraddr, attrff; + int attr_palette_enable; + uint8_t seqregs[64]; + int seqaddr; + + uint8_t miscout; + int vidclock; + + uint32_t vram_limit; + + uint8_t la, lb, lc, ld; + + uint8_t dac_mask, dac_status; + int dac_read, dac_write, dac_pos; + int dac_r, dac_g; + + uint8_t cgastat; + + uint8_t plane_mask; + + int fb_only; + + int fast; + uint8_t colourcompare, colournocare; + int readmode, writemode, readplane; + int chain4, chain2_write, chain2_read; + int oddeven_page; + int enablevram, extvram; + uint8_t writemask; + uint32_t charseta, charsetb; + + uint8_t egapal[16]; + uint32_t pallook[256]; + PALETTE vgapal; + + int ramdac_type; + + int vtotal, dispend, vsyncstart, split, vblankstart; + int hdisp, hdisp_old, htotal, hdisp_time, rowoffset; + int lowres, interlace; + int linedbl, rowcount; + double clock; + uint32_t ma_latch; + int bpp; + + int dispontime, dispofftime; + int vidtime; + + uint8_t scrblank; + + int dispon; + int hdisp_on; + + uint32_t ma, maback, ca; + int vc; + int sc; + int linepos, vslines, linecountff, oddeven; + int con, cursoron, blink; + int scrollcache; + + int firstline, lastline; + int firstline_draw, lastline_draw; + int displine; + + uint8_t *vram; + uint8_t *changedvram; + int vrammask; + uint32_t banked_mask; + + uint32_t write_bank, read_bank; + + int fullchange; + + int video_res_x, video_res_y, video_bpp; + int frames, fps; + + struct + { + int ena; + int x, y; + int xoff, yoff; + int ysize; + uint32_t addr; + int v_acc, h_acc; + } hwcursor, hwcursor_latch, overlay, overlay_latch; + + int hwcursor_on; + int overlay_on; + + int hwcursor_oddeven; + int overlay_oddeven; + + void (*render)(struct svga_t *svga); + void (*recalctimings_ex)(struct svga_t *svga); + + void (*video_out)(uint16_t addr, uint8_t val, void *p); + uint8_t (*video_in) (uint16_t addr, void *p); + + void (*hwcursor_draw)(struct svga_t *svga, int displine); + + void (*overlay_draw)(struct svga_t *svga, int displine); + + /*If set then another device is driving the monitor output and the SVGA + card should not attempt to display anything */ + int override; + void *p; +} svga_t; + +extern int svga_init(svga_t *svga, void *p, int memsize, + void (*recalctimings_ex)(struct svga_t *svga), + uint8_t (*video_in) (uint16_t addr, void *p), + void (*video_out)(uint16_t addr, uint8_t val, void *p), + void (*hwcursor_draw)(struct svga_t *svga, int displine), + void (*overlay_draw)(struct svga_t *svga, int displine)); +extern void svga_recalctimings(svga_t *svga); + + +uint8_t svga_read(uint32_t addr, void *p); +uint16_t svga_readw(uint32_t addr, void *p); +uint32_t svga_readl(uint32_t addr, void *p); +void svga_write(uint32_t addr, uint8_t val, void *p); +void svga_writew(uint32_t addr, uint16_t val, void *p); +void svga_writel(uint32_t addr, uint32_t val, void *p); +uint8_t svga_read_linear(uint32_t addr, void *p); +uint16_t svga_readw_linear(uint32_t addr, void *p); +uint32_t svga_readl_linear(uint32_t addr, void *p); +void svga_write_linear(uint32_t addr, uint8_t val, void *p); +void svga_writew_linear(uint32_t addr, uint16_t val, void *p); +void svga_writel_linear(uint32_t addr, uint32_t val, void *p); + +void svga_add_status_info(char *s, int max_len, void *p); + +extern uint8_t svga_rotate[8][256]; + +void svga_out(uint16_t addr, uint8_t val, void *p); +uint8_t svga_in(uint16_t addr, void *p); + +svga_t *svga_get_pri(); +void svga_set_override(svga_t *svga, int val); + +#define RAMDAC_6BIT 0 +#define RAMDAC_8BIT 1 +void svga_set_ramdac_type(svga_t *svga, int type); + +extern uint8_t mask_crtc[0x19]; diff --git a/src/vid_svga_render.c b/src/vid_svga_render.c new file mode 100644 index 000000000..7ffde9393 --- /dev/null +++ b/src/vid_svga_render.c @@ -0,0 +1,744 @@ +#include "ibm.h" +#include "mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include + +void svga_render_blank(svga_t *svga) +{ + int x, xx; + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x < svga->hdisp; x++) + { + switch (svga->seqregs[1] & 9) + { + case 0: + for (xx = 0; xx < 9; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 9) + xx + 32 + x_add] = 0; + break; + case 1: + for (xx = 0; xx < 8; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 8) + xx + 32 + x_add] = 0; + break; + case 8: + for (xx = 0; xx < 18; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 18) + xx + 32 + x_add] = 0; + break; + case 9: + for (xx = 0; xx < 16; xx++) ((uint32_t *)buffer32->line[svga->displine + y_add])[(x * 16) + xx + 32 + x_add] = 0; + break; + } + } +} + +void svga_render_text_40(svga_t *svga) +{ + uint32_t addr_ex = 0; + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + if (svga->fullchange) + { + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[32 + x_add]; + int x, xx; + int drawcursor; + uint8_t chr, attr, dat; + uint32_t charaddr; + int fg, bg; + int xinc = (svga->seqregs[1] & 1) ? 16 : 18; + + for (x = 0; x < svga->hdisp; x += xinc) + { + drawcursor = ((svga->ma == svga->ca) && svga->con && svga->cursoron); + if (svga->oddeven_page) addr_ex |= 0x10000; + chr = svga->vram[(svga->ma << 1) | addr_ex]; + attr = svga->vram[((svga->ma << 1) + 1) | addr_ex]; + if (attr & 8) charaddr = svga->charsetb + (chr * 128); + else charaddr = svga->charseta + (chr * 128); + + if (drawcursor) + { + bg = svga->pallook[svga->egapal[attr & 15]]; + fg = svga->pallook[svga->egapal[attr >> 4]]; + } + else + { + fg = svga->pallook[svga->egapal[attr & 15]]; + bg = svga->pallook[svga->egapal[attr >> 4]]; + if (attr & 0x80 && svga->attrregs[0x10] & 8) + { + bg = svga->pallook[svga->egapal[(attr >> 4) & 7]]; + if (svga->blink & 16) + fg = bg; + } + } + + dat = svga->vram[charaddr + (svga->sc << 2)]; + if (svga->seqregs[1] & 1) + { + for (xx = 0; xx < 16; xx += 2) + p[xx] = p[xx + 1] = (dat & (0x80 >> (xx >> 1))) ? fg : bg; + } + else + { + for (xx = 0; xx < 16; xx += 2) + p[xx] = p[xx + 1] = (dat & (0x80 >> (xx >> 1))) ? fg : bg; + if ((chr & ~0x1F) != 0xC0 || !(svga->attrregs[0x10] & 4)) + p[16] = p[17] = bg; + else + p[16] = p[17] = (dat & 1) ? fg : bg; + } + svga->ma += 4; + p += xinc; + } + svga->ma &= svga->vrammask; + } +} + +void svga_render_text_80(svga_t *svga) +{ + uint32_t addr_ex = 0; + FILE *f; + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + if (svga->fullchange) + { + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[32 + x_add]; + int x, xx; + int drawcursor; + uint8_t chr, attr, dat; + uint32_t charaddr; + int fg, bg; + int xinc = (svga->seqregs[1] & 1) ? 8 : 9; + + for (x = 0; x < svga->hdisp; x += xinc) + { + drawcursor = ((svga->ma == svga->ca) && svga->con && svga->cursoron); + if (svga->oddeven_page) addr_ex |= 0x10000; + chr = svga->vram[(svga->ma << 1) | addr_ex]; + attr = svga->vram[((svga->ma << 1) + 1) | addr_ex]; + if (attr & 8) charaddr = svga->charsetb + (chr * 128); + else charaddr = svga->charseta + (chr * 128); + + if (drawcursor) + { + bg = svga->pallook[svga->egapal[attr & 15]]; + fg = svga->pallook[svga->egapal[attr >> 4]]; + } + else + { + fg = svga->pallook[svga->egapal[attr & 15]]; + bg = svga->pallook[svga->egapal[attr >> 4]]; + if (attr & 0x80 && svga->attrregs[0x10] & 8) + { + bg = svga->pallook[svga->egapal[(attr >> 4) & 7]]; + if (svga->blink & 16) + fg = bg; + } + } + + dat = svga->vram[charaddr + (svga->sc << 2)]; + if (svga->seqregs[1] & 1) + { + for (xx = 0; xx < 8; xx++) + p[xx] = (dat & (0x80 >> xx)) ? fg : bg; + } + else + { + for (xx = 0; xx < 8; xx++) + p[xx] = (dat & (0x80 >> xx)) ? fg : bg; + if ((chr & ~0x1F) != 0xC0 || !(svga->attrregs[0x10] & 4)) + p[8] = bg; + else + p[8] = (dat & 1) ? fg : bg; + } + svga->ma += 4; + p += xinc; + } + svga->ma &= svga->vrammask; + } +} + +void svga_render_2bpp_lowres(svga_t *svga) +{ + int changed_offset; + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->sc & 1 && !(svga->crtc[0x17] & 1)) + changed_offset = (svga->ma << 1) >> 12; + else + changed_offset = ((svga->ma << 1) + 0x8000) >> 12; + + if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) + { + int x; + int offset = ((8 - svga->scrollcache) << 1) + 16; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 16) + { + uint8_t dat[2]; + + if (svga->sc & 1 && !(svga->crtc[0x17] & 1)) + { + dat[0] = svga->vram[(svga->ma << 1) + 0x8000]; + dat[1] = svga->vram[(svga->ma << 1) + 0x8001]; + } + else + { + dat[0] = svga->vram[(svga->ma << 1)]; + dat[1] = svga->vram[(svga->ma << 1) + 1]; + } + svga->ma += 4; + svga->ma &= svga->vrammask; + + p[0] = p[1] = svga->pallook[svga->egapal[(dat[0] >> 6) & 3]]; + p[2] = p[3] = svga->pallook[svga->egapal[(dat[0] >> 4) & 3]]; + p[4] = p[5] = svga->pallook[svga->egapal[(dat[0] >> 2) & 3]]; + p[6] = p[7] = svga->pallook[svga->egapal[dat[0] & 3]]; + p[8] = p[9] = svga->pallook[svga->egapal[(dat[1] >> 6) & 3]]; + p[10] = p[11] = svga->pallook[svga->egapal[(dat[1] >> 4) & 3]]; + p[12] = p[13] = svga->pallook[svga->egapal[(dat[1] >> 2) & 3]]; + p[14] = p[15] = svga->pallook[svga->egapal[dat[1] & 3]]; + + p += 16; + } + } +} + +void svga_render_2bpp_highres(svga_t *svga) +{ + int changed_offset; + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->sc & 1 && !(svga->crtc[0x17] & 1)) + changed_offset = ((svga->ma << 1) | 0x8000) >> 12; + else + changed_offset = (svga->ma << 1) >> 12; + + if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) + { + int x; + int offset = (8 - svga->scrollcache) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 8) + { + uint8_t dat[2]; + + if (svga->sc & 1 && !(svga->crtc[0x17] & 1)) + { + dat[0] = svga->vram[(svga->ma << 1) + 0x8000]; + dat[1] = svga->vram[(svga->ma << 1) + 0x8001]; + } + else + { + dat[0] = svga->vram[(svga->ma << 1)]; + dat[1] = svga->vram[(svga->ma << 1) + 1]; + } + svga->ma += 4; + svga->ma &= svga->vrammask; + + p[0] = svga->pallook[svga->egapal[(dat[0] >> 6) & 3]]; + p[1] = svga->pallook[svga->egapal[(dat[0] >> 4) & 3]]; + p[2] = svga->pallook[svga->egapal[(dat[0] >> 2) & 3]]; + p[3] = svga->pallook[svga->egapal[dat[0] & 3]]; + p[4] = svga->pallook[svga->egapal[(dat[1] >> 6) & 3]]; + p[5] = svga->pallook[svga->egapal[(dat[1] >> 4) & 3]]; + p[6] = svga->pallook[svga->egapal[(dat[1] >> 2) & 3]]; + p[7] = svga->pallook[svga->egapal[dat[1] & 3]]; + + p += 8; + } + } +} + +void svga_render_4bpp_lowres(svga_t *svga) +{ + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = ((8 - svga->scrollcache) << 1) + 16; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 16) + { + uint8_t edat[4]; + uint8_t dat; + + *(uint32_t *)(&edat[0]) = *(uint32_t *)(&svga->vram[svga->ma]); + svga->ma += 4; + svga->ma &= svga->vrammask; + + dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); + p[0] = p[1] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[2] = p[3] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); + p[4] = p[5] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[6] = p[7] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); + p[8] = p[9] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[10] = p[11] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); + p[12] = p[13] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[14] = p[15] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + + p += 16; + } + } +} + +void svga_render_4bpp_highres(svga_t *svga) +{ + int changed_offset; + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->sc & 1 && !(svga->crtc[0x17] & 1)) + changed_offset = (svga->ma | 0x8000) >> 12; + else + changed_offset = svga->ma >> 12; + + if (svga->changedvram[changed_offset] || svga->changedvram[changed_offset + 1] || svga->fullchange) + { + int x; + int offset = (8 - svga->scrollcache) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 8) + { + uint8_t edat[4]; + uint8_t dat; + + if (svga->sc & 1 && !(svga->crtc[0x17] & 1)) + *(uint32_t *)(&edat[0]) = *(uint32_t *)(&svga->vram[svga->ma | 0x8000]); + else + *(uint32_t *)(&edat[0]) = *(uint32_t *)(&svga->vram[svga->ma]); + svga->ma += 4; + svga->ma &= svga->vrammask; + + dat = edatlookup[edat[0] >> 6][edat[1] >> 6] | (edatlookup[edat[2] >> 6][edat[3] >> 6] << 2); + p[0] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[1] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[(edat[0] >> 4) & 3][(edat[1] >> 4) & 3] | (edatlookup[(edat[2] >> 4) & 3][(edat[3] >> 4) & 3] << 2); + p[2] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[3] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[(edat[0] >> 2) & 3][(edat[1] >> 2) & 3] | (edatlookup[(edat[2] >> 2) & 3][(edat[3] >> 2) & 3] << 2); + p[4] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[5] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + dat = edatlookup[edat[0] & 3][edat[1] & 3] | (edatlookup[edat[2] & 3][edat[3] & 3] << 2); + p[6] = svga->pallook[svga->egapal[(dat >> 4) & svga->plane_mask]]; + p[7] = svga->pallook[svga->egapal[dat & svga->plane_mask]]; + + p += 8; + } + } +} + +void svga_render_8bpp_lowres(svga_t *svga) +{ + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - (svga->scrollcache & 6)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 8) + { + uint32_t dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vrammask]); + + p[0] = p[1] = svga->pallook[dat & 0xff]; + p[2] = p[3] = svga->pallook[(dat >> 8) & 0xff]; + p[4] = p[5] = svga->pallook[(dat >> 16) & 0xff]; + p[6] = p[7] = svga->pallook[(dat >> 24) & 0xff]; + + svga->ma += 4; + p += 8; + } + svga->ma &= svga->vrammask; + } + + // return NULL; +} + +void svga_render_8bpp_highres(svga_t *svga) +{ + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 8) + { + uint32_t dat; + dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vrammask]); + p[0] = svga->pallook[dat & 0xff]; + p[1] = svga->pallook[(dat >> 8) & 0xff]; + p[2] = svga->pallook[(dat >> 16) & 0xff]; + p[3] = svga->pallook[(dat >> 24) & 0xff]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + 4) & svga->vrammask]); + p[4] = svga->pallook[dat & 0xff]; + p[5] = svga->pallook[(dat >> 8) & 0xff]; + p[6] = svga->pallook[(dat >> 16) & 0xff]; + p[7] = svga->pallook[(dat >> 24) & 0xff]; + + svga->ma += 8; + p += 8; + } + svga->ma &= svga->vrammask; + } + + // return NULL; +} + +void svga_render_15bpp_lowres(svga_t *svga) +{ + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - (svga->scrollcache & 6)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 4) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vrammask]); + + p[x] = video_15to32[dat & 0xffff]; + p[x + 1] = video_15to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vrammask]); + + p[x] = video_15to32[dat & 0xffff]; + p[x + 1] = video_15to32[dat >> 16]; + } + svga->ma += x << 1; + svga->ma &= svga->vrammask; + } +} + +void svga_render_15bpp_highres(svga_t *svga) +{ + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 8) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vrammask]); + p[x] = video_15to32[dat & 0xffff]; + p[x + 1] = video_15to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vrammask]); + p[x + 2] = video_15to32[dat & 0xffff]; + p[x + 3] = video_15to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 8) & svga->vrammask]); + p[x + 4] = video_15to32[dat & 0xffff]; + p[x + 5] = video_15to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 12) & svga->vrammask]); + p[x + 6] = video_15to32[dat & 0xffff]; + p[x + 7] = video_15to32[dat >> 16]; + } + svga->ma += x << 1; + svga->ma &= svga->vrammask; + } +} + +void svga_render_16bpp_lowres(svga_t *svga) +{ + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - (svga->scrollcache & 6)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 4) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vrammask]); + + p[x] = video_16to32[dat & 0xffff]; + p[x + 1] = video_16to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vrammask]); + + p[x] = video_16to32[dat & 0xffff]; + p[x + 1] = video_16to32[dat >> 16]; + } + svga->ma += x << 1; + svga->ma &= svga->vrammask; + } +} + +void svga_render_16bpp_highres(svga_t *svga) +{ + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 8) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1)) & svga->vrammask]); + p[x] = video_16to32[dat & 0xffff]; + p[x + 1] = video_16to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 4) & svga->vrammask]); + p[x + 2] = video_16to32[dat & 0xffff]; + p[x + 3] = video_16to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 8) & svga->vrammask]); + p[x + 4] = video_16to32[dat & 0xffff]; + p[x + 5] = video_16to32[dat >> 16]; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 1) + 12) & svga->vrammask]); + p[x + 6] = video_16to32[dat & 0xffff]; + p[x + 7] = video_16to32[dat >> 16]; + } + svga->ma += x << 1; + svga->ma &= svga->vrammask; + } +} + +void svga_render_24bpp_lowres(svga_t *svga) +{ + int x, offset; + uint32_t fg; + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + offset = (8 - (svga->scrollcache & 6)) + 24; + + for (x = 0; x <= svga->hdisp; x++) + { + fg = svga->vram[svga->ma] | (svga->vram[svga->ma + 1] << 8) | (svga->vram[svga->ma + 2] << 16); + svga->ma += 3; + svga->ma &= svga->vrammask; + ((uint32_t *)buffer32->line[svga->displine + y_add])[(x << 1) + offset + x_add] = ((uint32_t *)buffer32->line[svga->displine + y_add])[(x << 1) + 1 + offset + x_add] = fg; + } + } +} + +void svga_render_24bpp_highres(svga_t *svga) +{ + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x += 4) + { + uint32_t dat = *(uint32_t *)(&svga->vram[svga->ma & svga->vrammask]); + p[x] = dat & 0xffffff; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + 3) & svga->vrammask]); + p[x + 1] = dat & 0xffffff; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + 6) & svga->vrammask]); + p[x + 2] = dat & 0xffffff; + + dat = *(uint32_t *)(&svga->vram[(svga->ma + 9) & svga->vrammask]); + p[x + 3] = dat & 0xffffff; + + svga->ma += 12; + } + svga->ma &= svga->vrammask; + } +} + +void svga_render_32bpp_lowres(svga_t *svga) +{ + int x, offset; + uint32_t fg; + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->fullchange) + { + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + offset = (8 - (svga->scrollcache & 6)) + 24; + + for (x = 0; x <= svga->hdisp; x++) + { + fg = svga->vram[svga->ma] | (svga->vram[svga->ma + 1] << 8) | (svga->vram[svga->ma + 2] << 16); + svga->ma += 4; + svga->ma &= svga->vrammask; + ((uint32_t *)buffer32->line[svga->displine + y_add])[(x << 1) + offset + x_add] = ((uint32_t *)buffer32->line[svga->displine + y_add])[(x << 1) + 1 + offset + x_add] = fg; + } + } +} + +/*72% + 91%*/ +void svga_render_32bpp_highres(svga_t *svga) +{ + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x++) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vrammask]); + p[x] = dat & 0xffffff; + } + svga->ma += 4; + svga->ma &= svga->vrammask; + } +} + +void svga_render_ABGR8888_highres(svga_t *svga) +{ + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x++) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vrammask]); + p[x] = ((dat & 0xff0000) >> 16) | (dat & 0x00ff00) | ((dat & 0x0000ff) << 16); + } + svga->ma += 4; + svga->ma &= svga->vrammask; + } +} + +void svga_render_RGBA8888_highres(svga_t *svga) +{ + int y_add = (enable_overscan) ? 16 : 0; + int x_add = y_add >> 1; + + if (svga->changedvram[svga->ma >> 12] || svga->changedvram[(svga->ma >> 12) + 1] || svga->changedvram[(svga->ma >> 12) + 2] || svga->fullchange) + { + int x; + int offset = (8 - ((svga->scrollcache & 6) >> 1)) + 24; + uint32_t *p = &((uint32_t *)buffer32->line[svga->displine + y_add])[offset + x_add]; + + if (svga->firstline_draw == 2000) + svga->firstline_draw = svga->displine; + svga->lastline_draw = svga->displine; + + for (x = 0; x <= svga->hdisp; x++) + { + uint32_t dat = *(uint32_t *)(&svga->vram[(svga->ma + (x << 2)) & svga->vrammask]); + p[x] = dat >> 8; + } + svga->ma += 4; + svga->ma &= svga->vrammask; + } +} diff --git a/src/vid_svga_render.h b/src/vid_svga_render.h new file mode 100644 index 000000000..944d9757b --- /dev/null +++ b/src/vid_svga_render.h @@ -0,0 +1,33 @@ +extern int firstline_draw, lastline_draw; +extern int displine; +extern int sc; + +extern uint32_t ma, ca; +extern int con, cursoron, cgablink; + +extern int scrollcache; + +extern uint8_t edatlookup[4][4]; + +void svga_render_blank(svga_t *svga); +void svga_render_text_40(svga_t *svga); +void svga_render_text_80(svga_t *svga); + +void svga_render_2bpp_lowres(svga_t *svga); +void svga_render_2bpp_highres(svga_t *svga); +void svga_render_4bpp_lowres(svga_t *svga); +void svga_render_4bpp_highres(svga_t *svga); +void svga_render_8bpp_lowres(svga_t *svga); +void svga_render_8bpp_highres(svga_t *svga); +void svga_render_15bpp_lowres(svga_t *svga); +void svga_render_15bpp_highres(svga_t *svga); +void svga_render_16bpp_lowres(svga_t *svga); +void svga_render_16bpp_highres(svga_t *svga); +void svga_render_24bpp_lowres(svga_t *svga); +void svga_render_24bpp_highres(svga_t *svga); +void svga_render_32bpp_lowres(svga_t *svga); +void svga_render_32bpp_highres(svga_t *svga); +void svga_render_ABGR8888_highres(svga_t *svga); +void svga_render_RGBA8888_highres(svga_t *svga); + +extern void (*svga_render)(svga_t *svga); diff --git a/src/vid_tandy.c b/src/vid_tandy.c new file mode 100644 index 000000000..4f81efc6f --- /dev/null +++ b/src/vid_tandy.c @@ -0,0 +1,726 @@ +#include +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "timer.h" +#include "video.h" +#include "vid_tandy.h" + +static int i_filt[8],q_filt[8]; + +typedef struct tandy_t +{ + mem_mapping_t mapping; + mem_mapping_t ram_mapping; + + uint8_t crtc[32]; + int crtcreg; + + int array_index; + uint8_t array[32]; + int memctrl;//=-1; + uint32_t base; + uint8_t mode, col; + uint8_t stat; + + uint8_t *vram, *b8000; + uint32_t b8000_mask; + + int linepos, displine; + int sc, vc; + int dispon; + int con, coff, cursoron, blink; + int vsynctime, vadj; + uint16_t ma, maback; + + int dispontime, dispofftime, vidtime; + int firstline, lastline; +} tandy_t; + +static uint8_t crtcmask[32] = +{ + 0xff, 0xff, 0xff, 0xff, 0x7f, 0x1f, 0x7f, 0x7f, 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +void tandy_recalcaddress(tandy_t *tandy); +void tandy_recalctimings(tandy_t *tandy); + +void tandy_out(uint16_t addr, uint8_t val, void *p) +{ + tandy_t *tandy = (tandy_t *)p; + uint8_t old; +// pclog("Tandy OUT %04X %02X\n",addr,val); + switch (addr) + { + case 0x3d4: + tandy->crtcreg = val & 0x1f; + return; + case 0x3d5: + old = tandy->crtc[tandy->crtcreg]; + tandy->crtc[tandy->crtcreg] = val & crtcmask[tandy->crtcreg]; + if (old != val) + { + if (tandy->crtcreg < 0xe || tandy->crtcreg > 0x10) + { + fullchange = changeframecount; + tandy_recalctimings(tandy); + } + } + return; + case 0x3d8: + tandy->mode = val; + return; + case 0x3d9: + tandy->col = val; + return; + case 0x3da: + tandy->array_index = val & 0x1f; + break; + case 0x3de: + if (tandy->array_index & 16) + val &= 0xf; + tandy->array[tandy->array_index & 0x1f] = val; + break; + case 0x3df: + tandy->memctrl = val; + tandy_recalcaddress(tandy); + break; + case 0xa0: + mem_mapping_set_addr(&tandy->ram_mapping, ((val >> 1) & 7) * 128 * 1024, 0x20000); + tandy_recalcaddress(tandy); + break; + } +} + +uint8_t tandy_in(uint16_t addr, void *p) +{ + tandy_t *tandy = (tandy_t *)p; +// if (addr!=0x3DA) pclog("Tandy IN %04X\n",addr); + switch (addr) + { + case 0x3d4: + return tandy->crtcreg; + case 0x3d5: + return tandy->crtc[tandy->crtcreg]; + case 0x3da: + return tandy->stat; + } + return 0xFF; +} + +void tandy_recalcaddress(tandy_t *tandy) +{ + if ((tandy->memctrl & 0xc0) == 0xc0) + { + tandy->vram = &ram[((tandy->memctrl & 0x06) << 14) + tandy->base]; + tandy->b8000 = &ram[((tandy->memctrl & 0x30) << 11) + tandy->base]; + tandy->b8000_mask = 0x7fff; +// printf("VRAM at %05X B8000 at %05X\n",((tandy->memctrl&0x6)<<14)+tandy->base,((tandy->memctrl&0x30)<<11)+tandy->base); + } + else + { + tandy->vram = &ram[((tandy->memctrl & 0x07) << 14) + tandy->base]; + tandy->b8000 = &ram[((tandy->memctrl & 0x38) << 11) + tandy->base]; + tandy->b8000_mask = 0x3fff; +// printf("VRAM at %05X B8000 at %05X\n",((tandy->memctrl&0x7)<<14)+tandy->base,((tandy->memctrl&0x38)<<11)+tandy->base); + } +} + +void tandy_ram_write(uint32_t addr, uint8_t val, void *p) +{ + tandy_t *tandy = (tandy_t *)p; +// pclog("Tandy RAM write %05X %02X %04X:%04X\n",addr,val,CS,pc); + ram[tandy->base + (addr & 0x1ffff)] = val; +} + +uint8_t tandy_ram_read(uint32_t addr, void *p) +{ + tandy_t *tandy = (tandy_t *)p; +// pclog("Tandy RAM read %05X %02X %04X:%04X\n",addr,ram[tandy->base + (addr & 0x1ffff)],CS,pc); + return ram[tandy->base + (addr & 0x1ffff)]; +} + +void tandy_write(uint32_t addr, uint8_t val, void *p) +{ + tandy_t *tandy = (tandy_t *)p; + if (tandy->memctrl == -1) + return; + + egawrites++; +// pclog("Tandy VRAM write %05X %02X %04X:%04X %04X:%04X\n",addr,val,CS,pc,DS,SI); + tandy->b8000[addr & tandy->b8000_mask] = val; +} + +uint8_t tandy_read(uint32_t addr, void *p) +{ + tandy_t *tandy = (tandy_t *)p; + if (tandy->memctrl == -1) + return 0xff; + + egareads++; +// pclog("Tandy VRAM read %05X %02X %04X:%04X\n",addr,tandy->b8000[addr&0x7FFF],CS,pc); + return tandy->b8000[addr & tandy->b8000_mask]; +} + +void tandy_recalctimings(tandy_t *tandy) +{ + double _dispontime, _dispofftime, disptime; + if (tandy->mode & 1) + { + disptime = tandy->crtc[0] + 1; + _dispontime = tandy->crtc[1]; + } + else + { + disptime = (tandy->crtc[0] + 1) << 1; + _dispontime = tandy->crtc[1] << 1; + } + _dispofftime = disptime - _dispontime; + _dispontime *= CGACONST; + _dispofftime *= CGACONST; + tandy->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + tandy->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + + +static int ntsc_col[8][8]= +{ + {0,0,0,0,0,0,0,0}, /*Black*/ + {0,0,1,1,1,1,0,0}, /*Blue*/ + {1,0,0,0,0,1,1,1}, /*Green*/ + {0,0,0,0,1,1,1,1}, /*Cyan*/ + {1,1,1,1,0,0,0,0}, /*Red*/ + {0,1,1,1,1,0,0,0}, /*Magenta*/ + {1,1,0,0,0,0,1,1}, /*Yellow*/ + {1,1,1,1,1,1,1,1} /*White*/ +}; + +/*static int cga4pal[8][4]= +{ + {0,2,4,6},{0,3,5,7},{0,3,4,7},{0,3,4,7}, + {0,10,12,14},{0,11,13,15},{0,11,12,15},{0,11,12,15} +};*/ + +void tandy_poll(void *p) +{ +// int *cgapal=cga4pal[((tandy->col&0x10)>>2)|((cgamode&4)>>1)|((cgacol&0x20)>>5)]; + tandy_t *tandy = (tandy_t *)p; + uint16_t ca = (tandy->crtc[15] | (tandy->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + uint16_t dat; + int cols[4]; + int col; + int oldsc; + int y_buf[8] = {0, 0, 0, 0, 0, 0, 0, 0}, y_val, y_tot; + int i_buf[8] = {0, 0, 0, 0, 0, 0, 0, 0}, i_val, i_tot; + int q_buf[8] = {0, 0, 0, 0, 0, 0, 0, 0}, q_val, q_tot; + int r, g, b; + if (!tandy->linepos) + { +// cgapal[0]=tandy->col&15; +// printf("Firstline %i Lastline %i tandy->displine %i\n",firstline,lastline,tandy->displine); + tandy->vidtime += tandy->dispofftime; + tandy->stat |= 1; + tandy->linepos = 1; + oldsc = tandy->sc; + if ((tandy->crtc[8] & 3) == 3) + tandy->sc = (tandy->sc << 1) & 7; + if (tandy->dispon) + { + if (tandy->displine < tandy->firstline) + { + tandy->firstline = tandy->displine; +// printf("Firstline %i\n",firstline); + } + tandy->lastline = tandy->displine; + cols[0] = (tandy->array[2] & 0xf) + 16; + for (c = 0; c < 8; c++) + { + if (tandy->array[3] & 4) + { + buffer->line[tandy->displine][c] = cols[0]; + if (tandy->mode & 1) buffer->line[tandy->displine][c + (tandy->crtc[1] << 3) + 8] = cols[0]; + else buffer->line[tandy->displine][c + (tandy->crtc[1] << 4) + 8] = cols[0]; + } + else if ((tandy->mode & 0x12) == 0x12) + { + buffer->line[tandy->displine][c] = 0; + if (tandy->mode & 1) buffer->line[tandy->displine][c + (tandy->crtc[1] << 3) + 8] = 0; + else buffer->line[tandy->displine][c + (tandy->crtc[1] << 4) + 8] = 0; + } + else + { + buffer->line[tandy->displine][c] = (tandy->col & 15) + 16; + if (tandy->mode & 1) buffer->line[tandy->displine][c + (tandy->crtc[1] << 3) + 8] = (tandy->col & 15) + 16; + else buffer->line[tandy->displine][c + (tandy->crtc[1] << 4) + 8] = (tandy->col & 15) + 16; + } + } +// printf("X %i %i\n",c+(crtc[1]<<4)+8,c+(crtc[1]<<3)+8); +// printf("Drawing %i %i %i\n",tandy->displine,vc,sc); + if ((tandy->array[3] & 0x10) && (tandy->mode & 1)) /*320x200x16*/ + { + for (x = 0; x < tandy->crtc[1]; x++) + { + dat = (tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 3) * 0x2000)] << 8) | + tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 3) * 0x2000) + 1]; + tandy->ma++; + buffer->line[tandy->displine][(x << 3) + 8] = + buffer->line[tandy->displine][(x << 3) + 9] = tandy->array[((dat >> 12) & tandy->array[1]) + 16] + 16; + buffer->line[tandy->displine][(x << 3) + 10] = + buffer->line[tandy->displine][(x << 3) + 11] = tandy->array[((dat >> 8) & tandy->array[1]) + 16] + 16; + buffer->line[tandy->displine][(x << 3) + 12] = + buffer->line[tandy->displine][(x << 3) + 13] = tandy->array[((dat >> 4) & tandy->array[1]) + 16] + 16; + buffer->line[tandy->displine][(x << 3) + 14] = + buffer->line[tandy->displine][(x << 3) + 15] = tandy->array[(dat & tandy->array[1]) + 16] + 16; + } + } + else if (tandy->array[3] & 0x10) /*160x200x16*/ + { + for (x = 0; x < tandy->crtc[1]; x++) + { + dat = (tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 3) * 0x2000)] << 8) | + tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 3) * 0x2000) + 1]; + tandy->ma++; + buffer->line[tandy->displine][(x << 4) + 8] = + buffer->line[tandy->displine][(x << 4) + 9] = + buffer->line[tandy->displine][(x << 4) + 10] = + buffer->line[tandy->displine][(x << 4) + 11] = tandy->array[((dat >> 12) & tandy->array[1]) + 16] + 16; + buffer->line[tandy->displine][(x << 4) + 12] = + buffer->line[tandy->displine][(x << 4) + 13] = + buffer->line[tandy->displine][(x << 4) + 14] = + buffer->line[tandy->displine][(x << 4) + 15] = tandy->array[((dat >> 8) & tandy->array[1]) + 16] + 16; + buffer->line[tandy->displine][(x << 4) + 16] = + buffer->line[tandy->displine][(x << 4) + 17] = + buffer->line[tandy->displine][(x << 4) + 18] = + buffer->line[tandy->displine][(x << 4) + 19] = tandy->array[((dat >> 4) & tandy->array[1]) + 16] + 16; + buffer->line[tandy->displine][(x << 4) + 20] = + buffer->line[tandy->displine][(x << 4) + 21] = + buffer->line[tandy->displine][(x << 4) + 22] = + buffer->line[tandy->displine][(x << 4) + 23] = tandy->array[(dat & tandy->array[1]) + 16] + 16; + } + } + else if (tandy->array[3] & 0x08) /*640x200x4 - this implementation is a complete guess!*/ + { + for (x = 0; x < tandy->crtc[1]; x++) + { + dat = (tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 3) * 0x2000)] << 8) | + tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 3) * 0x2000) + 1]; + tandy->ma++; + for (c = 0; c < 8; c++) + { + chr = (dat >> 7) & 1; + chr |= ((dat >> 14) & 2); + buffer->line[tandy->displine][(x << 3) + 8 + c] = tandy->array[(chr & tandy->array[1]) + 16] + 16; + dat <<= 1; + } + } + } + else if (tandy->mode & 1) + { + for (x = 0; x < tandy->crtc[1]; x++) + { + chr = tandy->vram[ (tandy->ma << 1) & 0x3fff]; + attr = tandy->vram[((tandy->ma << 1) + 1) & 0x3fff]; + drawcursor = ((tandy->ma == ca) && tandy->con && tandy->cursoron); + if (tandy->mode & 0x20) + { + cols[1] = tandy->array[ ((attr & 15) & tandy->array[1]) + 16] + 16; + cols[0] = tandy->array[(((attr >> 4) & 7) & tandy->array[1]) + 16] + 16; + if ((tandy->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } + else + { + cols[1] = tandy->array[((attr & 15) & tandy->array[1]) + 16] + 16; + cols[0] = tandy->array[((attr >> 4) & tandy->array[1]) + 16] + 16; + } + if (tandy->sc & 8) + { + for (c = 0; c < 8; c++) + buffer->line[tandy->displine][(x << 3) + c + 8] = cols[0]; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[tandy->displine][(x << 3) + c + 8] = cols[(fontdat[chr][tandy->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } +// if (!((ma^(crtc[15]|(crtc[14]<<8)))&0x3FFF)) printf("Cursor match! %04X\n",ma); + if (drawcursor) + { + for (c = 0; c < 8; c++) + buffer->line[tandy->displine][(x << 3) + c + 8] ^= 15; + } + tandy->ma++; + } + } + else if (!(tandy->mode & 2)) + { + for (x = 0; x < tandy->crtc[1]; x++) + { + chr = tandy->vram[ (tandy->ma << 1) & 0x3fff]; + attr = tandy->vram[((tandy->ma << 1) + 1) & 0x3fff]; + drawcursor = ((tandy->ma == ca) && tandy->con && tandy->cursoron); + if (tandy->mode & 0x20) + { + cols[1] = tandy->array[ ((attr & 15) & tandy->array[1]) + 16] + 16; + cols[0] = tandy->array[(((attr >> 4) & 7) & tandy->array[1]) + 16] + 16; + if ((tandy->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } + else + { + cols[1] = tandy->array[((attr & 15) & tandy->array[1]) + 16] + 16; + cols[0] = tandy->array[((attr >> 4) & tandy->array[1]) + 16] + 16; + } + tandy->ma++; + if (tandy->sc & 8) + { + for (c = 0; c < 8; c++) + buffer->line[tandy->displine][(x << 4) + (c << 1) + 8] = + buffer->line[tandy->displine][(x << 4) + (c << 1) + 1 + 8] = cols[0]; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[tandy->displine][(x << 4) + (c << 1) + 8] = + buffer->line[tandy->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][tandy->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + if (drawcursor) + { + for (c = 0; c < 16; c++) + buffer->line[tandy->displine][(x << 4) + c + 8] ^= 15; + } + } + } + else if (!(tandy->mode& 16)) + { + cols[0] = (tandy->col & 15) | 16; + col = (tandy->col & 16) ? 24 : 16; + if (tandy->mode & 4) + { + cols[1] = col | 3; + cols[2] = col | 4; + cols[3] = col | 7; + } + else if (tandy->col & 32) + { + cols[1] = col | 3; + cols[2] = col | 5; + cols[3] = col | 7; + } + else + { + cols[1] = col | 2; + cols[2] = col | 4; + cols[3] = col | 6; + } + for (x = 0; x < tandy->crtc[1]; x++) + { + dat = (tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 1) * 0x2000)] << 8) | + tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 1) * 0x2000) + 1]; + tandy->ma++; + for (c = 0; c < 8; c++) + { + buffer->line[tandy->displine][(x << 4) + (c << 1) + 8] = + buffer->line[tandy->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + dat <<= 2; + } + } + } + else + { + cols[0] = 0; + cols[1] = tandy->array[(tandy->col & tandy->array[1]) + 16] + 16; + for (x = 0; x < tandy->crtc[1]; x++) + { + dat = (tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 1) * 0x2000)] << 8) | + tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 1) * 0x2000) + 1]; + tandy->ma++; + for (c = 0; c < 16; c++) + { + buffer->line[tandy->displine][(x << 4) + c + 8] = cols[dat >> 15]; + dat <<= 1; + } + } + } + } + else + { + if (tandy->array[3] & 4) + { + if (tandy->mode & 1) hline(buffer, 0, tandy->displine, (tandy->crtc[1] << 3) + 16, (tandy->array[2] & 0xf) + 16); + else hline(buffer, 0, tandy->displine, (tandy->crtc[1] << 4) + 16, (tandy->array[2] & 0xf) + 16); + } + else + { + cols[0] = ((tandy->mode & 0x12) == 0x12) ? 0 : (tandy->col & 0xf) + 16; + if (tandy->mode & 1) hline(buffer, 0, tandy->displine, (tandy->crtc[1] << 3) + 16, cols[0]); + else hline(buffer, 0, tandy->displine, (tandy->crtc[1] << 4) + 16, cols[0]); + } + } + if (tandy->mode & 1) x = (tandy->crtc[1] << 3) + 16; + else x = (tandy->crtc[1] << 4) + 16; + if (cga_comp) + { + for (c = 0; c < x; c++) + { + y_buf[(c << 1) & 6] = ntsc_col[buffer->line[tandy->displine][c] & 7][(c << 1) & 6] ? 0x6000 : 0; + y_buf[(c << 1) & 6] += (buffer->line[tandy->displine][c] & 8) ? 0x3000 : 0; + i_buf[(c << 1) & 6] = y_buf[(c << 1) & 6] * i_filt[(c << 1) & 6]; + q_buf[(c << 1) & 6] = y_buf[(c << 1) & 6] * q_filt[(c << 1) & 6]; + y_tot = y_buf[0] + y_buf[1] + y_buf[2] + y_buf[3] + y_buf[4] + y_buf[5] + y_buf[6] + y_buf[7]; + i_tot = i_buf[0] + i_buf[1] + i_buf[2] + i_buf[3] + i_buf[4] + i_buf[5] + i_buf[6] + i_buf[7]; + q_tot = q_buf[0] + q_buf[1] + q_buf[2] + q_buf[3] + q_buf[4] + q_buf[5] + q_buf[6] + q_buf[7]; + + y_val = y_tot >> 10; + if (y_val > 255) y_val = 255; + y_val <<= 16; + i_val = i_tot >> 12; + if (i_val > 39041) i_val = 39041; + if (i_val < -39041) i_val = -39041; + q_val = q_tot >> 12; + if (q_val > 34249) q_val = 34249; + if (q_val < -34249) q_val = -34249; + + r = (y_val + 249*i_val + 159*q_val) >> 16; + g = (y_val - 70*i_val - 166*q_val) >> 16; + b = (y_val - 283*i_val + 436*q_val) >> 16; + + y_buf[((c << 1) & 6) + 1] = ntsc_col[buffer->line[tandy->displine][c] & 7][((c << 1) & 6) + 1] ? 0x6000 : 0; + y_buf[((c << 1) & 6) + 1] += (buffer->line[tandy->displine][c] & 8) ? 0x3000 : 0; + i_buf[((c << 1) & 6) + 1] = y_buf[((c << 1) & 6) + 1] * i_filt[((c << 1) & 6) + 1]; + q_buf[((c << 1) & 6) + 1] = y_buf[((c << 1) & 6) + 1] * q_filt[((c << 1) & 6) + 1]; + y_tot = y_buf[0] + y_buf[1] + y_buf[2] + y_buf[3] + y_buf[4] + y_buf[5] + y_buf[6] + y_buf[7]; + i_tot = i_buf[0] + i_buf[1] + i_buf[2] + i_buf[3] + i_buf[4] + i_buf[5] + i_buf[6] + i_buf[7]; + q_tot = q_buf[0] + q_buf[1] + q_buf[2] + q_buf[3] + q_buf[4] + q_buf[5] + q_buf[6] + q_buf[7]; + + y_val = y_tot >> 10; + if (y_val > 255) y_val = 255; + y_val <<= 16; + i_val = i_tot >> 12; + if (i_val > 39041) i_val = 39041; + if (i_val < -39041) i_val = -39041; + q_val = q_tot >> 12; + if (q_val > 34249) q_val = 34249; + if (q_val < -34249) q_val = -34249; + + r = (y_val + 249*i_val + 159*q_val) >> 16; + g = (y_val - 70*i_val - 166*q_val) >> 16; + b = (y_val - 283*i_val + 436*q_val) >> 16; + if (r > 511) r = 511; + if (g > 511) g = 511; + if (b > 511) b = 511; + + ((uint32_t *)buffer32->line[tandy->displine])[c] = makecol32(r / 2, g / 2, b / 2); + } + } + tandy->sc = oldsc; + if (tandy->vc == tandy->crtc[7] && !tandy->sc) + { + tandy->stat |= 8; +// printf("VSYNC on %i %i\n",vc,sc); + } + tandy->displine++; + if (tandy->displine >= 360) + tandy->displine = 0; + } + else + { + tandy->vidtime += tandy->dispontime; + if (tandy->dispon) + tandy->stat &= ~1; + tandy->linepos = 0; + if (tandy->vsynctime) + { + tandy->vsynctime--; + if (!tandy->vsynctime) + { + tandy->stat &= ~8; +// printf("VSYNC off %i %i\n",vc,sc); + } + } + if (tandy->sc == (tandy->crtc[11] & 31) || ((tandy->crtc[8] & 3) == 3 && tandy->sc == ((tandy->crtc[11] & 31) >> 1))) + { + tandy->con = 0; + tandy->coff = 1; + } + if (tandy->vadj) + { + tandy->sc++; + tandy->sc &= 31; + tandy->ma = tandy->maback; + tandy->vadj--; + if (!tandy->vadj) + { + tandy->dispon = 1; + tandy->ma = tandy->maback = (tandy->crtc[13] | (tandy->crtc[12] << 8)) & 0x3fff; + tandy->sc = 0; +// printf("Display on!\n"); + } + } + else if (tandy->sc == tandy->crtc[9] || ((tandy->crtc[8] & 3) == 3 && tandy->sc == (tandy->crtc[9] >> 1))) + { + tandy->maback = tandy->ma; +// con=0; +// coff=0; + tandy->sc = 0; + oldvc = tandy->vc; + tandy->vc++; + tandy->vc &= 127; +// printf("VC %i %i %i %i %i\n",vc,crtc[4],crtc[6],crtc[7],tandy->dispon); + if (tandy->vc == tandy->crtc[6]) + tandy->dispon = 0; + if (oldvc == tandy->crtc[4]) + { +// printf("Display over at %i\n",tandy->displine); + tandy->vc = 0; + tandy->vadj = tandy->crtc[5]; + if (!tandy->vadj) + tandy->dispon = 1; + if (!tandy->vadj) + tandy->ma = tandy->maback = (tandy->crtc[13] | (tandy->crtc[12] << 8)) & 0x3fff; + if ((tandy->crtc[10] & 0x60) == 0x20) tandy->cursoron = 0; + else tandy->cursoron = tandy->blink & 16; +// printf("CRTC10 %02X %i\n",crtc[10],cursoron); + } + if (tandy->vc == tandy->crtc[7]) + { + tandy->dispon = 0; + tandy->displine = 0; + tandy->vsynctime = 16;//(crtc[3]>>4)+1; +// printf("tandy->vsynctime %i %02X\n",tandy->vsynctime,crtc[3]); +// tandy->stat|=8; + if (tandy->crtc[7]) + { +// printf("Lastline %i Firstline %i %i %i %i\n",lastline,firstline,lastline-firstline,crtc[1],xsize); + if (tandy->mode & 1) x = (tandy->crtc[1] << 3) + 16; + else x = (tandy->crtc[1] << 4) + 16; + tandy->lastline++; + if (x != xsize || (tandy->lastline - tandy->firstline) != ysize) + { + xsize = x; + ysize = tandy->lastline - tandy->firstline; +// printf("Resize to %i,%i - R1 %i\n",xsize,ysize,crtc[1]); + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + updatewindowsize(xsize, (ysize << 1) + 16); + } +// printf("Blit %i %i\n",firstline,lastline); +//printf("Xsize is %i\n",xsize); + startblit(); + if (cga_comp) + video_blit_memtoscreen(0, tandy->firstline-4, 0, (tandy->lastline - tandy->firstline) + 8, xsize, (tandy->lastline - tandy->firstline) + 8); + else + video_blit_memtoscreen_8(0, tandy->firstline-4, xsize, (tandy->lastline - tandy->firstline) + 8); + endblit(); + frames++; + video_res_x = xsize - 16; + video_res_y = ysize; + if ((tandy->array[3] & 0x10) && (tandy->mode & 1)) /*320x200x16*/ + { + video_res_x /= 2; + video_bpp = 4; + } + else if (tandy->array[3] & 0x10) /*160x200x16*/ + { + video_res_x /= 4; + video_bpp = 4; + } + else if (tandy->array[3] & 0x08) /*640x200x4 - this implementation is a complete guess!*/ + video_bpp = 2; + else if (tandy->mode & 1) + { + video_res_x /= 8; + video_res_y /= tandy->crtc[9] + 1; + video_bpp = 0; + } + else if (!(tandy->mode & 2)) + { + video_res_x /= 16; + video_res_y /= tandy->crtc[9] + 1; + video_bpp = 0; + } + else if (!(tandy->mode & 16)) + { + video_res_x /= 2; + video_bpp = 2; + } + else + video_bpp = 1; + } + tandy->firstline = 1000; + tandy->lastline = 0; + tandy->blink++; + } + } + else + { + tandy->sc++; + tandy->sc &= 31; + tandy->ma = tandy->maback; + } + if ((tandy->sc == (tandy->crtc[10] & 31) || ((tandy->crtc[8] & 3) == 3 && tandy->sc == ((tandy->crtc[10] & 31) >> 1)))) + tandy->con = 1; + } +} + +void *tandy_init() +{ + int c; + int tandy_tint = -2; + tandy_t *tandy = malloc(sizeof(tandy_t)); + memset(tandy, 0, sizeof(tandy_t)); + + tandy->memctrl = -1; + tandy->base = (mem_size - 128) * 1024; + + for (c = 0; c < 8; c++) + { + i_filt[c] = 512.0 * cos((3.14 * (tandy_tint + c * 4) / 16.0) - 33.0 / 180.0); + q_filt[c] = 512.0 * sin((3.14 * (tandy_tint + c * 4) / 16.0) - 33.0 / 180.0); + } + timer_add(tandy_poll, &tandy->vidtime, TIMER_ALWAYS_ENABLED, tandy); + mem_mapping_add(&tandy->mapping, 0xb8000, 0x08000, tandy_read, NULL, NULL, tandy_write, NULL, NULL, NULL, 0, tandy); + mem_mapping_add(&tandy->ram_mapping, 0x80000, 0x20000, tandy_ram_read, NULL, NULL, tandy_ram_write, NULL, NULL, NULL, 0, tandy); + /*Base 128k mapping is controlled via port 0xA0, so we remove it from the main mapping*/ + mem_mapping_set_addr(&ram_low_mapping, 0, (mem_size - 128) * 1024); + io_sethandler(0x03d0, 0x0010, tandy_in, NULL, NULL, tandy_out, NULL, NULL, tandy); + io_sethandler(0x00a0, 0x0001, tandy_in, NULL, NULL, tandy_out, NULL, NULL, tandy); + tandy->b8000_mask = 0x3fff; + + overscan_x = overscan_y = 16; + + return tandy; +} + +void tandy_close(void *p) +{ + tandy_t *tandy = (tandy_t *)p; + + free(tandy); +} + +void tandy_speed_changed(void *p) +{ + tandy_t *tandy = (tandy_t *)p; + + tandy_recalctimings(tandy); +} + +device_t tandy_device = +{ + "Tandy 1000 (video)", + 0, + tandy_init, + tandy_close, + NULL, + tandy_speed_changed, + NULL, + NULL +}; diff --git a/src/vid_tandy.h b/src/vid_tandy.h new file mode 100644 index 000000000..67e3bc5cf --- /dev/null +++ b/src/vid_tandy.h @@ -0,0 +1 @@ +extern device_t tandy_device; diff --git a/src/vid_tandysl.c b/src/vid_tandysl.c new file mode 100644 index 000000000..ece4e1fb0 --- /dev/null +++ b/src/vid_tandysl.c @@ -0,0 +1,733 @@ +#include +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "timer.h" +#include "video.h" +#include "vid_tandysl.h" + +typedef struct tandysl_t +{ + mem_mapping_t mapping; + mem_mapping_t ram_mapping; + mem_mapping_t vram_mapping; + + uint8_t crtc[32]; + int crtcreg; + + int array_index; + uint8_t array[32]; + int memctrl;//=-1; + uint32_t base; + uint8_t mode, col; + uint8_t stat; + + uint8_t *vram, *b8000; + uint32_t b8000_limit; + uint8_t planar_ctrl; + + int linepos, displine; + int sc, vc; + int dispon; + int con, coff, cursoron, blink; + int vsynctime, vadj; + uint16_t ma, maback; + + int dispontime, dispofftime, vidtime; + int firstline, lastline; +} tandysl_t; + +static uint8_t crtcmask[32] = +{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xf3, 0x1f, 0x7f, 0x1f, 0x3f, 0xff, 0x3f, 0xff, + 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static void tandysl_recalcaddress(tandysl_t *tandy); +static void tandysl_recalctimings(tandysl_t *tandy); +static void tandysl_recalcmapping(tandysl_t *tandy); +static uint8_t tandysl_in(uint16_t addr, void *p); +static void tandysl_ram_write(uint32_t addr, uint8_t val, void *p); +static void tandysl_write(uint32_t addr, uint8_t val, void *p); + +static void tandysl_out(uint16_t addr, uint8_t val, void *p) +{ + tandysl_t *tandy = (tandysl_t *)p; + uint8_t old; +// pclog("TandySL OUT %04X %02X\n",addr,val); + switch (addr) + { + case 0x3d4: + tandy->crtcreg = val & 0x1f; + return; + case 0x3d5: +// pclog("Write CRTC R%02x %02x ",tandy->crtcreg, val); + old = tandy->crtc[tandy->crtcreg]; + tandy->crtc[tandy->crtcreg] = val & crtcmask[tandy->crtcreg]; +// pclog("now %02x\n", tandy->crtc[tandy->crtcreg]); + if (old != val) + { + if (tandy->crtcreg < 0xe || tandy->crtcreg > 0x10) + { + fullchange = changeframecount; + tandysl_recalctimings(tandy); + } + } + return; + case 0x3d8: + tandy->mode = val; + return; + case 0x3d9: + tandy->col = val; + return; + case 0x3da: + tandy->array_index = val & 0x1f; + break; + case 0x3de: + if (tandy->array_index & 16) + val &= 0xf; + tandy->array[tandy->array_index & 0x1f] = val; + if ((tandy->array_index & 0x1f) == 5) + { + tandysl_recalcmapping(tandy); + tandysl_recalcaddress(tandy); + } + break; + case 0x3df: + tandy->memctrl = val; +// pclog("tandy 3df write %02x\n", val); + tandysl_recalcaddress(tandy); + break; + case 0x65: + if (val == 8) /*Hack*/ + return; + tandy->planar_ctrl = val; + tandysl_recalcmapping(tandy); + break; + case 0xffe8: + if ((val & 0xe) == 0xe) + mem_mapping_disable(&tandy->ram_mapping); + else + mem_mapping_set_addr(&tandy->ram_mapping, ((val >> 1) & 7) * 128 * 1024, 0x20000); + tandysl_recalcaddress(tandy); + break; + } +} + +static uint8_t tandysl_in(uint16_t addr, void *p) +{ + tandysl_t *tandy = (tandysl_t *)p; +// if (addr!=0x3DA) pclog("Tandy IN %04X\n",addr); + switch (addr) + { + case 0x3d4: + return tandy->crtcreg; + case 0x3d5: + return tandy->crtc[tandy->crtcreg]; + case 0x3da: + return tandy->stat; + } +// pclog("Bad Tandy IN %04x\n", addr); + return 0xFF; +} + +static void tandysl_recalcaddress(tandysl_t *tandy) +{ + tandy->b8000_limit = 0x8000; + if (tandy->array[5] & 1) + { + tandy->vram = &ram[((tandy->memctrl & 0x04) << 14) + tandy->base]; + tandy->b8000 = &ram[((tandy->memctrl & 0x20) << 11) + tandy->base]; + } + else if ((tandy->memctrl & 0xc0) == 0xc0) + { + tandy->vram = &ram[((tandy->memctrl & 0x06) << 14) + tandy->base]; + tandy->b8000 = &ram[((tandy->memctrl & 0x30) << 11) + tandy->base]; +// printf("VRAM at %05X B8000 at %05X\n",((tandy->memctrl&0x6)<<14)+tandy->base,((tandy->memctrl&0x30)<<11)+tandy->base); + } + else + { + tandy->vram = &ram[((tandy->memctrl & 0x07) << 14) + tandy->base]; + tandy->b8000 = &ram[((tandy->memctrl & 0x38) << 11) + tandy->base]; +// printf("VRAM at %05X B8000 at %05X\n",((tandy->memctrl&0x7)<<14)+tandy->base,((tandy->memctrl&0x38)<<11)+tandy->base); + if ((tandy->memctrl & 0x38) == 0x38) + tandy->b8000_limit = 0x4000; + } +} + +static void tandysl_recalcmapping(tandysl_t *tandy) +{ + mem_mapping_disable(&tandy->mapping); + io_removehandler(0x03d0, 0x0010, tandysl_in, NULL, NULL, tandysl_out, NULL, NULL, tandy); + if (tandy->planar_ctrl & 4) + { +// pclog("Enable VRAM mapping\n"); + mem_mapping_enable(&tandy->mapping); + if (tandy->array[5] & 1) + { +// pclog("Tandy mapping at A0000 %p %p\n", tandy_ram_write, tandy_write); + mem_mapping_set_addr(&tandy->mapping, 0xa0000, 0x10000); + } + else + { +// pclog("Tandy mapping at B8000\n"); + mem_mapping_set_addr(&tandy->mapping, 0xb8000, 0x8000); + } +// mem_mapping_enable(&tandy->vram_mapping); + io_sethandler(0x03d0, 0x0010, tandysl_in, NULL, NULL, tandysl_out, NULL, NULL, tandy); + } + else + { +// pclog("Disable VRAM mapping\n"); + mem_mapping_disable(&tandy->mapping); +// mem_mapping_disable(&tandy->vram_mapping); + io_removehandler(0x03d0, 0x0010, tandysl_in, NULL, NULL, tandysl_out, NULL, NULL, tandy); + } +} +static void tandysl_ram_write(uint32_t addr, uint8_t val, void *p) +{ + tandysl_t *tandy = (tandysl_t *)p; +// pclog("Tandy RAM write %05X %02X %04X:%04X %08x\n",addr,val,CS,pc, tandy->base); + ram[tandy->base + (addr & 0x1ffff)] = val; +} + +static uint8_t tandysl_ram_read(uint32_t addr, void *p) +{ + tandysl_t *tandy = (tandysl_t *)p; +// if (!nopageerrors) pclog("Tandy RAM read %05X %02X %04X:%04X\n",addr,ram[tandy->base + (addr & 0x1ffff)],CS,pc); + return ram[tandy->base + (addr & 0x1ffff)]; +} + +static void tandysl_write(uint32_t addr, uint8_t val, void *p) +{ + tandysl_t *tandy = (tandysl_t *)p; + if (tandy->memctrl == -1) + return; + + egawrites++; +// pclog("Tandy VRAM write %05X %02X %04X:%04X %02x %x\n",addr,val,CS,pc,tandy->array[5], (uintptr_t)&tandy->b8000[addr & 0xffff] - (uintptr_t)ram); + if (tandy->array[5] & 1) + tandy->b8000[addr & 0xffff] = val; + else + { + if ((addr & 0x7fff) >= tandy->b8000_limit) + return; + tandy->b8000[addr & 0x7fff] = val; + } +} + +static uint8_t tandysl_read(uint32_t addr, void *p) +{ + tandysl_t *tandy = (tandysl_t *)p; + if (tandy->memctrl == -1) + return 0xff; + + egareads++; +// if (!nopageerrors) pclog("Tandy VRAM read %05X %02X %04X:%04X\n",addr,tandy->b8000[addr&0x7FFF],CS,pc); + if (tandy->array[5] & 1) + return tandy->b8000[addr & 0xffff]; + if ((addr & 0x7fff) >= tandy->b8000_limit) + return 0xff; + return tandy->b8000[addr & 0x7fff]; +} + +static void tandysl_recalctimings(tandysl_t *tandy) +{ + double _dispontime, _dispofftime, disptime; + if (tandy->mode & 1) + { + disptime = tandy->crtc[0] + 1; + _dispontime = tandy->crtc[1]; + } + else + { + disptime = (tandy->crtc[0] + 1) << 1; + _dispontime = tandy->crtc[1] << 1; + } + _dispofftime = disptime - _dispontime; + _dispontime *= CGACONST; + _dispofftime *= CGACONST; + tandy->dispontime = (int)(_dispontime * (1 << TIMER_SHIFT)); + tandy->dispofftime = (int)(_dispofftime * (1 << TIMER_SHIFT)); +} + + +static void tandysl_poll(void *p) +{ + tandysl_t *tandy = (tandysl_t *)p; + uint16_t ca = (tandy->crtc[15] | (tandy->crtc[14] << 8)) & 0x3fff; + int drawcursor; + int x, c; + int oldvc; + uint8_t chr, attr; + uint16_t dat; + int cols[4]; + int col; + int oldsc; + + if (!tandy->linepos) + { +// pclog("tandy_poll vc=%i sc=%i dispon=%i\n", tandy->vc, tandy->sc, tandy->dispon); +// cgapal[0]=tandy->col&15; +// printf("Firstline %i Lastline %i tandy->displine %i\n",firstline,lastline,tandy->displine); + tandy->vidtime += tandy->dispofftime; + tandy->stat |= 1; + tandy->linepos = 1; + oldsc = tandy->sc; + if ((tandy->crtc[8] & 3) == 3) + tandy->sc = (tandy->sc << 1) & 7; + if (tandy->dispon) + { + if (tandy->displine < tandy->firstline) + { + tandy->firstline = tandy->displine; +// printf("Firstline %i\n",firstline); + } + tandy->lastline = tandy->displine; + cols[0] = (tandy->array[2] & 0xf) + 16; + for (c = 0; c < 8; c++) + { + if (tandy->array[3] & 4) + { + buffer->line[tandy->displine][c] = cols[0]; + if (tandy->mode & 1) buffer->line[tandy->displine][c + (tandy->crtc[1] << 3) + 8] = cols[0]; + else buffer->line[tandy->displine][c + (tandy->crtc[1] << 4) + 8] = cols[0]; + } + else if ((tandy->mode & 0x12) == 0x12) + { + buffer->line[tandy->displine][c] = 0; + if (tandy->mode & 1) buffer->line[tandy->displine][c + (tandy->crtc[1] << 3) + 8] = 0; + else buffer->line[tandy->displine][c + (tandy->crtc[1] << 4) + 8] = 0; + } + else + { + buffer->line[tandy->displine][c] = (tandy->col & 15) + 16; + if (tandy->mode & 1) buffer->line[tandy->displine][c + (tandy->crtc[1] << 3) + 8] = (tandy->col & 15) + 16; + else buffer->line[tandy->displine][c + (tandy->crtc[1] << 4) + 8] = (tandy->col & 15) + 16; + } + } + if (tandy->array[5] & 1) /*640x200x16*/ + { + for (x = 0; x < tandy->crtc[1]*2; x++) + { + dat = (tandy->vram[(tandy->ma << 1) & 0xffff] << 8) | + tandy->vram[((tandy->ma << 1) + 1) & 0xffff]; + tandy->ma++; + buffer->line[tandy->displine][(x << 2) + 8] = tandy->array[((dat >> 12) & 0xf)/*tandy->array[1])*/ + 16] + 16; + buffer->line[tandy->displine][(x << 2) + 9] = tandy->array[((dat >> 8) & 0xf)/*tandy->array[1])*/ + 16] + 16; + buffer->line[tandy->displine][(x << 2) + 10] = tandy->array[((dat >> 4) & 0xf)/*tandy->array[1])*/ + 16] + 16; + buffer->line[tandy->displine][(x << 2) + 11] = tandy->array[(dat & 0xf)/*tandy->array[1])*/ + 16] + 16; + } + } + else if ((tandy->array[3] & 0x10) && (tandy->mode & 1)) /*320x200x16*/ + { + for (x = 0; x < tandy->crtc[1]; x++) + { + dat = (tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 3) * 0x2000)] << 8) | + tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 3) * 0x2000) + 1]; + tandy->ma++; + buffer->line[tandy->displine][(x << 3) + 8] = + buffer->line[tandy->displine][(x << 3) + 9] = tandy->array[((dat >> 12) & tandy->array[1]) + 16] + 16; + buffer->line[tandy->displine][(x << 3) + 10] = + buffer->line[tandy->displine][(x << 3) + 11] = tandy->array[((dat >> 8) & tandy->array[1]) + 16] + 16; + buffer->line[tandy->displine][(x << 3) + 12] = + buffer->line[tandy->displine][(x << 3) + 13] = tandy->array[((dat >> 4) & tandy->array[1]) + 16] + 16; + buffer->line[tandy->displine][(x << 3) + 14] = + buffer->line[tandy->displine][(x << 3) + 15] = tandy->array[(dat & tandy->array[1]) + 16] + 16; + } + } + else if (tandy->array[3] & 0x10) /*160x200x16*/ + { + for (x = 0; x < tandy->crtc[1]; x++) + { + dat = (tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 1) * 0x2000)] << 8) | + tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 1) * 0x2000) + 1]; + tandy->ma++; + buffer->line[tandy->displine][(x << 4) + 8] = + buffer->line[tandy->displine][(x << 4) + 9] = + buffer->line[tandy->displine][(x << 4) + 10] = + buffer->line[tandy->displine][(x << 4) + 11] = tandy->array[((dat >> 12) & tandy->array[1]) + 16] + 16; + buffer->line[tandy->displine][(x << 4) + 12] = + buffer->line[tandy->displine][(x << 4) + 13] = + buffer->line[tandy->displine][(x << 4) + 14] = + buffer->line[tandy->displine][(x << 4) + 15] = tandy->array[((dat >> 8) & tandy->array[1]) + 16] + 16; + buffer->line[tandy->displine][(x << 4) + 16] = + buffer->line[tandy->displine][(x << 4) + 17] = + buffer->line[tandy->displine][(x << 4) + 18] = + buffer->line[tandy->displine][(x << 4) + 19] = tandy->array[((dat >> 4) & tandy->array[1]) + 16] + 16; + buffer->line[tandy->displine][(x << 4) + 20] = + buffer->line[tandy->displine][(x << 4) + 21] = + buffer->line[tandy->displine][(x << 4) + 22] = + buffer->line[tandy->displine][(x << 4) + 23] = tandy->array[(dat & tandy->array[1]) + 16] + 16; + } + } + else if (tandy->array[3] & 0x08) /*640x200x4 - this implementation is a complete guess!*/ + { + for (x = 0; x < tandy->crtc[1]; x++) + { + dat = (tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 3) * 0x2000)] << 8) | + tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 3) * 0x2000) + 1]; + tandy->ma++; + for (c = 0; c < 8; c++) + { + chr = (dat >> 7) & 1; + chr |= ((dat >> 14) & 2); + buffer->line[tandy->displine][(x << 3) + 8 + c] = tandy->array[(chr & tandy->array[1]) + 16] + 16; + dat <<= 1; + } + } + } + else if (tandy->mode & 1) + { + for (x = 0; x < tandy->crtc[1]; x++) + { + chr = tandy->vram[ (tandy->ma << 1) & 0x3fff]; + attr = tandy->vram[((tandy->ma << 1) + 1) & 0x3fff]; + drawcursor = ((tandy->ma == ca) && tandy->con && tandy->cursoron); + if (tandy->mode & 0x20) + { + cols[1] = tandy->array[ ((attr & 15) & tandy->array[1]) + 16] + 16; + cols[0] = tandy->array[(((attr >> 4) & 7) & tandy->array[1]) + 16] + 16; + if ((tandy->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } + else + { + cols[1] = tandy->array[((attr & 15) & tandy->array[1]) + 16] + 16; + cols[0] = tandy->array[((attr >> 4) & tandy->array[1]) + 16] + 16; + } + if (tandy->sc & 8) + { + for (c = 0; c < 8; c++) + buffer->line[tandy->displine][(x << 3) + c + 8] = cols[0]; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[tandy->displine][(x << 3) + c + 8] = cols[(fontdat[chr][tandy->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } +// if (!((ma^(crtc[15]|(crtc[14]<<8)))&0x3FFF)) printf("Cursor match! %04X\n",ma); + if (drawcursor) + { + for (c = 0; c < 8; c++) + buffer->line[tandy->displine][(x << 3) + c + 8] ^= 15; + } + tandy->ma++; + } + } + else if (!(tandy->mode & 2)) + { + for (x = 0; x < tandy->crtc[1]; x++) + { + chr = tandy->vram[ (tandy->ma << 1) & 0x3fff]; + attr = tandy->vram[((tandy->ma << 1) + 1) & 0x3fff]; + drawcursor = ((tandy->ma == ca) && tandy->con && tandy->cursoron); + if (tandy->mode & 0x20) + { + cols[1] = tandy->array[ ((attr & 15) & tandy->array[1]) + 16] + 16; + cols[0] = tandy->array[(((attr >> 4) & 7) & tandy->array[1]) + 16] + 16; + if ((tandy->blink & 16) && (attr & 0x80) && !drawcursor) + cols[1] = cols[0]; + } + else + { + cols[1] = tandy->array[((attr & 15) & tandy->array[1]) + 16] + 16; + cols[0] = tandy->array[((attr >> 4) & tandy->array[1]) + 16] + 16; + } + tandy->ma++; + if (tandy->sc & 8) + { + for (c = 0; c < 8; c++) + buffer->line[tandy->displine][(x << 4) + (c << 1) + 8] = + buffer->line[tandy->displine][(x << 4) + (c << 1) + 1 + 8] = cols[0]; + } + else + { + for (c = 0; c < 8; c++) + buffer->line[tandy->displine][(x << 4) + (c << 1) + 8] = + buffer->line[tandy->displine][(x << 4) + (c << 1) + 1 + 8] = cols[(fontdat[chr][tandy->sc & 7] & (1 << (c ^ 7))) ? 1 : 0]; + } + if (drawcursor) + { + for (c = 0; c < 16; c++) + buffer->line[tandy->displine][(x << 4) + c + 8] ^= 15; + } + } + } + else if (!(tandy->mode& 16)) + { + cols[0] = (tandy->col & 15) | 16; + col = (tandy->col & 16) ? 24 : 16; + if (tandy->mode & 4) + { + cols[1] = col | 3; + cols[2] = col | 4; + cols[3] = col | 7; + } + else if (tandy->col & 32) + { + cols[1] = col | 3; + cols[2] = col | 5; + cols[3] = col | 7; + } + else + { + cols[1] = col | 2; + cols[2] = col | 4; + cols[3] = col | 6; + } + for (x = 0; x < tandy->crtc[1]; x++) + { + dat = (tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 1) * 0x2000)] << 8) | + tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 1) * 0x2000) + 1]; + tandy->ma++; + for (c = 0; c < 8; c++) + { + buffer->line[tandy->displine][(x << 4) + (c << 1) + 8] = + buffer->line[tandy->displine][(x << 4) + (c << 1) + 1 + 8] = cols[dat >> 14]; + dat <<= 2; + } + } + } + else + { + cols[0] = 0; + cols[1] = tandy->array[(tandy->col & tandy->array[1]) + 16] + 16; + for (x = 0; x < tandy->crtc[1]; x++) + { + dat = (tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 1) * 0x2000)] << 8) | + tandy->vram[((tandy->ma << 1) & 0x1fff) + ((tandy->sc & 1) * 0x2000) + 1]; + tandy->ma++; + for (c = 0; c < 16; c++) + { + buffer->line[tandy->displine][(x << 4) + c + 8] = cols[dat >> 15]; + dat <<= 1; + } + } + } + } + else + { + if (tandy->array[3] & 4) + { + if (tandy->mode & 1) hline(buffer, 0, tandy->displine, (tandy->crtc[1] << 3) + 16, (tandy->array[2] & 0xf) + 16); + else hline(buffer, 0, tandy->displine, (tandy->crtc[1] << 4) + 16, (tandy->array[2] & 0xf) + 16); + } + else + { + cols[0] = ((tandy->mode & 0x12) == 0x12) ? 0 : (tandy->col & 0xf) + 16; + if (tandy->mode & 1) hline(buffer, 0, tandy->displine, (tandy->crtc[1] << 3) + 16, cols[0]); + else hline(buffer, 0, tandy->displine, (tandy->crtc[1] << 4) + 16, cols[0]); + } + } + if (tandy->mode & 1) x = (tandy->crtc[1] << 3) + 16; + else x = (tandy->crtc[1] << 4) + 16; + tandy->sc = oldsc; + if (tandy->vc == tandy->crtc[7] && !tandy->sc) + { + tandy->stat |= 8; +// printf("VSYNC on %i %i\n",vc,sc); + } + tandy->displine++; + if (tandy->displine >= 360) + tandy->displine = 0; + } + else + { + tandy->vidtime += tandy->dispontime; + if (tandy->dispon) + tandy->stat &= ~1; + tandy->linepos = 0; + if (tandy->vsynctime) + { + tandy->vsynctime--; + if (!tandy->vsynctime) + { + tandy->stat &= ~8; +// printf("VSYNC off %i %i\n",vc,sc); + } + } + if (tandy->sc == (tandy->crtc[11] & 31) || ((tandy->crtc[8] & 3) == 3 && tandy->sc == ((tandy->crtc[11] & 31) >> 1))) + { + tandy->con = 0; + tandy->coff = 1; + } + if (tandy->vadj) + { + tandy->sc++; + tandy->sc &= 31; + tandy->ma = tandy->maback; + tandy->vadj--; + if (!tandy->vadj) + { + tandy->dispon = 1; + if (tandy->array[5] & 1) + tandy->ma = tandy->maback = tandy->crtc[13] | (tandy->crtc[12] << 8); + else + tandy->ma = tandy->maback = (tandy->crtc[13] | (tandy->crtc[12] << 8)) & 0x3fff; + tandy->sc = 0; +// printf("Display on!\n"); + } + } + else if (tandy->sc == tandy->crtc[9] || ((tandy->crtc[8] & 3) == 3 && tandy->sc == (tandy->crtc[9] >> 1))) + { + tandy->maback = tandy->ma; +// con=0; +// coff=0; + tandy->sc = 0; + oldvc = tandy->vc; + tandy->vc++; + tandy->vc &= 255; +// printf("VC %i %i %i %i %i\n",vc,crtc[4],crtc[6],crtc[7],tandy->dispon); + if (tandy->vc == tandy->crtc[6]) + { +// pclog("Display off\n"); + tandy->dispon = 0; + } + if (oldvc == tandy->crtc[4]) + { +// pclog("Display over\n"); +// printf("Display over at %i\n",tandy->displine); + tandy->vc = 0; + tandy->vadj = tandy->crtc[5]; + if (!tandy->vadj) + tandy->dispon = 1; + if (!tandy->vadj) + { + if (tandy->array[5] & 1) + tandy->ma = tandy->maback = tandy->crtc[13] | (tandy->crtc[12] << 8); + else + tandy->ma = tandy->maback = (tandy->crtc[13] | (tandy->crtc[12] << 8)) & 0x3fff; + } + if ((tandy->crtc[10] & 0x60) == 0x20) tandy->cursoron = 0; + else tandy->cursoron = tandy->blink & 16; +// printf("CRTC10 %02X %i\n",crtc[10],cursoron); + } + if (tandy->vc == tandy->crtc[7]) + { + tandy->dispon = 0; + tandy->displine = 0; + tandy->vsynctime = 16;//(crtc[3]>>4)+1; +// printf("tandy->vsynctime %i %02X\n",tandy->vsynctime,crtc[3]); +// tandy->stat|=8; + if (tandy->crtc[7]) + { +// printf("Lastline %i Firstline %i %i %i %i\n",lastline,firstline,lastline-firstline,crtc[1],xsize); + if (tandy->mode & 1) x = (tandy->crtc[1] << 3) + 16; + else x = (tandy->crtc[1] << 4) + 16; + tandy->lastline++; + if (x != xsize || (tandy->lastline - tandy->firstline) != ysize) + { + xsize = x; + ysize = tandy->lastline - tandy->firstline; +// printf("Resize to %i,%i - R1 %i\n",xsize,ysize,crtc[1]); + if (xsize < 64) xsize = 656; + if (ysize < 32) ysize = 200; + updatewindowsize(xsize, (ysize << 1) + 16); + } +// printf("Blit %i %i\n",firstline,lastline); +//printf("Xsize is %i\n",xsize); + startblit(); + video_blit_memtoscreen_8(0, tandy->firstline-4, xsize, (tandy->lastline - tandy->firstline) + 8); + endblit(); + frames++; + video_res_x = xsize - 16; + video_res_y = ysize; + if ((tandy->array[3] & 0x10) && (tandy->mode & 1)) /*320x200x16*/ + { + video_res_x /= 2; + video_bpp = 4; + } + else if (tandy->array[3] & 0x10) /*160x200x16*/ + { + video_res_x /= 4; + video_bpp = 4; + } + else if (tandy->array[3] & 0x08) /*640x200x4 - this implementation is a complete guess!*/ + video_bpp = 2; + else if (tandy->mode & 1) + { + video_res_x /= 8; + video_res_y /= tandy->crtc[9] + 1; + video_bpp = 0; + } + else if (!(tandy->mode & 2)) + { + video_res_x /= 16; + video_res_y /= tandy->crtc[9] + 1; + video_bpp = 0; + } + else if (!(tandy->mode & 16)) + { + video_res_x /= 2; + video_bpp = 2; + } + else + video_bpp = 1; + } + tandy->firstline = 1000; + tandy->lastline = 0; + tandy->blink++; + } + } + else + { + tandy->sc++; + tandy->sc &= 31; + tandy->ma = tandy->maback; + } + if ((tandy->sc == (tandy->crtc[10] & 31) || ((tandy->crtc[8] & 3) == 3 && tandy->sc == ((tandy->crtc[10] & 31) >> 1)))) + tandy->con = 1; + } +} + +static void *tandysl_init() +{ + int c; + tandysl_t *tandy = malloc(sizeof(tandysl_t)); + memset(tandy, 0, sizeof(tandysl_t)); + + tandy->memctrl = -1; + tandy->base = (mem_size - 128) * 1024; + tandy->b8000_limit = 0x8000; + tandy->planar_ctrl = 4; + + timer_add(tandysl_poll, &tandy->vidtime, TIMER_ALWAYS_ENABLED, tandy); + mem_mapping_add(&tandy->mapping, 0xb8000, 0x08000, tandysl_read, NULL, NULL, tandysl_write, NULL, NULL, NULL, 0, tandy); + mem_mapping_add(&tandy->ram_mapping, 0x80000, 0x20000, tandysl_ram_read, NULL, NULL, tandysl_ram_write, NULL, NULL, NULL, 0, tandy); + /*Base 128k mapping is controlled via port 0xffe8, so we remove it from the main mapping*/ + mem_mapping_set_addr(&ram_low_mapping, 0, (mem_size - 128) * 1024); + io_sethandler(0x03d0, 0x0010, tandysl_in, NULL, NULL, tandysl_out, NULL, NULL, tandy); + io_sethandler(0xffe8, 0x0001, tandysl_in, NULL, NULL, tandysl_out, NULL, NULL, tandy); + io_sethandler(0x0065, 0x0001, tandysl_in, NULL, NULL, tandysl_out, NULL, NULL, tandy); + overscan_x = overscan_y = 16; + return tandy; +} + +static void tandysl_close(void *p) +{ + tandysl_t *tandy = (tandysl_t *)p; + + free(tandy); +} + +static void tandysl_speed_changed(void *p) +{ + tandysl_t *tandy = (tandysl_t *)p; + + tandysl_recalctimings(tandy); +} + +device_t tandysl_device = +{ + "Tandy 1000SL (video)", + 0, + tandysl_init, + tandysl_close, + NULL, + tandysl_speed_changed, + NULL, + NULL +}; diff --git a/src/vid_tandysl.h b/src/vid_tandysl.h new file mode 100644 index 000000000..5d09cf6ce --- /dev/null +++ b/src/vid_tandysl.h @@ -0,0 +1 @@ +extern device_t tandysl_device; diff --git a/src/vid_tgui9440.c b/src/vid_tgui9440.c new file mode 100644 index 000000000..6af165fd2 --- /dev/null +++ b/src/vid_tgui9440.c @@ -0,0 +1,1333 @@ +/*Trident TGUI9440 emulation*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "thread.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "vid_tkd8001_ramdac.h" +#include "vid_tgui9440.h" + +#define FIFO_SIZE 65536 +#define FIFO_MASK (FIFO_SIZE - 1) +#define FIFO_ENTRY_SIZE (1 << 31) + +#define FIFO_ENTRIES (tgui->fifo_write_idx - tgui->fifo_read_idx) +#define FIFO_FULL ((tgui->fifo_write_idx - tgui->fifo_read_idx) >= FIFO_SIZE) +#define FIFO_EMPTY (tgui->fifo_read_idx == tgui->fifo_write_idx) + +#define FIFO_TYPE 0xff000000 +#define FIFO_ADDR 0x00ffffff + +enum +{ + FIFO_INVALID = (0x00 << 24), + FIFO_WRITE_BYTE = (0x01 << 24), + FIFO_WRITE_FB_BYTE = (0x04 << 24), + FIFO_WRITE_FB_WORD = (0x05 << 24), + FIFO_WRITE_FB_LONG = (0x06 << 24) +}; + +typedef struct +{ + uint32_t addr_type; + uint32_t val; +} fifo_entry_t; + +typedef struct tgui_t +{ + mem_mapping_t linear_mapping; + mem_mapping_t accel_mapping; + + rom_t bios_rom; + + svga_t svga; + + struct + { + uint16_t src_x, src_y; + uint16_t dst_x, dst_y; + uint16_t size_x, size_y; + uint16_t fg_col, bg_col; + uint8_t rop; + uint16_t flags; + uint8_t pattern[0x80]; + int command; + int offset; + uint8_t ger22; + + int x, y; + uint32_t src, dst, src_old, dst_old; + int pat_x, pat_y; + int use_src; + + int pitch, bpp; + + uint16_t tgui_pattern[8][8]; + } accel; + + uint8_t tgui_3d8, tgui_3d9; + int oldmode; + uint8_t oldctrl2,newctrl2; + + uint32_t linear_base, linear_size; + + int ramdac_state; + uint8_t ramdac_ctrl; + + int clock_m, clock_n, clock_k; + + uint32_t vram_size, vram_mask; + + fifo_entry_t fifo[FIFO_SIZE]; + volatile int fifo_read_idx, fifo_write_idx; + + thread_t *fifo_thread; + event_t *wake_fifo_thread; + event_t *fifo_not_full_event; + + int blitter_busy; + uint64_t blitter_time; + uint64_t status_time; +} tgui_t; + +void tgui_recalcmapping(tgui_t *tgui); + +static void fifo_thread(void *param); + +uint8_t tgui_accel_read(uint32_t addr, void *priv); +uint16_t tgui_accel_read_w(uint32_t addr, void *priv); +uint32_t tgui_accel_read_l(uint32_t addr, void *priv); + +void tgui_accel_write(uint32_t addr, uint8_t val, void *priv); +void tgui_accel_write_w(uint32_t addr, uint16_t val, void *priv); +void tgui_accel_write_l(uint32_t addr, uint32_t val, void *priv); + + +void tgui_accel_write_fb_l(uint32_t addr, uint32_t val, void *priv); + +void tgui_out(uint16_t addr, uint8_t val, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + svga_t *svga = &tgui->svga; + + uint8_t old; + +// pclog("tgui_out : %04X %02X %04X:%04X %i\n", addr, val, CS,pc, svga->bpp); + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60; + + switch (addr) + { + case 0x3C5: + switch (svga->seqaddr & 0xf) + { + case 0xB: + tgui->oldmode=1; + break; + case 0xC: + if (svga->seqregs[0xe] & 0x80) + svga->seqregs[0xc] = val; + break; + case 0xd: + if (tgui->oldmode) + tgui->oldctrl2 = val; + else + tgui->newctrl2=val; + break; + case 0xE: + svga->seqregs[0xe] = val ^ 2; + svga->write_bank = (svga->seqregs[0xe] & 0xf) * 65536; + if (!(svga->gdcreg[0xf] & 1)) + svga->read_bank = svga->write_bank; + return; + } + break; + + case 0x3C6: + if (tgui->ramdac_state == 4) + { + tgui->ramdac_state = 0; + tgui->ramdac_ctrl = val; + switch (tgui->ramdac_ctrl & 0xf0) + { + case 0x10: + svga->bpp = 15; + break; + case 0x30: + svga->bpp = 16; + break; + case 0xd0: + svga->bpp = 24; + break; + default: + svga->bpp = 8; + break; + } + return; + } + case 0x3C7: case 0x3C8: case 0x3C9: + tgui->ramdac_state = 0; + break; + + case 0x3CF: + switch (svga->gdcaddr & 15) + { + case 0x6: + if (svga->gdcreg[6] != val) + { + svga->gdcreg[6] = val; + tgui_recalcmapping(tgui); + } + return; + + case 0xE: + svga->gdcreg[0xe] = val ^ 2; + if ((svga->gdcreg[0xf] & 1) == 1) + svga->read_bank = (svga->gdcreg[0xe] & 0xf) * 65536; + break; + case 0xF: + if (val & 1) svga->read_bank = (svga->gdcreg[0xe] & 0xf) *65536; + else svga->read_bank = (svga->seqregs[0xe] & 0xf) *65536; + svga->write_bank = (svga->seqregs[0xe] & 0xf) * 65536; + break; + } + break; + case 0x3D4: + svga->crtcreg = val & 0x7f; + return; + case 0x3D5: + if (svga->crtcreg <= 0x18) + val &= mask_crtc[svga->crtcreg]; + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; +// if (svga->crtcreg != 0xE && svga->crtcreg != 0xF) pclog("CRTC R%02X = %02X\n", svga->crtcreg, val); + if (old != val) + { + if (svga->crtcreg < 0xE || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + switch (svga->crtcreg) + { + case 0x21: + if (old != val) + { + if (!PCI) + { + tgui->linear_base = ((val & 0xf) | ((val >> 2) & 0x30)) << 20; + tgui->linear_size = (val & 0x10) ? 0x200000 : 0x100000; + } + tgui_recalcmapping(tgui); + } + break; + + case 0x40: case 0x41: case 0x42: case 0x43: + case 0x44: case 0x45: case 0x46: case 0x47: + svga->hwcursor.x = (svga->crtc[0x40] | (svga->crtc[0x41] << 8)) & 0x7ff; + svga->hwcursor.y = (svga->crtc[0x42] | (svga->crtc[0x43] << 8)) & 0x7ff; + svga->hwcursor.xoff = svga->crtc[0x46] & 0x3f; + svga->hwcursor.yoff = svga->crtc[0x47] & 0x3f; + svga->hwcursor.addr = (svga->crtc[0x44] << 10) | ((svga->crtc[0x45] & 0x7) << 18) | (svga->hwcursor.yoff * 8); + break; + + case 0x50: + svga->hwcursor.ena = val & 0x80; + break; + } + return; + case 0x3D8: + tgui->tgui_3d8 = val; + if (svga->gdcreg[0xf] & 4) + { + svga->write_bank = (val & 0x1f) * 65536; +// pclog("SVGAWBANK 3D8 %08X %04X:%04X\n",svgawbank,CS,pc); + if (!(svga->gdcreg[0xf] & 1)) + { + svga->read_bank = (val & 0x1f) * 65536; +// pclog("SVGARBANK 3D8 %08X %04X:%04X\n",svgarbank,CS,pc); + } + } + return; + case 0x3D9: + tgui->tgui_3d9 = val; + if ((svga->gdcreg[0xf] & 5) == 5) + { + svga->read_bank = (val & 0x1F) * 65536; +// pclog("SVGARBANK 3D9 %08X %04X:%04X\n",svgarbank,CS,pc); + } + return; + + case 0x43c8: + tgui->clock_n = val & 0x7f; + tgui->clock_m = (tgui->clock_m & ~1) | (val >> 7); + break; + case 0x43c9: + tgui->clock_m = (tgui->clock_m & ~0x1e) | ((val << 1) & 0x1e); + tgui->clock_k = (val & 0x10) >> 4; + break; + } + svga_out(addr, val, svga); +} + +uint8_t tgui_in(uint16_t addr, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + svga_t *svga = &tgui->svga; + +// if (addr != 0x3da) pclog("tgui_in : %04X %04X:%04X\n", addr, CS,pc); + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60; + + switch (addr) + { + case 0x3C5: + if ((svga->seqaddr & 0xf) == 0xb) + { +// printf("Read Trident ID %04X:%04X %04X\n",CS,pc,readmemw(ss,SP)); + tgui->oldmode = 0; + return 0xe3; /*TGUI9440AGi*/ + } + if ((svga->seqaddr & 0xf) == 0xc) + { +// printf("Read Trident Power Up 1 %04X:%04X %04X\n",CS,pc,readmemw(ss,SP)); +// return 0x20; /*2 DRAM banks*/ + } + if ((svga->seqaddr & 0xf) == 0xd) + { + if (tgui->oldmode) return tgui->oldctrl2; + return tgui->newctrl2; + } + break; + case 0x3C6: + if (tgui->ramdac_state == 4) + return tgui->ramdac_ctrl; + tgui->ramdac_state++; + break; + case 0x3C7: case 0x3C8: case 0x3C9: + tgui->ramdac_state = 0; + break; + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + return svga->crtc[svga->crtcreg]; + case 0x3d8: + return tgui->tgui_3d8; + case 0x3d9: + return tgui->tgui_3d9; + } + return svga_in(addr, svga); +} + +void tgui_recalctimings(svga_t *svga) +{ + tgui_t *tgui = (tgui_t *)svga->p; + + if (svga->crtc[0x29] & 0x10) + svga->rowoffset += 0x100; + + if (svga->bpp == 24) + svga->hdisp = (svga->crtc[1] + 1) * 8; + + if ((svga->crtc[0x1e] & 0xA0) == 0xA0) svga->ma_latch |= 0x10000; + if ((svga->crtc[0x27] & 0x01) == 0x01) svga->ma_latch |= 0x20000; + if ((svga->crtc[0x27] & 0x02) == 0x02) svga->ma_latch |= 0x40000; + + if (tgui->oldctrl2 & 0x10) + { + svga->rowoffset <<= 1; + svga->ma_latch <<= 1; + } + if (tgui->oldctrl2 & 0x10) /*I'm not convinced this is the right register for this function*/ + svga->lowres=0; + + svga->lowres = !(svga->crtc[0x2a] & 0x40); + + // svga->interlace = svga->crtc[0x1e] & 4; + if (svga->crtc[0x1e] & 4) + { + // svga->rowoffset >>= 1; + svga->vtotal *= 2; + svga->dispend *= 2; + svga->vblankstart *= 2; + svga->vsyncstart *= 2; + svga->split *= 2; + } + + if (svga->miscout & 8) + svga->clock = cpuclock / (((tgui->clock_n + 8) * 14318180.0) / ((tgui->clock_m + 2) * (1 << tgui->clock_k))); + + if (svga->gdcreg[0xf] & 0x08) + svga->clock *= 2; + else if (svga->gdcreg[0xf] & 0x40) + svga->clock *= 3; + + if ((tgui->oldctrl2 & 0x10) || (svga->crtc[0x2a] & 0x40)) + { + switch (svga->bpp) + { + case 8: + svga->render = svga_render_8bpp_highres; + break; + case 15: + svga->render = svga_render_15bpp_highres; + break; + case 16: + svga->render = svga_render_16bpp_highres; + break; + case 24: + svga->render = svga_render_24bpp_highres; + break; + } + } +} + +void tgui_recalcmapping(tgui_t *tgui) +{ + svga_t *svga = &tgui->svga; + +// pclog("tgui_recalcmapping : %02X %02X\n", svga->crtc[0x21], svga->gdcreg[6]); + + if (svga->crtc[0x21] & 0x20) + { + mem_mapping_disable(&svga->mapping); + mem_mapping_set_addr(&tgui->linear_mapping, tgui->linear_base, tgui->linear_size); +// pclog("Trident linear framebuffer at %08X - size %06X\n", tgui->linear_base, tgui->linear_size); + mem_mapping_enable(&tgui->accel_mapping); + } + else + { +// pclog("Write mapping %02X\n", val); + mem_mapping_disable(&tgui->linear_mapping); + mem_mapping_disable(&tgui->accel_mapping); + switch (svga->gdcreg[6] & 0xC) + { + case 0x0: /*128k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x20000); + svga->banked_mask = 0xffff; + break; + case 0x4: /*64k at A0000*/ + mem_mapping_set_addr(&svga->mapping, 0xa0000, 0x10000); + mem_mapping_enable(&tgui->accel_mapping); + svga->banked_mask = 0xffff; + break; + case 0x8: /*32k at B0000*/ + mem_mapping_set_addr(&svga->mapping, 0xb0000, 0x08000); + svga->banked_mask = 0x7fff; + break; + case 0xC: /*32k at B8000*/ + mem_mapping_set_addr(&svga->mapping, 0xb8000, 0x08000); + svga->banked_mask = 0x7fff; + break; + } + } +} + +void tgui_hwcursor_draw(svga_t *svga, int displine) +{ + uint32_t dat[2]; + int xx; + int offset = svga->hwcursor_latch.x - svga->hwcursor_latch.xoff; + int y_add = enable_overscan ? 16 : 0; + int x_add = enable_overscan ? 8 : 0; + + dat[0] = (svga->vram[svga->hwcursor_latch.addr] << 24) | (svga->vram[svga->hwcursor_latch.addr + 1] << 16) | (svga->vram[svga->hwcursor_latch.addr + 2] << 8) | svga->vram[svga->hwcursor_latch.addr + 3]; + dat[1] = (svga->vram[svga->hwcursor_latch.addr + 4] << 24) | (svga->vram[svga->hwcursor_latch.addr + 5] << 16) | (svga->vram[svga->hwcursor_latch.addr + 6] << 8) | svga->vram[svga->hwcursor_latch.addr + 7]; + for (xx = 0; xx < 32; xx++) + { + if (offset >= svga->hwcursor_latch.x) + { + if (!(dat[0] & 0x80000000)) + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] = (dat[1] & 0x80000000) ? 0xffffff : 0; + else if (dat[1] & 0x80000000) + ((uint32_t *)buffer32->line[displine + y_add])[offset + 32 + x_add] ^= 0xffffff; +// pclog("Plot %i, %i (%i %i) %04X %04X\n", offset, displine, x+xx, svga_hwcursor_on, dat[0], dat[1]); + } + + offset++; + dat[0] <<= 1; + dat[1] <<= 1; + } + svga->hwcursor_latch.addr += 8; +} + +uint8_t tgui_pci_read(int func, int addr, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + svga_t *svga = &tgui->svga; + +// pclog("Trident PCI read %08X\n", addr); + + switch (addr) + { + case 0x00: return 0x23; /*Trident*/ + case 0x01: return 0x10; + + case 0x02: return 0x40; /*TGUI9440 (9682)*/ + case 0x03: return 0x94; + + case 0x04: return 0x03; /*Respond to IO and memory accesses*/ + + case 0x07: return 1 << 1; /*Medium DEVSEL timing*/ + + case 0x08: return 0; /*Revision ID*/ + case 0x09: return 0; /*Programming interface*/ + + case 0x0a: return 0x01; /*Supports VGA interface, XGA compatible*/ + case 0x0b: return 0x03; + + case 0x10: return 0x00; /*Linear frame buffer address*/ + case 0x11: return 0x00; + case 0x12: return tgui->linear_base >> 16; + case 0x13: return tgui->linear_base >> 24; + + case 0x30: return 0x01; /*BIOS ROM address*/ + case 0x31: return 0x00; + case 0x32: return 0x0C; + case 0x33: return 0x00; + } + return 0; +} + +void tgui_pci_write(int func, int addr, uint8_t val, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + svga_t *svga = &tgui->svga; + +// pclog("Trident PCI write %08X %02X\n", addr, val); + + switch (addr) + { + case 0x12: + tgui->linear_base = (tgui->linear_base & 0xff000000) | ((val & 0xe0) << 16); + tgui->linear_size = 2 << 20; + svga->crtc[0x21] = (svga->crtc[0x21] & ~0xf) | (val >> 4); + tgui_recalcmapping(tgui); + break; + case 0x13: + tgui->linear_base = (tgui->linear_base & 0xe00000) | (val << 24); + tgui->linear_size = 2 << 20; + svga->crtc[0x21] = (svga->crtc[0x21] & ~0xc0) | (val >> 6); + tgui_recalcmapping(tgui); + break; + } +} + +void *tgui9440_init() +{ + tgui_t *tgui = malloc(sizeof(tgui_t)); + memset(tgui, 0, sizeof(tgui_t)); + + tgui->vram_size = device_get_config_int("memory") << 20; + tgui->vram_mask = tgui->vram_size - 1; + + rom_init(&tgui->bios_rom, "roms/9440.vbi", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + svga_init(&tgui->svga, tgui, tgui->vram_size, + tgui_recalctimings, + tgui_in, tgui_out, + tgui_hwcursor_draw, + NULL); + + mem_mapping_add(&tgui->linear_mapping, 0, 0, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear, NULL, 0, &tgui->svga); + mem_mapping_add(&tgui->accel_mapping, 0xbc000, 0x4000, tgui_accel_read, tgui_accel_read_w, tgui_accel_read_l, tgui_accel_write, tgui_accel_write_w, tgui_accel_write_l, NULL, 0, tgui); + mem_mapping_disable(&tgui->accel_mapping); + + io_sethandler(0x03c0, 0x0020, tgui_in, NULL, NULL, tgui_out, NULL, NULL, tgui); + io_sethandler(0x43c8, 0x0002, tgui_in, NULL, NULL, tgui_out, NULL, NULL, tgui); + + pci_add(tgui_pci_read, tgui_pci_write, tgui); + + tgui->wake_fifo_thread = thread_create_event(); + tgui->fifo_not_full_event = thread_create_event(); + tgui->fifo_thread = thread_create(fifo_thread, tgui); + + return tgui; +} + +static int tgui9440_available() +{ + return rom_present("roms/9440.vbi"); +} + +void tgui_close(void *p) +{ + tgui_t *tgui = (tgui_t *)p; + + svga_close(&tgui->svga); + + free(tgui); +} + +void tgui_speed_changed(void *p) +{ + tgui_t *tgui = (tgui_t *)p; + + svga_recalctimings(&tgui->svga); +} + +void tgui_force_redraw(void *p) +{ + tgui_t *tgui = (tgui_t *)p; + + tgui->svga.fullchange = changeframecount; +} + +enum +{ + TGUI_BITBLT = 1 +}; + +enum +{ + TGUI_SRCCPU = 0, + + TGUI_SRCDISP = 0x04, /*Source is from display*/ + TGUI_PATMONO = 0x20, /*Pattern is monochrome and needs expansion*/ + TGUI_SRCMONO = 0x40, /*Source is monochrome from CPU and needs expansion*/ + TGUI_TRANSENA = 0x1000, /*Transparent (no draw when source == bg col)*/ + TGUI_TRANSREV = 0x2000, /*Reverse fg/bg for transparent*/ + TGUI_SOLIDFILL = 0x4000 /*Pattern all zero?*/ +}; + +#define READ(addr, dat) if (tgui->accel.bpp == 0) dat = svga->vram[addr & 0x1fffff]; \ + else dat = vram_w[addr & 0xfffff]; + +#define MIX() do \ + { \ + out = 0; \ + for (c=0;c<16;c++) \ + { \ + d=(dst_dat & (1<accel.rop & (1<accel.bpp == 0) \ + { \ + svga->vram[addr & 0x1fffff] = dat; \ + svga->changedvram[((addr) & 0x1fffff) >> 12] = changeframecount; \ + } \ + else \ + { \ + vram_w[addr & 0xfffff] = dat; \ + svga->changedvram[((addr) & 0xfffff) >> 11] = changeframecount; \ + } + +void tgui_accel_write_fb_b(uint32_t addr, uint8_t val, void *priv); +void tgui_accel_write_fb_w(uint32_t addr, uint16_t val, void *priv); + +void tgui_accel_command(int count, uint32_t cpu_dat, tgui_t *tgui) +{ + svga_t *svga = &tgui->svga; + int x, y; + int c, d; + uint16_t src_dat, dst_dat, pat_dat; + uint16_t out; + int xdir = (tgui->accel.flags & 0x200) ? -1 : 1; + int ydir = (tgui->accel.flags & 0x100) ? -1 : 1; + uint16_t trans_col = (tgui->accel.flags & TGUI_TRANSREV) ? tgui->accel.fg_col : tgui->accel.bg_col; + uint16_t *vram_w = (uint16_t *)svga->vram; + + if (tgui->accel.bpp == 0) + trans_col &= 0xff; + + if (count != -1 && !tgui->accel.x) + { + count -= tgui->accel.offset; + cpu_dat <<= tgui->accel.offset; + } + if (count == -1) + { + tgui->accel.x = tgui->accel.y = 0; + } + if (tgui->accel.flags & TGUI_SOLIDFILL) + { +// pclog("SOLIDFILL\n"); + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + tgui->accel.tgui_pattern[y][x] = tgui->accel.fg_col; + } + } + } + else if (tgui->accel.flags & TGUI_PATMONO) + { +// pclog("PATMONO\n"); + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + tgui->accel.tgui_pattern[y][x] = (tgui->accel.pattern[y] & (1 << x)) ? tgui->accel.fg_col : tgui->accel.bg_col; + } + } + } + else + { + if (tgui->accel.bpp == 0) + { +// pclog("OTHER 8-bit\n"); + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + tgui->accel.tgui_pattern[y][x] = tgui->accel.pattern[x + y*8]; + } + } + } + else + { +// pclog("OTHER 16-bit\n"); + for (y = 0; y < 8; y++) + { + for (x = 0; x < 8; x++) + { + tgui->accel.tgui_pattern[y][x] = tgui->accel.pattern[x*2 + y*16] | (tgui->accel.pattern[x*2 + y*16 + 1] << 8); + } + } + } + } +/* for (y = 0; y < 8; y++) + { + if (count == -1) pclog("Pattern %i : %02X %02X %02X %02X %02X %02X %02X %02X\n", y, tgui->accel.tgui_pattern[y][0], tgui->accel.tgui_pattern[y][1], tgui->accel.tgui_pattern[y][2], tgui->accel.tgui_pattern[y][3], tgui->accel.tgui_pattern[y][4], tgui->accel.tgui_pattern[y][5], tgui->accel.tgui_pattern[y][6], tgui->accel.tgui_pattern[y][7]); + }*/ +// if (count == -1) pclog("Command %i %i %p\n", tgui->accel.command, TGUI_BITBLT, tgui); + switch (tgui->accel.command) + { + case TGUI_BITBLT: +// if (count == -1) pclog("BITBLT src %i,%i dst %i,%i size %i,%i flags %04X\n", tgui->accel.src_x, tgui->accel.src_y, tgui->accel.dst_x, tgui->accel.dst_y, tgui->accel.size_x, tgui->accel.size_y, tgui->accel.flags); + if (count == -1) + { + tgui->accel.src = tgui->accel.src_old = tgui->accel.src_x + (tgui->accel.src_y * tgui->accel.pitch); + tgui->accel.dst = tgui->accel.dst_old = tgui->accel.dst_x + (tgui->accel.dst_y * tgui->accel.pitch); + tgui->accel.pat_x = tgui->accel.dst_x; + tgui->accel.pat_y = tgui->accel.dst_y; + } + + switch (tgui->accel.flags & (TGUI_SRCMONO|TGUI_SRCDISP)) + { + case TGUI_SRCCPU: + if (count == -1) + { +// pclog("Blit start TGUI_SRCCPU\n"); + if (svga->crtc[0x21] & 0x20) + mem_mapping_set_handler(&tgui->linear_mapping, svga_read_linear, svga_readw_linear, svga_readl_linear, tgui_accel_write_fb_b, tgui_accel_write_fb_w, tgui_accel_write_fb_l); + + if (tgui->accel.use_src) + return; + } + else + count >>= 3; +// pclog("TGUI_SRCCPU\n"); + while (count) + { + if (tgui->accel.bpp == 0) + { + src_dat = cpu_dat >> 24; + cpu_dat <<= 8; + } + else + { + src_dat = (cpu_dat >> 24) | ((cpu_dat >> 8) & 0xff00); + cpu_dat <<= 16; + count--; + } + READ(tgui->accel.dst, dst_dat); + pat_dat = tgui->accel.tgui_pattern[tgui->accel.pat_y & 7][tgui->accel.pat_x & 7]; + + if (!(tgui->accel.flags & TGUI_TRANSENA) || src_dat != trans_col) + { + MIX(); + + WRITE(tgui->accel.dst, out); + } + +// pclog(" %i,%i %02X %02X %02X %02X\n", tgui->accel.x, tgui->accel.y, src_dat,dst_dat,pat_dat, out); + + tgui->accel.src += xdir; + tgui->accel.dst += xdir; + tgui->accel.pat_x += xdir; + + tgui->accel.x++; + if (tgui->accel.x > tgui->accel.size_x) + { + tgui->accel.x = 0; + tgui->accel.y++; + + tgui->accel.pat_x = tgui->accel.dst_x; + + tgui->accel.src = tgui->accel.src_old = tgui->accel.src_old + (ydir * tgui->accel.pitch); + tgui->accel.dst = tgui->accel.dst_old = tgui->accel.dst_old + (ydir * tgui->accel.pitch); + tgui->accel.pat_y += ydir; + + if (tgui->accel.y > tgui->accel.size_y) + { + if (svga->crtc[0x21] & 0x20) + { +// pclog("Blit end\n"); + mem_mapping_set_handler(&tgui->linear_mapping, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear); + } + return; + } + if (tgui->accel.use_src) + return; + } + count--; + } + break; + + case TGUI_SRCMONO | TGUI_SRCCPU: + if (count == -1) + { +// pclog("Blit start TGUI_SRCMONO | TGUI_SRCCPU\n"); + if (svga->crtc[0x21] & 0x20) + mem_mapping_set_handler(&tgui->linear_mapping, svga_read_linear, svga_readw_linear, svga_readl_linear, tgui_accel_write_fb_b, tgui_accel_write_fb_w, tgui_accel_write_fb_l); + +// pclog(" %i\n", tgui->accel.command); + if (tgui->accel.use_src) + return; + } +// pclog("TGUI_SRCMONO | TGUI_SRCCPU\n"); + while (count) + { + src_dat = ((cpu_dat >> 31) ? tgui->accel.fg_col : tgui->accel.bg_col); + if (tgui->accel.bpp == 0) + src_dat &= 0xff; + + READ(tgui->accel.dst, dst_dat); + pat_dat = tgui->accel.tgui_pattern[tgui->accel.pat_y & 7][tgui->accel.pat_x & 7]; + + if (!(tgui->accel.flags & TGUI_TRANSENA) || src_dat != trans_col) + { + MIX(); + + WRITE(tgui->accel.dst, out); + } +// pclog(" %i,%i %02X %02X %02X %02X %i\n", tgui->accel.x, tgui->accel.y, src_dat,dst_dat,pat_dat, out, (!(tgui->accel.flags & TGUI_TRANSENA) || src_dat != trans_col)); + cpu_dat <<= 1; + tgui->accel.src += xdir; + tgui->accel.dst += xdir; + tgui->accel.pat_x += xdir; + + tgui->accel.x++; + if (tgui->accel.x > tgui->accel.size_x) + { + tgui->accel.x = 0; + tgui->accel.y++; + + tgui->accel.pat_x = tgui->accel.dst_x; + + tgui->accel.src = tgui->accel.src_old = tgui->accel.src_old + (ydir * tgui->accel.pitch); + tgui->accel.dst = tgui->accel.dst_old = tgui->accel.dst_old + (ydir * tgui->accel.pitch); + tgui->accel.pat_y += ydir; + + if (tgui->accel.y > tgui->accel.size_y) + { + if (svga->crtc[0x21] & 0x20) + { +// pclog("Blit end\n"); + mem_mapping_set_handler(&tgui->linear_mapping, svga_read_linear, svga_readw_linear, svga_readl_linear, svga_write_linear, svga_writew_linear, svga_writel_linear); + } + return; + } + if (tgui->accel.use_src) + return; + } + count--; + } + break; + + default: + while (count) + { + READ(tgui->accel.src, src_dat); + READ(tgui->accel.dst, dst_dat); + pat_dat = tgui->accel.tgui_pattern[tgui->accel.pat_y & 7][tgui->accel.pat_x & 7]; + + if (!(tgui->accel.flags & TGUI_TRANSENA) || src_dat != trans_col) + { + MIX(); + + WRITE(tgui->accel.dst, out); + } +// pclog(" %i,%i %02X %02X %02X %02X\n", tgui->accel.x, tgui->accel.y, src_dat,dst_dat,pat_dat, out); + + tgui->accel.src += xdir; + tgui->accel.dst += xdir; + tgui->accel.pat_x += xdir; + + tgui->accel.x++; + if (tgui->accel.x > tgui->accel.size_x) + { + tgui->accel.x = 0; + tgui->accel.y++; + + tgui->accel.pat_x = tgui->accel.dst_x; + + tgui->accel.src = tgui->accel.src_old = tgui->accel.src_old + (ydir * tgui->accel.pitch); + tgui->accel.dst = tgui->accel.dst_old = tgui->accel.dst_old + (ydir * tgui->accel.pitch); + tgui->accel.pat_y += ydir; + + if (tgui->accel.y > tgui->accel.size_y) + return; + } + count--; + } + break; + } + break; + } +} + +static void tgui_accel_write_fifo(tgui_t *tgui, uint32_t addr, uint8_t val) +{ + switch (addr & 0xff) + { + case 0x22: + tgui->accel.ger22 = val; + tgui->accel.pitch = 512 << ((val >> 2) & 3); + tgui->accel.bpp = (val & 3) ? 1 : 0; + tgui->accel.pitch >>= tgui->accel.bpp; + break; + + case 0x24: /*Command*/ + tgui->accel.command = val; + tgui_accel_command(-1, 0, tgui); + break; + + case 0x27: /*ROP*/ + tgui->accel.rop = val; + tgui->accel.use_src = (val & 0x33) ^ ((val >> 2) & 0x33); +// pclog("Write ROP %02X %i\n", val, tgui->accel.use_src); + break; + + case 0x28: /*Flags*/ + tgui->accel.flags = (tgui->accel.flags & 0xff00) | val; + break; + case 0x29: /*Flags*/ + tgui->accel.flags = (tgui->accel.flags & 0xff) | (val << 8); + break; + + case 0x2b: + tgui->accel.offset = val & 7; + break; + + case 0x2c: /*Foreground colour*/ + tgui->accel.fg_col = (tgui->accel.fg_col & 0xff00) | val; + break; + case 0x2d: /*Foreground colour*/ + tgui->accel.fg_col = (tgui->accel.fg_col & 0xff) | (val << 8); + break; + + case 0x30: /*Background colour*/ + tgui->accel.bg_col = (tgui->accel.bg_col & 0xff00) | val; + break; + case 0x31: /*Background colour*/ + tgui->accel.bg_col = (tgui->accel.bg_col & 0xff) | (val << 8); + break; + + case 0x38: /*Dest X*/ + tgui->accel.dst_x = (tgui->accel.dst_x & 0xff00) | val; + break; + case 0x39: /*Dest X*/ + tgui->accel.dst_x = (tgui->accel.dst_x & 0xff) | (val << 8); + break; + case 0x3a: /*Dest Y*/ + tgui->accel.dst_y = (tgui->accel.dst_y & 0xff00) | val; + break; + case 0x3b: /*Dest Y*/ + tgui->accel.dst_y = (tgui->accel.dst_y & 0xff) | (val << 8); + break; + + case 0x3c: /*Src X*/ + tgui->accel.src_x = (tgui->accel.src_x & 0xff00) | val; + break; + case 0x3d: /*Src X*/ + tgui->accel.src_x = (tgui->accel.src_x & 0xff) | (val << 8); + break; + case 0x3e: /*Src Y*/ + tgui->accel.src_y = (tgui->accel.src_y & 0xff00) | val; + break; + case 0x3f: /*Src Y*/ + tgui->accel.src_y = (tgui->accel.src_y & 0xff) | (val << 8); + break; + + case 0x40: /*Size X*/ + tgui->accel.size_x = (tgui->accel.size_x & 0xff00) | val; + break; + case 0x41: /*Size X*/ + tgui->accel.size_x = (tgui->accel.size_x & 0xff) | (val << 8); + break; + case 0x42: /*Size Y*/ + tgui->accel.size_y = (tgui->accel.size_y & 0xff00) | val; + break; + case 0x43: /*Size Y*/ + tgui->accel.size_y = (tgui->accel.size_y & 0xff) | (val << 8); + break; + + case 0x80: case 0x81: case 0x82: case 0x83: + case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: + case 0x8c: case 0x8d: case 0x8e: case 0x8f: + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: + case 0x9c: case 0x9d: case 0x9e: case 0x9f: + case 0xa0: case 0xa1: case 0xa2: case 0xa3: + case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: + case 0xac: case 0xad: case 0xae: case 0xaf: + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: + case 0xdc: case 0xdd: case 0xde: case 0xdf: + case 0xe0: case 0xe1: case 0xe2: case 0xe3: + case 0xe4: case 0xe5: case 0xe6: case 0xe7: + case 0xe8: case 0xe9: case 0xea: case 0xeb: + case 0xec: case 0xed: case 0xee: case 0xef: + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: + tgui->accel.pattern[addr & 0x7f] = val; + break; + } +} + +static void tgui_accel_write_fifo_fb_b(tgui_t *tgui, uint32_t addr, uint8_t val) +{ + tgui_accel_command(8, val << 24, tgui); +} +static void tgui_accel_write_fifo_fb_w(tgui_t *tgui, uint32_t addr, uint16_t val) +{ + tgui_accel_command(16, (((val & 0xff00) >> 8) | ((val & 0x00ff) << 8)) << 16, tgui); +} +static void tgui_accel_write_fifo_fb_l(tgui_t *tgui, uint32_t addr, uint32_t val) +{ + tgui_accel_command(32, ((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24), tgui); +} + +static void fifo_thread(void *param) +{ + tgui_t *tgui = (tgui_t *)param; + + while (1) + { + thread_set_event(tgui->fifo_not_full_event); + thread_wait_event(tgui->wake_fifo_thread, -1); + thread_reset_event(tgui->wake_fifo_thread); + tgui->blitter_busy = 1; + while (!FIFO_EMPTY) + { + uint64_t start_time = timer_read(); + uint64_t end_time; + fifo_entry_t *fifo = &tgui->fifo[tgui->fifo_read_idx & FIFO_MASK]; + uint32_t val = fifo->val; + + switch (fifo->addr_type & FIFO_TYPE) + { + case FIFO_WRITE_BYTE: + tgui_accel_write_fifo(tgui, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_FB_BYTE: + tgui_accel_write_fifo_fb_b(tgui, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_FB_WORD: + tgui_accel_write_fifo_fb_w(tgui, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + case FIFO_WRITE_FB_LONG: + tgui_accel_write_fifo_fb_l(tgui, fifo->addr_type & FIFO_ADDR, fifo->val); + break; + } + + tgui->fifo_read_idx++; + fifo->addr_type = FIFO_INVALID; + + if (FIFO_ENTRIES > 0xe000) + thread_set_event(tgui->fifo_not_full_event); + + end_time = timer_read(); + tgui->blitter_time += end_time - start_time; + } + tgui->blitter_busy = 0; + } +} + +static inline void wake_fifo_thread(tgui_t *tgui) +{ + thread_set_event(tgui->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +static void tgui_wait_fifo_idle(tgui_t *tgui) +{ + while (!FIFO_EMPTY) + { + wake_fifo_thread(tgui); + thread_wait_event(tgui->fifo_not_full_event, 1); + } +} + +static void tgui_queue(tgui_t *tgui, uint32_t addr, uint32_t val, uint32_t type) +{ + fifo_entry_t *fifo = &tgui->fifo[tgui->fifo_write_idx & FIFO_MASK]; + int c; + + if (FIFO_FULL) + { + thread_reset_event(tgui->fifo_not_full_event); + if (FIFO_FULL) + { + thread_wait_event(tgui->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ + } + } + + fifo->val = val; + fifo->addr_type = (addr & FIFO_ADDR) | type; + + tgui->fifo_write_idx++; + + if (FIFO_ENTRIES > 0xe000 || FIFO_ENTRIES < 8) + wake_fifo_thread(tgui); +} + + +void tgui_accel_write(uint32_t addr, uint8_t val, void *p) +{ + tgui_t *tgui = (tgui_t *)p; +// pclog("tgui_accel_write : %08X %02X %04X(%08X):%08X %02X\n", addr, val, CS,cs,pc, opcode); + if ((addr & ~0xff) != 0xbff00) + return; + tgui_queue(tgui, addr, val, FIFO_WRITE_BYTE); +} + +void tgui_accel_write_w(uint32_t addr, uint16_t val, void *p) +{ + tgui_t *tgui = (tgui_t *)p; +// pclog("tgui_accel_write_w %08X %04X\n", addr, val); + tgui_accel_write(addr, val, tgui); + tgui_accel_write(addr + 1, val >> 8, tgui); +} + +void tgui_accel_write_l(uint32_t addr, uint32_t val, void *p) +{ + tgui_t *tgui = (tgui_t *)p; +// pclog("tgui_accel_write_l %08X %08X\n", addr, val); + tgui_accel_write(addr, val, tgui); + tgui_accel_write(addr + 1, val >> 8, tgui); + tgui_accel_write(addr + 2, val >> 16, tgui); + tgui_accel_write(addr + 3, val >> 24, tgui); +} + +uint8_t tgui_accel_read(uint32_t addr, void *p) +{ + tgui_t *tgui = (tgui_t *)p; +// pclog("tgui_accel_read : %08X\n", addr); + if ((addr & ~0xff) != 0xbff00) + return 0xff; + if ((addr & 0xff) != 0x20) + tgui_wait_fifo_idle(tgui); + switch (addr & 0xff) + { + case 0x20: /*Status*/ + if (!FIFO_EMPTY) + return 1 << 5; + return 0; + + case 0x27: /*ROP*/ + return tgui->accel.rop; + + case 0x28: /*Flags*/ + return tgui->accel.flags & 0xff; + case 0x29: /*Flags*/ + return tgui->accel.flags >> 8; + + case 0x2b: + return tgui->accel.offset; + + case 0x2c: /*Background colour*/ + return tgui->accel.bg_col & 0xff; + case 0x2d: /*Background colour*/ + return tgui->accel.bg_col >> 8; + + case 0x30: /*Foreground colour*/ + return tgui->accel.fg_col & 0xff; + case 0x31: /*Foreground colour*/ + return tgui->accel.fg_col >> 8; + + case 0x38: /*Dest X*/ + return tgui->accel.dst_x & 0xff; + case 0x39: /*Dest X*/ + return tgui->accel.dst_x >> 8; + case 0x3a: /*Dest Y*/ + return tgui->accel.dst_y & 0xff; + case 0x3b: /*Dest Y*/ + return tgui->accel.dst_y >> 8; + + case 0x3c: /*Src X*/ + return tgui->accel.src_x & 0xff; + case 0x3d: /*Src X*/ + return tgui->accel.src_x >> 8; + case 0x3e: /*Src Y*/ + return tgui->accel.src_y & 0xff; + case 0x3f: /*Src Y*/ + return tgui->accel.src_y >> 8; + + case 0x40: /*Size X*/ + return tgui->accel.size_x & 0xff; + case 0x41: /*Size X*/ + return tgui->accel.size_x >> 8; + case 0x42: /*Size Y*/ + return tgui->accel.size_y & 0xff; + case 0x43: /*Size Y*/ + return tgui->accel.size_y >> 8; + + case 0x80: case 0x81: case 0x82: case 0x83: + case 0x84: case 0x85: case 0x86: case 0x87: + case 0x88: case 0x89: case 0x8a: case 0x8b: + case 0x8c: case 0x8d: case 0x8e: case 0x8f: + case 0x90: case 0x91: case 0x92: case 0x93: + case 0x94: case 0x95: case 0x96: case 0x97: + case 0x98: case 0x99: case 0x9a: case 0x9b: + case 0x9c: case 0x9d: case 0x9e: case 0x9f: + case 0xa0: case 0xa1: case 0xa2: case 0xa3: + case 0xa4: case 0xa5: case 0xa6: case 0xa7: + case 0xa8: case 0xa9: case 0xaa: case 0xab: + case 0xac: case 0xad: case 0xae: case 0xaf: + case 0xb0: case 0xb1: case 0xb2: case 0xb3: + case 0xb4: case 0xb5: case 0xb6: case 0xb7: + case 0xb8: case 0xb9: case 0xba: case 0xbb: + case 0xbc: case 0xbd: case 0xbe: case 0xbf: + case 0xc0: case 0xc1: case 0xc2: case 0xc3: + case 0xc4: case 0xc5: case 0xc6: case 0xc7: + case 0xc8: case 0xc9: case 0xca: case 0xcb: + case 0xcc: case 0xcd: case 0xce: case 0xcf: + case 0xd0: case 0xd1: case 0xd2: case 0xd3: + case 0xd4: case 0xd5: case 0xd6: case 0xd7: + case 0xd8: case 0xd9: case 0xda: case 0xdb: + case 0xdc: case 0xdd: case 0xde: case 0xdf: + case 0xe0: case 0xe1: case 0xe2: case 0xe3: + case 0xe4: case 0xe5: case 0xe6: case 0xe7: + case 0xe8: case 0xe9: case 0xea: case 0xeb: + case 0xec: case 0xed: case 0xee: case 0xef: + case 0xf0: case 0xf1: case 0xf2: case 0xf3: + case 0xf4: case 0xf5: case 0xf6: case 0xf7: + case 0xf8: case 0xf9: case 0xfa: case 0xfb: + case 0xfc: case 0xfd: case 0xfe: case 0xff: + return tgui->accel.pattern[addr & 0x7f]; + } + return 0xff; +} + +uint16_t tgui_accel_read_w(uint32_t addr, void *p) +{ + tgui_t *tgui = (tgui_t *)p; +// pclog("tgui_accel_read_w %08X\n", addr); + return tgui_accel_read(addr, tgui) | (tgui_accel_read(addr + 1, tgui) << 8); +} + +uint32_t tgui_accel_read_l(uint32_t addr, void *p) +{ + tgui_t *tgui = (tgui_t *)p; +// pclog("tgui_accel_read_l %08X\n", addr); + return tgui_accel_read_w(addr, tgui) | (tgui_accel_read_w(addr + 2, tgui) << 16); +} + +void tgui_accel_write_fb_b(uint32_t addr, uint8_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + tgui_t *tgui = (tgui_t *)svga->p; +// pclog("tgui_accel_write_fb_b %08X %02X\n", addr, val); + tgui_queue(tgui, addr, val, FIFO_WRITE_FB_BYTE); +} + +void tgui_accel_write_fb_w(uint32_t addr, uint16_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + tgui_t *tgui = (tgui_t *)svga->p; +// pclog("tgui_accel_write_fb_w %08X %04X\n", addr, val); + tgui_queue(tgui, addr, val, FIFO_WRITE_FB_WORD); +} + +void tgui_accel_write_fb_l(uint32_t addr, uint32_t val, void *p) +{ + svga_t *svga = (svga_t *)p; + tgui_t *tgui = (tgui_t *)svga->p; +// pclog("tgui_accel_write_fb_l %08X %08X\n", addr, val); + tgui_queue(tgui, addr, val, FIFO_WRITE_FB_LONG); +} + +void tgui_add_status_info(char *s, int max_len, void *p) +{ + tgui_t *tgui = (tgui_t *)p; + char temps[256]; + uint64_t new_time = timer_read(); + uint64_t status_diff = new_time - tgui->status_time; + tgui->status_time = new_time; + + svga_add_status_info(s, max_len, &tgui->svga); + + sprintf(temps, "%f%% CPU\n%f%% CPU (real)\n\n", ((double)tgui->blitter_time * 100.0) / timer_freq, ((double)tgui->blitter_time * 100.0) / status_diff); + strncat(s, temps, max_len); + + tgui->blitter_time = 0; +} + +static device_config_t tgui9440_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1 MB", + .value = 1 + }, + { + .description = "2 MB", + .value = 2 + }, + { + .description = "" + } + }, + .default_int = 2 + }, + { + .type = -1 + } +}; + +device_t tgui9440_device = +{ + "Trident TGUI 9440", + 0, + tgui9440_init, + tgui_close, + tgui9440_available, + tgui_speed_changed, + tgui_force_redraw, + tgui_add_status_info, + tgui9440_config +}; diff --git a/src/vid_tgui9440.h b/src/vid_tgui9440.h new file mode 100644 index 000000000..d5a09458e --- /dev/null +++ b/src/vid_tgui9440.h @@ -0,0 +1 @@ +extern device_t tgui9440_device; diff --git a/src/vid_tkd8001_ramdac.c b/src/vid_tkd8001_ramdac.c new file mode 100644 index 000000000..13f20e6e6 --- /dev/null +++ b/src/vid_tkd8001_ramdac.c @@ -0,0 +1,65 @@ +/*Trident TKD8001 RAMDAC emulation*/ +#include "ibm.h" +#include "mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_tkd8001_ramdac.h" + +static int tkd8001_state=0; +static uint8_t tkd8001_ctrl; + +void tkd8001_ramdac_out(uint16_t addr, uint8_t val, tkd8001_ramdac_t *ramdac, svga_t *svga) +{ +// pclog("OUT RAMDAC %04X %02X %04X:%04X\n",addr,val,CS,pc); + switch (addr) + { + case 0x3C6: + if (ramdac->state == 4) + { + ramdac->state = 0; + ramdac->ctrl = val; + switch (val >> 5) + { + case 0: case 1: case 2: case 3: + svga->bpp = 8; + break; + case 5: + svga->bpp = 15; + break; + case 6: + svga->bpp = 24; + break; + case 7: + svga->bpp = 16; + break; + } + return; + } + // tkd8001_state = 0; + break; + case 0x3C7: case 0x3C8: case 0x3C9: + ramdac->state = 0; + break; + } + svga_out(addr, val, svga); +} + +uint8_t tkd8001_ramdac_in(uint16_t addr, tkd8001_ramdac_t *ramdac, svga_t *svga) +{ +// pclog("IN RAMDAC %04X %04X:%04X\n",addr,CS,pc); + switch (addr) + { + case 0x3C6: + if (ramdac->state == 4) + { + //tkd8001_state = 0; + return ramdac->ctrl; + } + ramdac->state++; + break; + case 0x3C7: case 0x3C8: case 0x3C9: + ramdac->state = 0; + break; + } + return svga_in(addr, svga); +} diff --git a/src/vid_tkd8001_ramdac.h b/src/vid_tkd8001_ramdac.h new file mode 100644 index 000000000..b6db31b60 --- /dev/null +++ b/src/vid_tkd8001_ramdac.h @@ -0,0 +1,8 @@ +typedef struct tkd8001_ramdac_t +{ + int state; + uint8_t ctrl; +} tkd8001_ramdac_t; + +void tkd8001_ramdac_out(uint16_t addr, uint8_t val, tkd8001_ramdac_t *ramdac, svga_t *svga); +uint8_t tkd8001_ramdac_in(uint16_t addr, tkd8001_ramdac_t *ramdac, svga_t *svga); diff --git a/src/vid_tvga.c b/src/vid_tvga.c new file mode 100644 index 000000000..174a132b7 --- /dev/null +++ b/src/vid_tvga.c @@ -0,0 +1,389 @@ +/*Trident TVGA (8900D) emulation*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_svga_render.h" +#include "vid_tkd8001_ramdac.h" +#include "vid_tvga.h" + +typedef struct tvga_t +{ + mem_mapping_t linear_mapping; + mem_mapping_t accel_mapping; + + svga_t svga; + tkd8001_ramdac_t ramdac; + + rom_t bios_rom; + + uint8_t tvga_3d8, tvga_3d9; + int oldmode; + uint8_t oldctrl1; + uint8_t oldctrl2, newctrl2; + + int vram_size; + uint32_t vram_mask; +} tvga_t; + +static uint8_t crtc_mask[0x40] = +{ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0x7f, 0xff, 0x3f, 0x7f, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xef, + 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, + 0x7f, 0x00, 0x00, 0x2f, 0x00, 0x00, 0x00, 0x03, + 0x00, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +static void tvga_recalcbanking(tvga_t *tvga); +void tvga_out(uint16_t addr, uint8_t val, void *p) +{ + tvga_t *tvga = (tvga_t *)p; + svga_t *svga = &tvga->svga; + + uint8_t old; + +// pclog("tvga_out : %04X %02X %04X:%04X %i\n", addr, val, CS,pc, svga->bpp); + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60; + + switch (addr) + { + case 0x3C5: + switch (svga->seqaddr & 0xf) + { + case 0xB: + tvga->oldmode=1; + break; + case 0xC: + if (svga->seqregs[0xe] & 0x80) + svga->seqregs[0xc] = val; + break; + case 0xd: + if (tvga->oldmode) + tvga->oldctrl2 = val; + else + { + tvga->newctrl2 = val; + svga_recalctimings(svga); + } + break; + case 0xE: + if (tvga->oldmode) + tvga->oldctrl1 = val; + else + { + svga->seqregs[0xe] = val ^ 2; + tvga->tvga_3d8 = svga->seqregs[0xe] & 0xf; + tvga_recalcbanking(tvga); + } + return; + } + break; + + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + tkd8001_ramdac_out(addr, val, &tvga->ramdac, svga); + return; + + case 0x3CF: + switch (svga->gdcaddr & 15) + { + case 0xE: + svga->gdcreg[0xe] = val ^ 2; + tvga->tvga_3d9 = svga->gdcreg[0xe] & 0xf; + tvga_recalcbanking(tvga); + break; + case 0xF: + svga->gdcreg[0xf] = val; + tvga_recalcbanking(tvga); + break; + } + break; + case 0x3D4: + svga->crtcreg = val & 0x3f; + return; + case 0x3D5: + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + val &= crtc_mask[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; +// if (svga->crtcreg != 0xC && svga->crtcreg != 0xE && svga->crtcreg != 0xF) pclog("CRTC R%02X = %02X %04X:%04X\n", svga->crtcreg, val, CS, pc); + if (old != val) + { + if (svga->crtcreg < 0xE || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + switch (svga->crtcreg) + { + case 0x1e: + svga->vrammask = (val & 0x80) ? tvga->vram_mask : 0x3ffff; + break; + } + return; + case 0x3D8: + if (svga->gdcreg[0xf] & 4) + { + tvga->tvga_3d8 = val; + tvga_recalcbanking(tvga); + } + return; + case 0x3D9: + if (svga->gdcreg[0xf] & 4) + { + tvga->tvga_3d9 = val; + tvga_recalcbanking(tvga); + } + return; + } + svga_out(addr, val, svga); +} + +uint8_t tvga_in(uint16_t addr, void *p) +{ + tvga_t *tvga = (tvga_t *)p; + svga_t *svga = &tvga->svga; + +// if (addr != 0x3da) pclog("tvga_in : %04X %04X:%04X\n", addr, CS,pc); + + if (((addr&0xFFF0) == 0x3D0 || (addr&0xFFF0) == 0x3B0) && !(svga->miscout & 1)) addr ^= 0x60; + + switch (addr) + { + case 0x3C5: + if ((svga->seqaddr & 0xf) == 0xb) + { +// printf("Read Trident ID %04X:%04X %04X\n",CS,pc,readmemw(ss,SP)); + tvga->oldmode = 0; + return 0x33; /*TVGA8900D*/ + } + if ((svga->seqaddr & 0xf) == 0xc) + { +// printf("Read Trident Power Up 1 %04X:%04X %04X\n",CS,pc,readmemw(ss,SP)); +// return 0x20; /*2 DRAM banks*/ + } + if ((svga->seqaddr & 0xf) == 0xd) + { + if (tvga->oldmode) return tvga->oldctrl2; + return tvga->newctrl2; + } + if ((svga->seqaddr & 0xf) == 0xe) + { + if (tvga->oldmode) + return tvga->oldctrl1; + } + break; + case 0x3C6: case 0x3C7: case 0x3C8: case 0x3C9: + return tkd8001_ramdac_in(addr, &tvga->ramdac, svga); + case 0x3D4: + return svga->crtcreg; + case 0x3D5: + if (svga->crtcreg > 0x18 && svga->crtcreg < 0x1e) + return 0xff; + return svga->crtc[svga->crtcreg]; + case 0x3d8: + return tvga->tvga_3d8; + case 0x3d9: + return tvga->tvga_3d9; + } + return svga_in(addr, svga); +} + +static void tvga_recalcbanking(tvga_t *tvga) +{ + svga_t *svga = &tvga->svga; + + svga->write_bank = (tvga->tvga_3d8 & 0x1f) * 65536; + + if (svga->gdcreg[0xf] & 1) + svga->read_bank = (tvga->tvga_3d9 & 0x1f) * 65536; + else + svga->read_bank = svga->write_bank; + +// pclog("recalcbanking: write_bank=%08x read_bank=%08x GDC[E]=%02x GDC[F]=%02x SEQ[E]=%02x 3d8=%02x 3d9=%02x\n", svga->read_bank, svga->write_bank, svga->gdcreg[0xe], svga->gdcreg[0xf], svga->seqregs[0xe], tvga->tvga_3d8, tvga->tvga_3d9); +} + +void tvga_recalctimings(svga_t *svga) +{ + tvga_t *tvga = (tvga_t *)svga->p; + if (!svga->rowoffset) svga->rowoffset = 0x100; /*This is the only sensible way I can see this being handled, + given that TVGA8900D has no overflow bits. + Some sort of overflow is required for 320x200x24 and 1024x768x16*/ + if (svga->crtc[0x29] & 0x10) + svga->rowoffset += 0x100; + + if (svga->bpp == 24) + svga->hdisp = (svga->crtc[1] + 1) * 8; + + if ((svga->crtc[0x1e] & 0xA0) == 0xA0) svga->ma_latch |= 0x10000; + if ((svga->crtc[0x27] & 0x01) == 0x01) svga->ma_latch |= 0x20000; + if ((svga->crtc[0x27] & 0x02) == 0x02) svga->ma_latch |= 0x40000; + + if (tvga->oldctrl2 & 0x10) + { + svga->rowoffset <<= 1; + svga->ma_latch <<= 1; + } + if (svga->gdcreg[0xf] & 0x08) + { + svga->htotal *= 2; + svga->hdisp *= 2; + svga->hdisp_time *= 2; + } + + // svga->interlace = svga->crtc[0x1e] & 4; + if (svga->crtc[0x1e] & 4) + { + svga->rowoffset >>= 1; + svga->vtotal *= 2; + svga->dispend *= 2; + svga->vblankstart *= 2; + svga->vsyncstart *= 2; + svga->split *= 2; + } + + switch (((svga->miscout >> 2) & 3) | ((tvga->newctrl2 << 2) & 4)) + { + case 2: svga->clock = cpuclock/44900000.0; break; + case 3: svga->clock = cpuclock/36000000.0; break; + case 4: svga->clock = cpuclock/57272000.0; break; + case 5: svga->clock = cpuclock/65000000.0; break; + case 6: svga->clock = cpuclock/50350000.0; break; + case 7: svga->clock = cpuclock/40000000.0; break; + } + + if (tvga->oldctrl2 & 0x10) + { + switch (svga->bpp) + { + case 8: + svga->render = svga_render_8bpp_highres; + break; + case 15: + svga->render = svga_render_15bpp_highres; + svga->hdisp /= 2; + break; + case 16: + svga->render = svga_render_16bpp_highres; + svga->hdisp /= 2; + break; + case 24: + svga->render = svga_render_24bpp_highres; + svga->hdisp /= 3; + break; + } + svga->lowres = 0; + } +} + +void *tvga8900d_init() +{ + tvga_t *tvga = malloc(sizeof(tvga_t)); + memset(tvga, 0, sizeof(tvga_t)); + + tvga->vram_size = device_get_config_int("memory") << 10; + tvga->vram_mask = tvga->vram_size - 1; + + rom_init(&tvga->bios_rom, "roms/TRIDENT.BIN", 0xc0000, 0x8000, 0x7fff, 0, MEM_MAPPING_EXTERNAL); + + svga_init(&tvga->svga, tvga, tvga->vram_size, + tvga_recalctimings, + tvga_in, tvga_out, + NULL, + NULL); + + io_sethandler(0x03c0, 0x0020, tvga_in, NULL, NULL, tvga_out, NULL, NULL, tvga); + + return tvga; +} + +static int tvga8900d_available() +{ + return rom_present("roms/TRIDENT.BIN"); +} + +void tvga_close(void *p) +{ + tvga_t *tvga = (tvga_t *)p; + + svga_close(&tvga->svga); + + free(tvga); +} + +void tvga_speed_changed(void *p) +{ + tvga_t *tvga = (tvga_t *)p; + + svga_recalctimings(&tvga->svga); +} + +void tvga_force_redraw(void *p) +{ + tvga_t *tvga = (tvga_t *)p; + + tvga->svga.fullchange = changeframecount; +} + +void tvga_add_status_info(char *s, int max_len, void *p) +{ + tvga_t *tvga = (tvga_t *)p; + + svga_add_status_info(s, max_len, &tvga->svga); +} + +static device_config_t tvga_config[] = +{ + { + .name = "memory", + .description = "Memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "256 kB", + .value = 256 + }, + { + .description = "512 kB", + .value = 512 + }, + { + .description = "1 MB", + .value = 1024 + }, + /*Chip supports 2mb, but drivers are buggy*/ + { + .description = "" + } + }, + .default_int = 1024 + }, + { + .type = -1 + } +}; + +device_t tvga8900d_device = +{ + "Trident TVGA 8900D", + 0, + tvga8900d_init, + tvga_close, + tvga8900d_available, + tvga_speed_changed, + tvga_force_redraw, + tvga_add_status_info, + tvga_config +}; diff --git a/src/vid_tvga.h b/src/vid_tvga.h new file mode 100644 index 000000000..e49e21f05 --- /dev/null +++ b/src/vid_tvga.h @@ -0,0 +1 @@ +extern device_t tvga8900d_device; diff --git a/src/vid_unk_ramdac.c b/src/vid_unk_ramdac.c new file mode 100644 index 000000000..2b71647ae --- /dev/null +++ b/src/vid_unk_ramdac.c @@ -0,0 +1,64 @@ +/*It is unknown exactly what RAMDAC this is + It is possibly a Sierra 1502x + It's addressed by the TLIVESA1 driver for ET4000*/ +#include "ibm.h" +#include "mem.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_unk_ramdac.h" + +void unk_ramdac_out(uint16_t addr, uint8_t val, unk_ramdac_t *ramdac, svga_t *svga) +{ + //pclog("OUT RAMDAC %04X %02X\n",addr,val); + switch (addr) + { + case 0x3C6: + if (ramdac->state == 4) + { + ramdac->state = 0; + ramdac->ctrl = val; + switch ((val&1)|((val&0xE0)>>4)) + { + case 0: case 1: case 2: case 3: + svga->bpp = 8; + break; + case 6: case 7: + svga->bpp = 15; + break; + case 8: case 9: case 0xA: case 0xB: + svga->bpp = 16; + break; + case 0xC: case 0xD: case 0xE: case 0xF: + svga->bpp = 24; + break; + } + return; + } + ramdac->state = 0; + break; + case 0x3C7: case 0x3C8: case 0x3C9: + ramdac->state = 0; + break; + } + svga_out(addr, val, svga); +} + +uint8_t unk_ramdac_in(uint16_t addr, unk_ramdac_t *ramdac, svga_t *svga) +{ + //pclog("IN RAMDAC %04X\n",addr); + switch (addr) + { + case 0x3C6: + if (ramdac->state == 4) + { + ramdac->state = 0; + return ramdac->ctrl; + } + ramdac->state++; + break; + case 0x3C7: case 0x3C8: case 0x3C9: + ramdac->state = 0; + break; + } + return svga_in(addr, svga); +} diff --git a/src/vid_unk_ramdac.h b/src/vid_unk_ramdac.h new file mode 100644 index 000000000..0f92848f2 --- /dev/null +++ b/src/vid_unk_ramdac.h @@ -0,0 +1,8 @@ +typedef struct unk_ramdac_t +{ + int state; + uint8_t ctrl; +} unk_ramdac_t; + +void unk_ramdac_out(uint16_t addr, uint8_t val, unk_ramdac_t *ramdac, svga_t *svga); +uint8_t unk_ramdac_in(uint16_t addr, unk_ramdac_t *ramdac, svga_t *svga); diff --git a/src/vid_vga.c b/src/vid_vga.c new file mode 100644 index 000000000..a800e9bc2 --- /dev/null +++ b/src/vid_vga.c @@ -0,0 +1,181 @@ +/*IBM VGA emulation*/ +#include +#include "ibm.h" +#include "device.h" +#include "io.h" +#include "mem.h" +#include "rom.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_vga.h" + +typedef struct vga_t +{ + svga_t svga; + + rom_t bios_rom; +} vga_t; + +void vga_out(uint16_t addr, uint8_t val, void *p) +{ + vga_t *vga = (vga_t *)p; + svga_t *svga = &vga->svga; + uint8_t old; + +// pclog("vga_out : %04X %02X %04X:%04X %02X %i\n", addr, val, CS,pc, ram[0x489], ins); + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3D4: + svga->crtcreg = val & 0x1f; + return; + case 0x3D5: + if (svga->crtcreg <= 0x18) + val &= mask_crtc[svga->crtcreg]; + if ((svga->crtcreg < 7) && (svga->crtc[0x11] & 0x80)) + return; + if ((svga->crtcreg == 7) && (svga->crtc[0x11] & 0x80)) + val = (svga->crtc[7] & ~0x10) | (val & 0x10); + old = svga->crtc[svga->crtcreg]; + svga->crtc[svga->crtcreg] = val; + if (old != val) + { + if (svga->crtcreg < 0xe || svga->crtcreg > 0x10) + { + svga->fullchange = changeframecount; + svga_recalctimings(svga); + } + } + break; + } + svga_out(addr, val, svga); +} + +uint8_t vga_in(uint16_t addr, void *p) +{ + vga_t *vga = (vga_t *)p; + svga_t *svga = &vga->svga; + uint8_t temp; + +// if (addr != 0x3da) pclog("vga_in : %04X ", addr); + + if (((addr & 0xfff0) == 0x3d0 || (addr & 0xfff0) == 0x3b0) && !(svga->miscout & 1)) + addr ^= 0x60; + + switch (addr) + { + case 0x3D4: + temp = svga->crtcreg; + break; + case 0x3D5: + temp = svga->crtc[svga->crtcreg]; + break; + default: + temp = svga_in(addr, svga); + break; + } +// if (addr != 0x3da) pclog("%02X %04X:%04X\n", temp, CS,pc); + return temp; +} + +void *vga_init() +{ + vga_t *vga = malloc(sizeof(vga_t)); + memset(vga, 0, sizeof(vga_t)); + + rom_init(&vga->bios_rom, "roms/ibm_vga.bin", 0xc0000, 0x8000, 0x7fff, 0x2000, MEM_MAPPING_EXTERNAL); + + svga_init(&vga->svga, vga, 1 << 18, /*256kb*/ + NULL, + vga_in, vga_out, + NULL, + NULL); + + io_sethandler(0x03c0, 0x0020, vga_in, NULL, NULL, vga_out, NULL, NULL, vga); + + vga->svga.bpp = 8; + vga->svga.miscout = 1; + + return vga; +} + +/*PS/1 uses a standard VGA controller, but with no option ROM*/ +void *ps1vga_init() +{ + vga_t *vga = malloc(sizeof(vga_t)); + memset(vga, 0, sizeof(vga_t)); + + svga_init(&vga->svga, vga, 1 << 18, /*256kb*/ + NULL, + vga_in, vga_out, + NULL, + NULL); + + io_sethandler(0x03c0, 0x0020, vga_in, NULL, NULL, vga_out, NULL, NULL, vga); + + vga->svga.bpp = 8; + vga->svga.miscout = 1; + + return vga; +} + +static int vga_available() +{ + return rom_present("roms/ibm_vga.bin"); +} + +void vga_close(void *p) +{ + vga_t *vga = (vga_t *)p; + + svga_close(&vga->svga); + + free(vga); +} + +void vga_speed_changed(void *p) +{ + vga_t *vga = (vga_t *)p; + + svga_recalctimings(&vga->svga); +} + +void vga_force_redraw(void *p) +{ + vga_t *vga = (vga_t *)p; + + vga->svga.fullchange = changeframecount; +} + +void vga_add_status_info(char *s, int max_len, void *p) +{ + vga_t *vga = (vga_t *)p; + + svga_add_status_info(s, max_len, &vga->svga); +} + +device_t vga_device = +{ + "VGA", + 0, + vga_init, + vga_close, + vga_available, + vga_speed_changed, + vga_force_redraw, + vga_add_status_info +}; +device_t ps1vga_device = +{ + "PS/1 VGA", + 0, + ps1vga_init, + vga_close, + vga_available, + vga_speed_changed, + vga_force_redraw, + vga_add_status_info +}; diff --git a/src/vid_vga.h b/src/vid_vga.h new file mode 100644 index 000000000..9a45bef5d --- /dev/null +++ b/src/vid_vga.h @@ -0,0 +1,2 @@ +extern device_t vga_device; +extern device_t ps1vga_device; diff --git a/src/vid_voodoo.c b/src/vid_voodoo.c new file mode 100644 index 000000000..0acd6553c --- /dev/null +++ b/src/vid_voodoo.c @@ -0,0 +1,4565 @@ +#include +#include +#include "ibm.h" +#include "device.h" +#include "mem.h" +#include "pci.h" +#include "thread.h" +#include "timer.h" +#include "video.h" +#include "vid_svga.h" +#include "vid_voodoo.h" +#include "vid_voodoo_dither.h" + +#define MIN(a, b) ((a) < (b) ? (a) : (b)) + +#define CLAMP(x) (((x) < 0) ? 0 : (((x) > 0xff) ? 0xff : (x))) +#define CLAMP16(x) (((x) < 0) ? 0 : (((x) > 0xffff) ? 0xffff : (x))) + +#define LOD_MAX 8 + +static int tris = 0; + +static uint64_t status_time = 0; +static uint64_t voodoo_time = 0; +static int voodoo_render_time[2] = {0, 0}; +static int voodoo_render_time_old[2] = {0, 0}; + +typedef union int_float +{ + uint32_t i; + float f; +} int_float; + +typedef struct rgb_t +{ + uint8_t b, g, r; + uint8_t pad; +} rgb_t; +typedef struct rgba8_t +{ + uint8_t b, g, r, a; +} rgba8_t; + +typedef union rgba_u +{ + struct + { + uint8_t b, g, r, a; + } rgba; + uint32_t u; +} rgba_u; + +#define FIFO_SIZE 65536 +#define FIFO_MASK (FIFO_SIZE - 1) +#define FIFO_ENTRY_SIZE (1 << 31) + +#define FIFO_ENTRIES (voodoo->fifo_write_idx - voodoo->fifo_read_idx) +#define FIFO_FULL ((voodoo->fifo_write_idx - voodoo->fifo_read_idx) >= FIFO_SIZE) +#define FIFO_EMPTY (voodoo->fifo_read_idx == voodoo->fifo_write_idx) + +#define FIFO_TYPE 0xff000000 +#define FIFO_ADDR 0x00ffffff + +enum +{ + FIFO_INVALID = (0x00 << 24), + FIFO_WRITEL_REG = (0x01 << 24), + FIFO_WRITEW_FB = (0x02 << 24), + FIFO_WRITEL_FB = (0x03 << 24), + FIFO_WRITEL_TEX = (0x04 << 24) +}; + +#define PARAM_SIZE 1024 +#define PARAM_MASK (PARAM_SIZE - 1) +#define PARAM_ENTRY_SIZE (1 << 31) + +#define PARAM_ENTRIES_1 (voodoo->params_write_idx - voodoo->params_read_idx[0]) +#define PARAM_ENTRIES_2 (voodoo->params_write_idx - voodoo->params_read_idx[1]) +#define PARAM_FULL_1 ((voodoo->params_write_idx - voodoo->params_read_idx[0]) >= PARAM_SIZE) +#define PARAM_FULL_2 ((voodoo->params_write_idx - voodoo->params_read_idx[1]) >= PARAM_SIZE) +#define PARAM_EMPTY_1 (voodoo->params_read_idx[0] == voodoo->params_write_idx) +#define PARAM_EMPTY_2 (voodoo->params_read_idx[1] == voodoo->params_write_idx) + +typedef struct +{ + uint32_t addr_type; + uint32_t val; +} fifo_entry_t; + +static rgba8_t rgb332[0x100], ai44[0x100], rgb565[0x10000], argb1555[0x10000], argb4444[0x10000], ai88[0x10000]; + +typedef struct voodoo_params_t +{ + int command; + + int32_t vertexAx, vertexAy, vertexBx, vertexBy, vertexCx, vertexCy; + + uint32_t startR, startG, startB, startZ, startA; + + int32_t dBdX, dGdX, dRdX, dAdX, dZdX; + + int32_t dBdY, dGdY, dRdY, dAdY, dZdY; + + int64_t startW, dWdX, dWdY; + + struct + { + int64_t startS, startT, startW, p1; + int64_t dSdX, dTdX, dWdX, p2; + int64_t dSdY, dTdY, dWdY, p3; + } tmu[1]; + + uint32_t color0, color1; + + uint32_t fbzMode; + uint32_t fbzColorPath; + + uint32_t fogMode; + rgb_t fogColor; + struct + { + uint8_t fog, dfog; + } fogTable[64]; + + uint32_t alphaMode; + + uint32_t zaColor; + + int chromaKey_r, chromaKey_g, chromaKey_b; + uint32_t chromaKey; + + uint32_t textureMode; + uint32_t tLOD; + + uint32_t texBaseAddr, texBaseAddr1, texBaseAddr2, texBaseAddr38; + + uint32_t tex_base[LOD_MAX+1]; + int tex_width; + int tex_w_mask[LOD_MAX+1]; + int tex_w_nmask[LOD_MAX+1]; + int tex_h_mask[LOD_MAX+1]; + int tex_shift[LOD_MAX+1]; + + uint32_t draw_offset, aux_offset; + + int tformat; + + int clipLeft, clipRight, clipLowY, clipHighY; + + int sign; + + uint32_t front_offset; + + uint32_t swapbufferCMD; + + rgba_u palette[256]; +} voodoo_params_t; + +typedef struct voodoo_t +{ + mem_mapping_t mapping; + + int pci_enable; + + uint8_t dac_data[8]; + int dac_reg, dac_reg_ff; + uint8_t dac_readdata; + uint16_t dac_pll_regs[16]; + + float pixel_clock; + int line_time; + + voodoo_params_t params; + + uint32_t fbiInit0, fbiInit1, fbiInit2, fbiInit3, fbiInit4; + + uint8_t initEnable; + + uint32_t lfbMode; + + uint32_t memBaseAddr; + + int_float fvertexAx, fvertexAy, fvertexBx, fvertexBy, fvertexCx, fvertexCy; + + uint32_t front_offset, back_offset; + + uint32_t fb_read_offset, fb_write_offset; + + int row_width; + + uint8_t *fb_mem, *tex_mem; + uint16_t *tex_mem_w; + + int rgb_sel; + + uint32_t trexInit1; + + int swap_count; + + int disp_buffer; + int timer_count; + + int line; + svga_t *svga; + + uint32_t backPorch; + uint32_t videoDimensions; + uint32_t hSync, vSync; + + int v_total, v_disp; + int h_disp; + int v_retrace; + + struct + { + uint32_t y[4], i[4], q[4]; + } nccTable[2]; + + rgba_u palette[256]; + + rgba_u ncc_lookup[2][256]; + int ncc_dirty; + + thread_t *fifo_thread; + thread_t *render_thread[2]; + event_t *wake_fifo_thread; + event_t *wake_main_thread; + event_t *fifo_not_full_event; + event_t *render_not_full_event[2]; + event_t *wake_render_thread[2]; + + int voodoo_busy; + int render_voodoo_busy[2]; + + int render_threads; + int odd_even_mask; + + int pixel_count[2], tri_count, frame_count; + int pixel_count_old[2]; + int wr_count, rd_count, tex_count; + + int retrace_count; + int swap_interval; + uint32_t swap_offset; + int swap_pending; + + int bilinear_enabled; + + int fb_size; + uint32_t fb_mask; + + int texture_size; + uint32_t texture_mask; + + fifo_entry_t fifo[FIFO_SIZE]; + volatile int fifo_read_idx, fifo_write_idx; + int cmd_read, cmd_written; + + voodoo_params_t params_buffer[PARAM_SIZE]; + volatile int params_read_idx[2], params_write_idx; + + int flush; + + int scrfilter; + + uint32_t last_write_addr; + + uint32_t fbiPixelsIn; + uint32_t fbiChromaFail; + uint32_t fbiZFuncFail; + uint32_t fbiAFuncFail; + uint32_t fbiPixelsOut; + + rgb_t clutData[33]; + int clutData_dirty; + rgb_t clutData256[256]; + uint32_t video_16to32[0x10000]; + + uint8_t dirty_line[1024]; + int dirty_line_low, dirty_line_high; + + int fb_write_buffer, fb_draw_buffer; + + uint16_t thefilter[1024][1024]; // pixel filter, feeding from one or two + uint16_t thefilterg[1024][1024]; // for green + + /* the voodoo adds purple lines for some reason */ + uint16_t purpleline[1024]; + + int use_recompiler; + void *codegen_data; +} voodoo_t; + +enum +{ + SST_status = 0x000, + + SST_vertexAx = 0x008, + SST_vertexAy = 0x00c, + SST_vertexBx = 0x010, + SST_vertexBy = 0x014, + SST_vertexCx = 0x018, + SST_vertexCy = 0x01c, + + SST_startR = 0x0020, + SST_startG = 0x0024, + SST_startB = 0x0028, + SST_startZ = 0x002c, + SST_startA = 0x0030, + SST_startS = 0x0034, + SST_startT = 0x0038, + SST_startW = 0x003c, + + SST_dRdX = 0x0040, + SST_dGdX = 0x0044, + SST_dBdX = 0x0048, + SST_dZdX = 0x004c, + SST_dAdX = 0x0050, + SST_dSdX = 0x0054, + SST_dTdX = 0x0058, + SST_dWdX = 0x005c, + + SST_dRdY = 0x0060, + SST_dGdY = 0x0064, + SST_dBdY = 0x0068, + SST_dZdY = 0x006c, + SST_dAdY = 0x0070, + SST_dSdY = 0x0074, + SST_dTdY = 0x0078, + SST_dWdY = 0x007c, + + SST_triangleCMD = 0x0080, + + SST_fvertexAx = 0x088, + SST_fvertexAy = 0x08c, + SST_fvertexBx = 0x090, + SST_fvertexBy = 0x094, + SST_fvertexCx = 0x098, + SST_fvertexCy = 0x09c, + + SST_fstartR = 0x00a0, + SST_fstartG = 0x00a4, + SST_fstartB = 0x00a8, + SST_fstartZ = 0x00ac, + SST_fstartA = 0x00b0, + SST_fstartS = 0x00b4, + SST_fstartT = 0x00b8, + SST_fstartW = 0x00bc, + + SST_fdRdX = 0x00c0, + SST_fdGdX = 0x00c4, + SST_fdBdX = 0x00c8, + SST_fdZdX = 0x00cc, + SST_fdAdX = 0x00d0, + SST_fdSdX = 0x00d4, + SST_fdTdX = 0x00d8, + SST_fdWdX = 0x00dc, + + SST_fdRdY = 0x00e0, + SST_fdGdY = 0x00e4, + SST_fdBdY = 0x00e8, + SST_fdZdY = 0x00ec, + SST_fdAdY = 0x00f0, + SST_fdSdY = 0x00f4, + SST_fdTdY = 0x00f8, + SST_fdWdY = 0x00fc, + + SST_ftriangleCMD = 0x0100, + + SST_fbzColorPath = 0x104, + SST_fogMode = 0x108, + + SST_alphaMode = 0x10c, + SST_fbzMode = 0x110, + SST_lfbMode = 0x114, + + SST_clipLeftRight = 0x118, + SST_clipLowYHighY = 0x11c, + + SST_nopCMD = 0x120, + SST_fastfillCMD = 0x124, + SST_swapbufferCMD = 0x128, + + SST_fogColor = 0x12c, + SST_zaColor = 0x130, + SST_chromaKey = 0x134, + + SST_color0 = 0x144, + SST_color1 = 0x148, + + SST_fbiPixelsIn = 0x14c, + SST_fbiChromaFail = 0x150, + SST_fbiZFuncFail = 0x154, + SST_fbiAFuncFail = 0x158, + SST_fbiPixelsOut = 0x15c, + + SST_fogTable00 = 0x160, + SST_fogTable01 = 0x164, + SST_fogTable02 = 0x168, + SST_fogTable03 = 0x16c, + SST_fogTable04 = 0x170, + SST_fogTable05 = 0x174, + SST_fogTable06 = 0x178, + SST_fogTable07 = 0x17c, + SST_fogTable08 = 0x180, + SST_fogTable09 = 0x184, + SST_fogTable0a = 0x188, + SST_fogTable0b = 0x18c, + SST_fogTable0c = 0x190, + SST_fogTable0d = 0x194, + SST_fogTable0e = 0x198, + SST_fogTable0f = 0x19c, + SST_fogTable10 = 0x1a0, + SST_fogTable11 = 0x1a4, + SST_fogTable12 = 0x1a8, + SST_fogTable13 = 0x1ac, + SST_fogTable14 = 0x1b0, + SST_fogTable15 = 0x1b4, + SST_fogTable16 = 0x1b8, + SST_fogTable17 = 0x1bc, + SST_fogTable18 = 0x1c0, + SST_fogTable19 = 0x1c4, + SST_fogTable1a = 0x1c8, + SST_fogTable1b = 0x1cc, + SST_fogTable1c = 0x1d0, + SST_fogTable1d = 0x1d4, + SST_fogTable1e = 0x1d8, + SST_fogTable1f = 0x1dc, + + SST_fbiInit4 = 0x200, + + SST_backPorch = 0x208, + SST_videoDimensions = 0x20c, + SST_fbiInit0 = 0x210, + SST_fbiInit1 = 0x214, + SST_fbiInit2 = 0x218, + SST_fbiInit3 = 0x21c, + SST_hSync = 0x220, + SST_vSync = 0x224, + SST_clutData = 0x228, + SST_dacData = 0x22c, + + SST_textureMode = 0x300, + SST_tLOD = 0x304, + + SST_texBaseAddr = 0x30c, + SST_texBaseAddr1 = 0x310, + SST_texBaseAddr2 = 0x314, + SST_texBaseAddr38 = 0x318, + + SST_trexInit1 = 0x320, + + SST_nccTable0_Y0 = 0x324, + SST_nccTable0_Y1 = 0x328, + SST_nccTable0_Y2 = 0x32c, + SST_nccTable0_Y3 = 0x330, + SST_nccTable0_I0 = 0x334, + SST_nccTable0_I1 = 0x338, + SST_nccTable0_I2 = 0x33c, + SST_nccTable0_I3 = 0x340, + SST_nccTable0_Q0 = 0x344, + SST_nccTable0_Q1 = 0x348, + SST_nccTable0_Q2 = 0x34c, + SST_nccTable0_Q3 = 0x350, + + SST_nccTable1_Y0 = 0x354, + SST_nccTable1_Y1 = 0x358, + SST_nccTable1_Y2 = 0x35c, + SST_nccTable1_Y3 = 0x360, + SST_nccTable1_I0 = 0x364, + SST_nccTable1_I1 = 0x368, + SST_nccTable1_I2 = 0x36c, + SST_nccTable1_I3 = 0x370, + SST_nccTable1_Q0 = 0x374, + SST_nccTable1_Q1 = 0x378, + SST_nccTable1_Q2 = 0x37c, + SST_nccTable1_Q3 = 0x380, + + SST_remap_status = 0x000 | 0x400, + + SST_remap_vertexAx = 0x008 | 0x400, + SST_remap_vertexAy = 0x00c | 0x400, + SST_remap_vertexBx = 0x010 | 0x400, + SST_remap_vertexBy = 0x014 | 0x400, + SST_remap_vertexCx = 0x018 | 0x400, + SST_remap_vertexCy = 0x01c | 0x400, + + SST_remap_startR = 0x0020 | 0x400, + SST_remap_startG = 0x002c | 0x400, + SST_remap_startB = 0x0038 | 0x400, + SST_remap_startZ = 0x0044 | 0x400, + SST_remap_startA = 0x0050 | 0x400, + SST_remap_startS = 0x005c | 0x400, + SST_remap_startT = 0x0068 | 0x400, + SST_remap_startW = 0x0074 | 0x400, + + SST_remap_dRdX = 0x0024 | 0x400, + SST_remap_dGdX = 0x0030 | 0x400, + SST_remap_dBdX = 0x003c | 0x400, + SST_remap_dZdX = 0x0048 | 0x400, + SST_remap_dAdX = 0x0054 | 0x400, + SST_remap_dSdX = 0x0060 | 0x400, + SST_remap_dTdX = 0x006c | 0x400, + SST_remap_dWdX = 0x0078 | 0x400, + + SST_remap_dRdY = 0x0028 | 0x400, + SST_remap_dGdY = 0x0034 | 0x400, + SST_remap_dBdY = 0x0040 | 0x400, + SST_remap_dZdY = 0x004c | 0x400, + SST_remap_dAdY = 0x0058 | 0x400, + SST_remap_dSdY = 0x0064 | 0x400, + SST_remap_dTdY = 0x0070 | 0x400, + SST_remap_dWdY = 0x007c | 0x400, + + SST_remap_triangleCMD = 0x0080 | 0x400, + + SST_remap_fvertexAx = 0x088 | 0x400, + SST_remap_fvertexAy = 0x08c | 0x400, + SST_remap_fvertexBx = 0x090 | 0x400, + SST_remap_fvertexBy = 0x094 | 0x400, + SST_remap_fvertexCx = 0x098 | 0x400, + SST_remap_fvertexCy = 0x09c | 0x400, + + SST_remap_fstartR = 0x00a0 | 0x400, + SST_remap_fstartG = 0x00ac | 0x400, + SST_remap_fstartB = 0x00b8 | 0x400, + SST_remap_fstartZ = 0x00c4 | 0x400, + SST_remap_fstartA = 0x00d0 | 0x400, + SST_remap_fstartS = 0x00dc | 0x400, + SST_remap_fstartT = 0x00e8 | 0x400, + SST_remap_fstartW = 0x00f4 | 0x400, + + SST_remap_fdRdX = 0x00a4 | 0x400, + SST_remap_fdGdX = 0x00b0 | 0x400, + SST_remap_fdBdX = 0x00bc | 0x400, + SST_remap_fdZdX = 0x00c8 | 0x400, + SST_remap_fdAdX = 0x00d4 | 0x400, + SST_remap_fdSdX = 0x00e0 | 0x400, + SST_remap_fdTdX = 0x00ec | 0x400, + SST_remap_fdWdX = 0x00f8 | 0x400, + + SST_remap_fdRdY = 0x00a8 | 0x400, + SST_remap_fdGdY = 0x00b4 | 0x400, + SST_remap_fdBdY = 0x00c0 | 0x400, + SST_remap_fdZdY = 0x00cc | 0x400, + SST_remap_fdAdY = 0x00d8 | 0x400, + SST_remap_fdSdY = 0x00e4 | 0x400, + SST_remap_fdTdY = 0x00f0 | 0x400, + SST_remap_fdWdY = 0x00fc | 0x400, +}; + +enum +{ + LFB_WRITE_FRONT = 0x0000, + LFB_WRITE_BACK = 0x0010, + LFB_WRITE_MASK = 0x0030 +}; + +enum +{ + LFB_READ_FRONT = 0x0000, + LFB_READ_BACK = 0x0040, + LFB_READ_AUX = 0x0080, + LFB_READ_MASK = 0x00c0 +}; + +enum +{ + LFB_FORMAT_RGB565 = 0, + LFB_FORMAT_RGB555 = 1, + LFB_FORMAT_ARGB1555 = 2, + LFB_FORMAT_ARGB8888 = 5, + LFB_FORMAT_DEPTH = 15, + LFB_FORMAT_MASK = 15 +}; + +enum +{ + LFB_WRITE_COLOUR = 1, + LFB_WRITE_DEPTH = 2 +}; + +enum +{ + FBZ_CHROMAKEY = (1 << 1), + FBZ_W_BUFFER = (1 << 3), + FBZ_DEPTH_ENABLE = (1 << 4), + + FBZ_DITHER = (1 << 8), + FBZ_RGB_WMASK = (1 << 9), + FBZ_DEPTH_WMASK = (1 << 10), + FBZ_DITHER_2x2 = (1 << 11), + + FBZ_DRAW_FRONT = 0x0000, + FBZ_DRAW_BACK = 0x4000, + FBZ_DRAW_MASK = 0xc000, + + FBZ_DEPTH_BIAS = (1 << 16), + + FBZ_PARAM_ADJUST = (1 << 26) +}; + +enum +{ + TEX_RGB332 = 0x0, + TEX_Y4I2Q2 = 0x1, + TEX_A8 = 0x2, + TEX_I8 = 0x3, + TEX_AI8 = 0x4, + TEX_PAL8 = 0x5, + TEX_R5G6B5 = 0xa, + TEX_ARGB1555 = 0xb, + TEX_ARGB4444 = 0xc, + TEX_A8I8 = 0xd, + TEX_APAL88 = 0xe +}; + +enum +{ + TEXTUREMODE_NCC_SEL = (1 << 5), + TEXTUREMODE_TCLAMPS = (1 << 6), + TEXTUREMODE_TCLAMPT = (1 << 7) +}; + +enum +{ + FBIINIT0_VGA_PASS = 1 +}; + +enum +{ + FBIINIT3_REMAP = 1 +}; + +enum +{ + CC_LOCALSELECT_ITER_RGB = 0, + CC_LOCALSELECT_TEX = 1, + CC_LOCALSELECT_COLOR1 = 2, + CC_LOCALSELECT_LFB = 3 +}; + +enum +{ + CCA_LOCALSELECT_ITER_A = 0, + CCA_LOCALSELECT_COLOR0 = 1, + CCA_LOCALSELECT_ITER_Z = 2 +}; + +enum +{ + C_SEL_ITER_RGB = 0, + C_SEL_TEX = 1, + C_SEL_COLOR1 = 2, + C_SEL_LFB = 3 +}; + +enum +{ + A_SEL_ITER_A = 0, + A_SEL_TEX = 1, + A_SEL_COLOR1 = 2, + A_SEL_LFB = 3 +}; + +enum +{ + CC_MSELECT_ZERO = 0, + CC_MSELECT_CLOCAL = 1, + CC_MSELECT_AOTHER = 2, + CC_MSELECT_ALOCAL = 3, + CC_MSELECT_TEX = 4 +}; + +enum +{ + CCA_MSELECT_ZERO = 0, + CCA_MSELECT_ALOCAL = 1, + CCA_MSELECT_AOTHER = 2, + CCA_MSELECT_ALOCAL2 = 3, + CCA_MSELECT_TEX = 4 +}; + +enum +{ + CC_ADD_CLOCAL = 1, + CC_ADD_ALOCAL = 2 +}; + +enum +{ + CCA_ADD_CLOCAL = 1, + CCA_ADD_ALOCAL = 2 +}; + +enum +{ + AFUNC_AZERO = 0x0, + AFUNC_ASRC_ALPHA = 0x1, + AFUNC_A_COLOR = 0x2, + AFUNC_ADST_ALPHA = 0x3, + AFUNC_AONE = 0x4, + AFUNC_AOMSRC_ALPHA = 0x5, + AFUNC_AOM_COLOR = 0x6, + AFUNC_AOMDST_ALPHA = 0x7, + AFUNC_ASATURATE = 0xf +}; + +enum +{ + AFUNC_ACOLORBEFOREFOG = 0xf +}; + +enum +{ + AFUNC_NEVER = 0, + AFUNC_LESSTHAN = 1, + AFUNC_EQUAL = 2, + AFUNC_LESSTHANEQUAL = 3, + AFUNC_GREATERTHAN = 4, + AFUNC_NOTEQUAL = 5, + AFUNC_GREATERTHANEQUAL = 6, + AFUNC_ALWAYS = 7 +}; + +enum +{ + DEPTHOP_NEVER = 0, + DEPTHOP_LESSTHAN = 1, + DEPTHOP_EQUAL = 2, + DEPTHOP_LESSTHANEQUAL = 3, + DEPTHOP_GREATERTHAN = 4, + DEPTHOP_NOTEQUAL = 5, + DEPTHOP_GREATERTHANEQUAL = 6, + DEPTHOP_ALWAYS = 7 +}; + +enum +{ + FOG_ENABLE = 0x01, + FOG_ADD = 0x02, + FOG_MULT = 0x04, + FOG_ALPHA = 0x08, + FOG_Z = 0x10, + FOG_CONSTANT = 0x20 +}; + +enum +{ + LOD_S_IS_WIDER = (1 << 20) +}; +enum +{ + CMD_INVALID = 0, + CMD_DRAWTRIANGLE, + CMD_FASTFILL, + CMD_SWAPBUF +}; + +enum +{ + FBZCP_TEXTURE_ENABLED = (1 << 27) +}; + +static void voodoo_update_ncc(voodoo_t *voodoo) +{ + int tbl; + + for (tbl = 0; tbl < 2; tbl++) + { + int col; + + for (col = 0; col < 256; col++) + { + int y = (col >> 4), i = (col >> 2) & 3, q = col & 3; + int _y = (col >> 4), _i = (col >> 2) & 3, _q = col & 3; + int i_r, i_g, i_b; + int q_r, q_g, q_b; + int r, g, b; + + y = (voodoo->nccTable[tbl].y[y >> 2] >> ((y & 3) * 8)) & 0xff; + + i_r = (voodoo->nccTable[tbl].i[i] >> 18) & 0x1ff; + if (i_r & 0x100) + i_r |= 0xfffffe00; + i_g = (voodoo->nccTable[tbl].i[i] >> 9) & 0x1ff; + if (i_g & 0x100) + i_g |= 0xfffffe00; + i_b = voodoo->nccTable[tbl].i[i] & 0x1ff; + if (i_b & 0x100) + i_b |= 0xfffffe00; + + q_r = (voodoo->nccTable[tbl].q[q] >> 18) & 0x1ff; + if (q_r & 0x100) + q_r |= 0xfffffe00; + q_g = (voodoo->nccTable[tbl].q[q] >> 9) & 0x1ff; + if (q_g & 0x100) + q_g |= 0xfffffe00; + q_b = voodoo->nccTable[tbl].q[q] & 0x1ff; + if (q_b & 0x100) + q_b |= 0xfffffe00; + + voodoo->ncc_lookup[tbl][col].rgba.r = CLAMP(y + i_r + q_r); + voodoo->ncc_lookup[tbl][col].rgba.g = CLAMP(y + i_g + q_g); + voodoo->ncc_lookup[tbl][col].rgba.b = CLAMP(y + i_b + q_b); + voodoo->ncc_lookup[tbl][col].rgba.a = 0xff; + } + } +} + +static void voodoo_recalc(voodoo_t *voodoo) +{ + uint32_t buffer_offset = ((voodoo->fbiInit2 >> 11) & 511) * 4096; + + if (voodoo->disp_buffer) + { + voodoo->back_offset = 0; + voodoo->params.front_offset = buffer_offset; + } + else + { + voodoo->params.front_offset = 0; + voodoo->back_offset = buffer_offset; + } + voodoo->params.aux_offset = buffer_offset * 2; + + switch (voodoo->lfbMode & LFB_WRITE_MASK) + { + case LFB_WRITE_FRONT: + voodoo->fb_write_offset = voodoo->params.front_offset; + voodoo->fb_write_buffer = voodoo->disp_buffer ? 1 : 0; + break; + case LFB_WRITE_BACK: + voodoo->fb_write_offset = voodoo->back_offset; + voodoo->fb_write_buffer = voodoo->disp_buffer ? 0 : 1; + break; + + default: + /*BreakNeck sets invalid LFB write buffer select*/ + voodoo->fb_write_offset = voodoo->params.front_offset; + break; + } + + switch (voodoo->lfbMode & LFB_READ_MASK) + { + case LFB_READ_FRONT: + voodoo->fb_read_offset = voodoo->params.front_offset; + break; + case LFB_READ_BACK: + voodoo->fb_read_offset = voodoo->back_offset; + break; + case LFB_READ_AUX: + voodoo->fb_read_offset = voodoo->params.aux_offset; + break; + + default: + fatal("voodoo_recalc : unknown lfb source\n"); + } + + switch (voodoo->params.fbzMode & FBZ_DRAW_MASK) + { + case FBZ_DRAW_FRONT: + voodoo->params.draw_offset = voodoo->params.front_offset; + voodoo->fb_draw_buffer = voodoo->disp_buffer ? 1 : 0; + break; + case FBZ_DRAW_BACK: + voodoo->params.draw_offset = voodoo->back_offset; + voodoo->fb_draw_buffer = voodoo->disp_buffer ? 0 : 1; + break; + + default: + fatal("voodoo_recalc : unknown draw buffer\n"); + } + + voodoo->row_width = ((voodoo->fbiInit1 >> 4) & 15) * 64 * 2; +// pclog("voodoo_recalc : front_offset %08X back_offset %08X aux_offset %08X draw_offset %08x\n", voodoo->params.front_offset, voodoo->back_offset, voodoo->params.aux_offset, voodoo->params.draw_offset); +// pclog(" fb_read_offset %08X fb_write_offset %08X row_width %i %08x %08x\n", voodoo->fb_read_offset, voodoo->fb_write_offset, voodoo->row_width, voodoo->lfbMode, voodoo->params.fbzMode); +} + +static void voodoo_recalc_tex(voodoo_t *voodoo) +{ + int aspect = (voodoo->params.tLOD >> 21) & 3; + int width = 256, height = 256; + int shift = 8; + int lod; + int lod_min = (voodoo->params.tLOD >> 2) & 15; + int lod_max = (voodoo->params.tLOD >> 8) & 15; + uint32_t base = voodoo->params.texBaseAddr; + + if (voodoo->params.tLOD & LOD_S_IS_WIDER) + height >>= aspect; + else + { + width >>= aspect; + shift -= aspect; + } + + for (lod = 0; lod <= LOD_MAX; lod++) + { + if (!width) + width = 1; + if (!height) + height = 1; + if (shift < 0) + shift = 0; + voodoo->params.tex_base[lod] = base; + voodoo->params.tex_w_mask[lod] = width - 1; + voodoo->params.tex_w_nmask[lod] = ~(width - 1); + voodoo->params.tex_h_mask[lod] = height - 1; + voodoo->params.tex_shift[lod] = shift; +// pclog("LOD%i base=%08x %i-%i %i,%i wm=%02x hm=%02x sh=%i\n", lod, base, lod_min, lod_max, width, height, voodoo->params.tex_w_mask[lod], voodoo->params.tex_h_mask[lod], voodoo->params.tex_shift[lod]); + + if (voodoo->params.tformat & 8) + base += width * height * 2; + else + base += width * height; + + width >>= 1; + height >>= 1; + shift--; + } + + voodoo->params.tex_width = width; +} + +typedef struct voodoo_state_t +{ + int xstart, xend, xdir; + uint32_t base_r, base_g, base_b, base_a, base_z; + struct + { + int64_t base_s, base_t, base_w; + int lod; + } tmu[1]; + int64_t base_w; + int lod; + int lod_min, lod_max; + int dx1, dx2; + int y, yend, ydir; + int32_t dxAB, dxAC, dxBC; + int tex_b, tex_g, tex_r, tex_a; + int tex_s, tex_t; + int clamp_s, clamp_t; + + int32_t vertexAx, vertexAy, vertexBx, vertexBy, vertexCx, vertexCy; + + uint8_t *tex[LOD_MAX+1]; + uint16_t *tex_w[LOD_MAX+1]; + int tformat; + + rgba_u *palette; + + int *tex_w_mask; + int *tex_h_mask; + int *tex_shift; + + uint16_t *fb_mem, *aux_mem; + + int32_t ib, ig, ir, ia; + int32_t z; + + int32_t new_depth; + + int64_t tmu0_s, tmu0_t; + int64_t tmu0_w; + int64_t w; + + int pixel_count; + int x, x2; + + uint32_t w_depth; + + float log_temp; + uint32_t ebp_store; +} voodoo_state_t; + +static int voodoo_output = 0; + +static uint8_t logtable[256] = +{ + 0x00,0x01,0x02,0x04,0x05,0x07,0x08,0x09,0x0b,0x0c,0x0e,0x0f,0x10,0x12,0x13,0x15, + 0x16,0x17,0x19,0x1a,0x1b,0x1d,0x1e,0x1f,0x21,0x22,0x23,0x25,0x26,0x27,0x28,0x2a, + 0x2b,0x2c,0x2e,0x2f,0x30,0x31,0x33,0x34,0x35,0x36,0x38,0x39,0x3a,0x3b,0x3d,0x3e, + 0x3f,0x40,0x41,0x43,0x44,0x45,0x46,0x47,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x50,0x51, + 0x52,0x53,0x54,0x55,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x60,0x61,0x62,0x63, + 0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6c,0x6d,0x6e,0x6f,0x70,0x71,0x72,0x73,0x74, + 0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,0x80,0x81,0x83,0x84,0x85, + 0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8c,0x8d,0x8e,0x8f,0x90,0x91,0x92,0x93,0x94, + 0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,0xa0,0xa1,0xa2,0xa2,0xa3, + 0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xad,0xae,0xaf,0xb0,0xb1,0xb2, + 0xb3,0xb4,0xb5,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbc,0xbd,0xbe,0xbf,0xc0, + 0xc1,0xc2,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xcd, + 0xce,0xcf,0xd0,0xd1,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd6,0xd7,0xd8,0xd9,0xda,0xda, + 0xdb,0xdc,0xdd,0xde,0xde,0xdf,0xe0,0xe1,0xe1,0xe2,0xe3,0xe4,0xe5,0xe5,0xe6,0xe7, + 0xe8,0xe8,0xe9,0xea,0xeb,0xeb,0xec,0xed,0xee,0xef,0xef,0xf0,0xf1,0xf2,0xf2,0xf3, + 0xf4,0xf5,0xf5,0xf6,0xf7,0xf7,0xf8,0xf9,0xfa,0xfa,0xfb,0xfc,0xfd,0xfd,0xfe,0xff +}; + +static inline int fastlog(uint64_t val) +{ + uint64_t oldval = val; + int exp = 63; + int frac; + + if (!val || val & (1ULL << 63)) + return 0x80000000; + + if (!(val & 0xffffffff00000000)) + { + exp -= 32; + val <<= 32; + } + if (!(val & 0xffff000000000000)) + { + exp -= 16; + val <<= 16; + } + if (!(val & 0xff00000000000000)) + { + exp -= 8; + val <<= 8; + } + if (!(val & 0xf000000000000000)) + { + exp -= 4; + val <<= 4; + } + if (!(val & 0xc000000000000000)) + { + exp -= 2; + val <<= 2; + } + if (!(val & 0x8000000000000000)) + { + exp -= 1; + val <<= 1; + } + + if (exp >= 8) + frac = (oldval >> (exp - 8)) & 0xff; + else + frac = (oldval << (8 - exp)) & 0xff; + + return (exp << 8) | logtable[frac]; +} + +static inline int fls(uint16_t val) +{ + int num = 0; + +//pclog("fls(%04x) = ", val); + if (!(val & 0xff00)) + { + num += 8; + val <<= 8; + } + if (!(val & 0xf000)) + { + num += 4; + val <<= 4; + } + if (!(val & 0xc000)) + { + num += 2; + val <<= 2; + } + if (!(val & 0x8000)) + { + num += 1; + val <<= 1; + } +//pclog("%i %04x\n", num, val); + return num; +} + +typedef struct voodoo_texture_state_t +{ + int s, t; + int w_mask, h_mask; + int tex_shift; +} voodoo_texture_state_t; + +static inline void tex_read(voodoo_state_t *state, voodoo_texture_state_t *texture_state) +{ + uint16_t dat; + + if (texture_state->s & ~texture_state->w_mask) + { + if (state->clamp_s) + { + if (texture_state->s < 0) + texture_state->s = 0; + if (texture_state->s > texture_state->w_mask) + texture_state->s = texture_state->w_mask; + } + else + texture_state->s &= texture_state->w_mask; + } + if (texture_state->t & ~texture_state->h_mask) + { + if (state->clamp_t) + { + if (texture_state->t < 0) + texture_state->t = 0; + if (texture_state->t > texture_state->h_mask) + texture_state->t = texture_state->h_mask; + } + else + texture_state->t &= texture_state->h_mask; + } + + if (state->tformat & 8) + dat = state->tex_w[state->lod][texture_state->s + (texture_state->t << texture_state->tex_shift)]; + else + dat = state->tex[state->lod][texture_state->s + (texture_state->t << texture_state->tex_shift)]; + + switch (state->tformat) + { + case TEX_RGB332: + state->tex_r = rgb332[dat].r; + state->tex_g = rgb332[dat].g; + state->tex_b = rgb332[dat].b; + state->tex_a = 0xff; + break; + + case TEX_Y4I2Q2: + state->tex_r = state->palette[dat].rgba.r; + state->tex_g = state->palette[dat].rgba.g; + state->tex_b = state->palette[dat].rgba.b; + state->tex_a = 0xff; + break; + + case TEX_A8: + state->tex_r = state->tex_g = state->tex_b = state->tex_a = dat & 0xff; + break; + + case TEX_I8: + state->tex_r = state->tex_g = state->tex_b = dat & 0xff; + state->tex_a = 0xff; + break; + + case TEX_AI8: + state->tex_r = state->tex_g = state->tex_b = (dat & 0x0f) | ((dat << 4) & 0xf0); + state->tex_a = (dat & 0xf0) | ((dat >> 4) & 0x0f); + break; + + case TEX_PAL8: + state->tex_r = state->palette[dat].rgba.r; + state->tex_g = state->palette[dat].rgba.g; + state->tex_b = state->palette[dat].rgba.b; + state->tex_a = 0xff; + break; + + case TEX_R5G6B5: + state->tex_r = rgb565[dat].r; + state->tex_g = rgb565[dat].g; + state->tex_b = rgb565[dat].b; + state->tex_a = 0xff; + break; + + case TEX_ARGB1555: + state->tex_r = argb1555[dat].r; + state->tex_g = argb1555[dat].g; + state->tex_b = argb1555[dat].b; + state->tex_a = argb1555[dat].a; + break; + + case TEX_ARGB4444: + state->tex_r = argb4444[dat].r; + state->tex_g = argb4444[dat].g; + state->tex_b = argb4444[dat].b; + state->tex_a = argb4444[dat].a; + break; + + case TEX_A8I8: + state->tex_r = state->tex_g = state->tex_b = dat & 0xff; + state->tex_a = dat >> 8; + break; + + case TEX_APAL88: + state->tex_r = state->palette[dat & 0xff].rgba.r; + state->tex_g = state->palette[dat & 0xff].rgba.g; + state->tex_b = state->palette[dat & 0xff].rgba.b; + state->tex_a = dat >> 8; + break; + + default: + fatal("Unknown texture format %i\n", state->tformat); + } +} + +#define LOW4(x) ((x & 0x0f) | ((x & 0x0f) << 4)) +#define HIGH4(x) ((x & 0xf0) | ((x & 0xf0) >> 4)) + +static inline void tex_read_4(voodoo_state_t *state, voodoo_texture_state_t *texture_state, int s, int t, int *d) +{ + uint16_t dat[4]; + + if (((s | (s + 1)) & ~texture_state->w_mask) || ((t | (t + 1)) & ~texture_state->h_mask)) + { + int c; + for (c = 0; c < 4; c++) + { + int _s = s + (c & 1); + int _t = t + ((c & 2) >> 1); + + if (_s & ~texture_state->w_mask) + { + if (state->clamp_s) + { + if (_s < 0) + _s = 0; + if (_s > texture_state->w_mask) + _s = texture_state->w_mask; + } + else + _s &= texture_state->w_mask; + } + if (_t & ~texture_state->h_mask) + { + if (state->clamp_t) + { + if (_t < 0) + _t = 0; + if (_t > texture_state->h_mask) + _t = texture_state->h_mask; + } + else + _t &= texture_state->h_mask; + } + if (state->tformat & 8) + dat[c] = state->tex_w[state->lod][_s + (_t << texture_state->tex_shift)]; + else + dat[c] = state->tex[state->lod][_s + (_t << texture_state->tex_shift)]; + } + } + else + { + if (state->tformat & 8) + { + dat[0] = state->tex_w[state->lod][s + (t << texture_state->tex_shift)]; + dat[1] = state->tex_w[state->lod][s + 1 + (t << texture_state->tex_shift)]; + dat[2] = state->tex_w[state->lod][s + ((t + 1) << texture_state->tex_shift)]; + dat[3] = state->tex_w[state->lod][s + 1 + ((t + 1) << texture_state->tex_shift)]; + } + else + { + dat[0] = state->tex[state->lod][s + (t << texture_state->tex_shift)]; + dat[1] = state->tex[state->lod][s + 1 + (t << texture_state->tex_shift)]; + dat[2] = state->tex[state->lod][s + ((t + 1) << texture_state->tex_shift)]; + dat[3] = state->tex[state->lod][s + 1 + ((t + 1) << texture_state->tex_shift)]; + } + } + + switch (state->tformat) + { + case TEX_RGB332: + state->tex_r = (rgb332[dat[0]].r * d[0] + rgb332[dat[1]].r * d[1] + rgb332[dat[2]].r * d[2] + rgb332[dat[3]].r * d[3]) >> 8; + state->tex_g = (rgb332[dat[0]].g * d[0] + rgb332[dat[1]].g * d[1] + rgb332[dat[2]].g * d[2] + rgb332[dat[3]].g * d[3]) >> 8; + state->tex_b = (rgb332[dat[0]].b * d[0] + rgb332[dat[1]].b * d[1] + rgb332[dat[2]].b * d[2] + rgb332[dat[3]].b * d[3]) >> 8; + state->tex_a = 0xff; + break; + + case TEX_Y4I2Q2: + state->tex_r = (state->palette[dat[0]].rgba.r * d[0] + state->palette[dat[1]].rgba.r * d[1] + state->palette[dat[2]].rgba.r * d[2] + state->palette[dat[3]].rgba.r * d[3]) >> 8; + state->tex_g = (state->palette[dat[0]].rgba.g * d[0] + state->palette[dat[1]].rgba.g * d[1] + state->palette[dat[2]].rgba.g * d[2] + state->palette[dat[3]].rgba.g * d[3]) >> 8; + state->tex_b = (state->palette[dat[0]].rgba.b * d[0] + state->palette[dat[1]].rgba.b * d[1] + state->palette[dat[2]].rgba.b * d[2] + state->palette[dat[3]].rgba.b * d[3]) >> 8; + state->tex_a = 0xff; + break; + + case TEX_A8: + state->tex_r = state->tex_g = state->tex_b = state->tex_a = (dat[0] * d[0] + dat[1] * d[1] + dat[2] * d[2] + dat[3] * d[3]) >> 8; + break; + + case TEX_I8: + state->tex_r = state->tex_g = state->tex_b = (dat[0] * d[0] + dat[1] * d[1] + dat[2] * d[2] + dat[3] * d[3]) >> 8; + state->tex_a = 0xff; + break; + + case TEX_AI8: + state->tex_r = state->tex_g = state->tex_b = (LOW4(dat[0]) * d[0] + LOW4(dat[1]) * d[1] + LOW4(dat[2]) * d[2] + LOW4(dat[3]) * d[3]) >> 8; + state->tex_a = (HIGH4(dat[0]) * d[0] + HIGH4(dat[1]) * d[1] + HIGH4(dat[2]) * d[2] + HIGH4(dat[3]) * d[3]) >> 8; + break; + + case TEX_PAL8: + state->tex_r = (state->palette[dat[0]].rgba.r * d[0] + state->palette[dat[1]].rgba.r * d[1] + state->palette[dat[2]].rgba.r * d[2] + state->palette[dat[3]].rgba.r * d[3]) >> 8; + state->tex_g = (state->palette[dat[0]].rgba.g * d[0] + state->palette[dat[1]].rgba.g * d[1] + state->palette[dat[2]].rgba.g * d[2] + state->palette[dat[3]].rgba.g * d[3]) >> 8; + state->tex_b = (state->palette[dat[0]].rgba.b * d[0] + state->palette[dat[1]].rgba.b * d[1] + state->palette[dat[2]].rgba.b * d[2] + state->palette[dat[3]].rgba.b * d[3]) >> 8; + state->tex_a = 0xff; + break; + + case TEX_R5G6B5: + state->tex_r = (rgb565[dat[0]].r * d[0] + rgb565[dat[1]].r * d[1] + rgb565[dat[2]].r * d[2] + rgb565[dat[3]].r * d[3]) >> 8; + state->tex_g = (rgb565[dat[0]].g * d[0] + rgb565[dat[1]].g * d[1] + rgb565[dat[2]].g * d[2] + rgb565[dat[3]].g * d[3]) >> 8; + state->tex_b = (rgb565[dat[0]].b * d[0] + rgb565[dat[1]].b * d[1] + rgb565[dat[2]].b * d[2] + rgb565[dat[3]].b * d[3]) >> 8; + state->tex_a = 0xff; + break; + + case TEX_ARGB1555: + state->tex_r = (argb1555[dat[0]].r * d[0] + argb1555[dat[1]].r * d[1] + argb1555[dat[2]].r * d[2] + argb1555[dat[3]].r * d[3]) >> 8; + state->tex_g = (argb1555[dat[0]].g * d[0] + argb1555[dat[1]].g * d[1] + argb1555[dat[2]].g * d[2] + argb1555[dat[3]].g * d[3]) >> 8; + state->tex_b = (argb1555[dat[0]].b * d[0] + argb1555[dat[1]].b * d[1] + argb1555[dat[2]].b * d[2] + argb1555[dat[3]].b * d[3]) >> 8; + state->tex_a = (argb1555[dat[0]].a * d[0] + argb1555[dat[1]].a * d[1] + argb1555[dat[2]].a * d[2] + argb1555[dat[3]].a * d[3]) >> 8; + break; + + case TEX_ARGB4444: + state->tex_r = (argb4444[dat[0]].r * d[0] + argb4444[dat[1]].r * d[1] + argb4444[dat[2]].r * d[2] + argb4444[dat[3]].r * d[3]) >> 8; + state->tex_g = (argb4444[dat[0]].g * d[0] + argb4444[dat[1]].g * d[1] + argb4444[dat[2]].g * d[2] + argb4444[dat[3]].g * d[3]) >> 8; + state->tex_b = (argb4444[dat[0]].b * d[0] + argb4444[dat[1]].b * d[1] + argb4444[dat[2]].b * d[2] + argb4444[dat[3]].b * d[3]) >> 8; + state->tex_a = (argb4444[dat[0]].a * d[0] + argb4444[dat[1]].a * d[1] + argb4444[dat[2]].a * d[2] + argb4444[dat[3]].a * d[3]) >> 8; + break; + + case TEX_A8I8: + state->tex_r = state->tex_g = state->tex_b = ((dat[0] & 0xff) * d[0] + (dat[1] & 0xff) * d[1] + (dat[2] & 0xff) * d[2] + (dat[3] & 0xff) * d[3]) >> 8; + state->tex_a = ((dat[0] >> 8) * d[0] + (dat[1] >> 8) * d[1] + (dat[2] >> 8) * d[2] + (dat[3] >> 8) * d[3]) >> 8; + break; + + case TEX_APAL88: + state->tex_r = (state->palette[dat[0] & 0xff].rgba.r * d[0] + state->palette[dat[1] & 0xff].rgba.r * d[1] + state->palette[dat[2] & 0xff].rgba.r * d[2] + state->palette[dat[3] & 0xff].rgba.r * d[3]) >> 8; + state->tex_g = (state->palette[dat[0] & 0xff].rgba.g * d[0] + state->palette[dat[1] & 0xff].rgba.g * d[1] + state->palette[dat[2] & 0xff].rgba.g * d[2] + state->palette[dat[3] & 0xff].rgba.g * d[3]) >> 8; + state->tex_b = (state->palette[dat[0] & 0xff].rgba.b * d[0] + state->palette[dat[1] & 0xff].rgba.b * d[1] + state->palette[dat[2] & 0xff].rgba.b * d[2] + state->palette[dat[3] & 0xff].rgba.b * d[3]) >> 8; + state->tex_a = ((dat[0] >> 8) * d[0] + (dat[1] >> 8) * d[1] + (dat[2] >> 8) * d[2] + (dat[3] >> 8) * d[3]) >> 8; + break; + + default: + fatal("Unknown texture format %i\n", state->tformat); + } +} + +static inline void voodoo_get_texture(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state) +{ + rgba_u tex_samples[4]; + voodoo_texture_state_t texture_state; + int d[4]; + int s, t; + + texture_state.w_mask = state->tex_w_mask[state->lod]; + texture_state.h_mask = state->tex_h_mask[state->lod]; + texture_state.tex_shift = state->tex_shift[state->lod]; + + if (voodoo->bilinear_enabled && params->textureMode & 6) + { + int _ds, dt; + + state->tex_s -= 1 << (3+state->lod); + state->tex_t -= 1 << (3+state->lod); + + s = state->tex_s >> state->lod; + t = state->tex_t >> state->lod; + + _ds = s & 0xf; + dt = t & 0xf; + + s >>= 4; + t >>= 4; + +//if (x == 80) +//if (voodoo_output) +// pclog("s=%08x t=%08x _ds=%02x _dt=%02x\n", s, t, _ds, dt); + d[0] = (16 - _ds) * (16 - dt); + d[1] = _ds * (16 - dt); + d[2] = (16 - _ds) * dt; + d[3] = _ds * dt; + +// texture_state.s = s; +// texture_state.t = t; + tex_read_4(state, &texture_state, s, t, d); + + +/* state->tex_r = (tex_samples[0].rgba.r * d[0] + tex_samples[1].rgba.r * d[1] + tex_samples[2].rgba.r * d[2] + tex_samples[3].rgba.r * d[3]) >> 8; + state->tex_g = (tex_samples[0].rgba.g * d[0] + tex_samples[1].rgba.g * d[1] + tex_samples[2].rgba.g * d[2] + tex_samples[3].rgba.g * d[3]) >> 8; + state->tex_b = (tex_samples[0].rgba.b * d[0] + tex_samples[1].rgba.b * d[1] + tex_samples[2].rgba.b * d[2] + tex_samples[3].rgba.b * d[3]) >> 8; + state->tex_a = (tex_samples[0].rgba.a * d[0] + tex_samples[1].rgba.a * d[1] + tex_samples[2].rgba.a * d[2] + tex_samples[3].rgba.a * d[3]) >> 8;*/ +/* state->tex_r = tex_samples[0].r; + state->tex_g = tex_samples[0].g; + state->tex_b = tex_samples[0].b; + state->tex_a = tex_samples[0].a;*/ + } + else + { + // rgba_t tex_samples; + // voodoo_texture_state_t texture_state; +// int s = state->tex_s >> (18+state->lod); +// int t = state->tex_t >> (18+state->lod); + // int s, t; + +// state->tex_s -= 1 << (17+state->lod); +// state->tex_t -= 1 << (17+state->lod); + + s = state->tex_s >> (4+state->lod); + t = state->tex_t >> (4+state->lod); + + texture_state.s = s; + texture_state.t = t; + tex_read(state, &texture_state); + +/* state->tex_r = tex_samples[0].rgba.r; + state->tex_g = tex_samples[0].rgba.g; + state->tex_b = tex_samples[0].rgba.b; + state->tex_a = tex_samples[0].rgba.a;*/ + } +} + + +#define DEPTH_TEST() \ + do \ + { \ + switch (depth_op) \ + { \ + case DEPTHOP_NEVER: \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + case DEPTHOP_LESSTHAN: \ + if (!(new_depth < old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_EQUAL: \ + if (!(new_depth == old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_LESSTHANEQUAL: \ + if (!(new_depth <= old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_GREATERTHAN: \ + if (!(new_depth > old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_NOTEQUAL: \ + if (!(new_depth != old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_GREATERTHANEQUAL: \ + if (!(new_depth >= old_depth)) \ + { \ + voodoo->fbiZFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case DEPTHOP_ALWAYS: \ + break; \ + } \ + } while (0) + +#define APPLY_FOG(src_r, src_g, src_b, z, ia) \ + do \ + { \ + if (params->fogMode & FOG_CONSTANT) \ + { \ + src_r += params->fogColor.r; \ + src_g += params->fogColor.g; \ + src_b += params->fogColor.b; \ + } \ + else \ + { \ + int fog_r, fog_g, fog_b, fog_a; \ + \ + if (!(params->fogMode & FOG_ADD)) \ + { \ + fog_r = params->fogColor.r; \ + fog_g = params->fogColor.g; \ + fog_b = params->fogColor.b; \ + } \ + else \ + fog_r = fog_g = fog_b = 0; \ + \ + if (!(params->fogMode & FOG_MULT)) \ + { \ + fog_r -= src_r; \ + fog_g -= src_g; \ + fog_b -= src_b; \ + } \ + \ + if (params->fogMode & FOG_Z) \ + fog_a = (z >> 20) & 0xff; \ + else if (params->fogMode & FOG_ALPHA) \ + fog_a = CLAMP(ia >> 12); \ + else \ + { \ + int fog_idx = (w_depth >> 10) & 0x3f; \ + \ + fog_a = params->fogTable[fog_idx].fog; \ + fog_a += (params->fogTable[fog_idx].dfog * ((w_depth >> 2) & 0xff)) >> 10; \ + } \ + fog_a++; \ + \ + fog_r = (fog_r * fog_a) >> 8; \ + fog_g = (fog_g * fog_a) >> 8; \ + fog_b = (fog_b * fog_a) >> 8; \ + \ + if (params->fogMode & FOG_MULT) \ + { \ + src_r = fog_r; \ + src_g = fog_g; \ + src_b = fog_b; \ + } \ + else \ + { \ + src_r += fog_r; \ + src_g += fog_g; \ + src_b += fog_b; \ + } \ + } \ + \ + src_r = CLAMP(src_r); \ + src_g = CLAMP(src_g); \ + src_b = CLAMP(src_b); \ + } while (0) + +#define ALPHA_TEST(src_a) \ + do \ + { \ + switch (alpha_func) \ + { \ + case AFUNC_NEVER: \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + case AFUNC_LESSTHAN: \ + if (!(src_a < a_ref)) \ + { \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case AFUNC_EQUAL: \ + if (!(src_a == a_ref)) \ + { \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case AFUNC_LESSTHANEQUAL: \ + if (!(src_a <= a_ref)) \ + { \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case AFUNC_GREATERTHAN: \ + if (!(src_a > a_ref)) \ + { \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case AFUNC_NOTEQUAL: \ + if (!(src_a != a_ref)) \ + { \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case AFUNC_GREATERTHANEQUAL: \ + if (!(src_a >= a_ref)) \ + { \ + voodoo->fbiAFuncFail++; \ + goto skip_pixel; \ + } \ + break; \ + case AFUNC_ALWAYS: \ + break; \ + } \ + } while (0) + +#define ALPHA_BLEND(src_r, src_g, src_b, src_a) \ + do \ + { \ + int _a; \ + int newdest_r, newdest_g, newdest_b; \ + \ + switch (dest_afunc) \ + { \ + case AFUNC_AZERO: \ + newdest_r = newdest_g = newdest_b = 0; \ + break; \ + case AFUNC_ASRC_ALPHA: \ + newdest_r = (dest_r * src_a) / 255; \ + newdest_g = (dest_g * src_a) / 255; \ + newdest_b = (dest_b * src_a) / 255; \ + break; \ + case AFUNC_A_COLOR: \ + newdest_r = (dest_r * src_r) / 255; \ + newdest_g = (dest_g * src_g) / 255; \ + newdest_b = (dest_b * src_b) / 255; \ + break; \ + case AFUNC_ADST_ALPHA: \ + newdest_r = (dest_r * dest_a) / 255; \ + newdest_g = (dest_g * dest_a) / 255; \ + newdest_b = (dest_b * dest_a) / 255; \ + break; \ + case AFUNC_AONE: \ + newdest_r = dest_r; \ + newdest_g = dest_g; \ + newdest_b = dest_b; \ + break; \ + case AFUNC_AOMSRC_ALPHA: \ + newdest_r = (dest_r * (255-src_a)) / 255; \ + newdest_g = (dest_g * (255-src_a)) / 255; \ + newdest_b = (dest_b * (255-src_a)) / 255; \ + break; \ + case AFUNC_AOM_COLOR: \ + newdest_r = (dest_r * (255-src_r)) / 255; \ + newdest_g = (dest_g * (255-src_g)) / 255; \ + newdest_b = (dest_b * (255-src_b)) / 255; \ + break; \ + case AFUNC_AOMDST_ALPHA: \ + newdest_r = (dest_r * (255-dest_a)) / 255; \ + newdest_g = (dest_g * (255-dest_a)) / 255; \ + newdest_b = (dest_b * (255-dest_a)) / 255; \ + break; \ + case AFUNC_ASATURATE: \ + _a = MIN(src_a, 1-dest_a); \ + newdest_r = (dest_r * _a) / 255; \ + newdest_g = (dest_g * _a) / 255; \ + newdest_b = (dest_b * _a) / 255; \ + break; \ + } \ + \ + switch (src_afunc) \ + { \ + case AFUNC_AZERO: \ + src_r = src_g = src_b = 0; \ + break; \ + case AFUNC_ASRC_ALPHA: \ + src_r = (src_r * src_a) / 255; \ + src_g = (src_g * src_a) / 255; \ + src_b = (src_b * src_a) / 255; \ + break; \ + case AFUNC_A_COLOR: \ + src_r = (src_r * dest_r) / 255; \ + src_g = (src_g * dest_g) / 255; \ + src_b = (src_b * dest_b) / 255; \ + break; \ + case AFUNC_ADST_ALPHA: \ + src_r = (src_r * dest_a) / 255; \ + src_g = (src_g * dest_a) / 255; \ + src_b = (src_b * dest_a) / 255; \ + break; \ + case AFUNC_AONE: \ + break; \ + case AFUNC_AOMSRC_ALPHA: \ + src_r = (src_r * (255-src_a)) / 255; \ + src_g = (src_g * (255-src_a)) / 255; \ + src_b = (src_b * (255-src_a)) / 255; \ + break; \ + case AFUNC_AOM_COLOR: \ + src_r = (src_r * (255-dest_r)) / 255; \ + src_g = (src_g * (255-dest_g)) / 255; \ + src_b = (src_b * (255-dest_b)) / 255; \ + break; \ + case AFUNC_AOMDST_ALPHA: \ + src_r = (src_r * (255-dest_a)) / 255; \ + src_g = (src_g * (255-dest_a)) / 255; \ + src_b = (src_b * (255-dest_a)) / 255; \ + break; \ + case AFUNC_ACOLORBEFOREFOG: \ + break; \ + } \ + \ + src_r += newdest_r; \ + src_g += newdest_g; \ + src_b += newdest_b; \ + \ + src_r = CLAMP(src_r); \ + src_g = CLAMP(src_g); \ + src_b = CLAMP(src_b); \ + } while(0) + + +#define _rgb_sel ( params->fbzColorPath & 3) +#define a_sel ( (params->fbzColorPath >> 2) & 3) +#define cc_localselect ( params->fbzColorPath & (1 << 4)) +#define cca_localselect ( (params->fbzColorPath >> 5) & 3) +#define cc_localselect_override ( params->fbzColorPath & (1 << 7)) +#define cc_zero_other ( params->fbzColorPath & (1 << 8)) +#define cc_sub_clocal ( params->fbzColorPath & (1 << 9)) +#define cc_mselect ( (params->fbzColorPath >> 10) & 7) +#define cc_reverse_blend ( params->fbzColorPath & (1 << 13)) +#define cc_add ( (params->fbzColorPath >> 14) & 3) +#define cc_add_alocal ( params->fbzColorPath & (1 << 15)) +#define cc_invert_output ( params->fbzColorPath & (1 << 16)) +#define cca_zero_other ( params->fbzColorPath & (1 << 17)) +#define cca_sub_clocal ( params->fbzColorPath & (1 << 18)) +#define cca_mselect ( (params->fbzColorPath >> 19) & 7) +#define cca_reverse_blend ( params->fbzColorPath & (1 << 22)) +#define cca_add ( (params->fbzColorPath >> 23) & 3) +#define cca_invert_output ( params->fbzColorPath & (1 << 25)) +#define src_afunc ( (params->alphaMode >> 8) & 0xf) +#define dest_afunc ( (params->alphaMode >> 12) & 0xf) +#define alpha_func ( (params->alphaMode >> 1) & 7) +#define a_ref ( params->alphaMode >> 24) +#define depth_op ( (params->fbzMode >> 5) & 7) +#define dither ( params->fbzMode & FBZ_DITHER) +#define dither2x2 (params->fbzMode & FBZ_DITHER_2x2) + +#if (defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32) && !(defined __amd64__) +#include "vid_voodoo_codegen_x86.h" +#elif (defined __amd64__) +#include "vid_voodoo_codegen_x86-64.h" +#else +#define NO_CODEGEN +static int voodoo_recomp = 0; +#endif + +static void voodoo_half_triangle(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int ystart, int yend, int odd_even) +{ +/* int rgb_sel = params->fbzColorPath & 3; + int a_sel = (params->fbzColorPath >> 2) & 3; + int cc_localselect = params->fbzColorPath & (1 << 4); + int cca_localselect = (params->fbzColorPath >> 5) & 3; + int cc_localselect_override = params->fbzColorPath & (1 << 7); + int cc_zero_other = params->fbzColorPath & (1 << 8); + int cc_sub_clocal = params->fbzColorPath & (1 << 9); + int cc_mselect = (params->fbzColorPath >> 10) & 7; + int cc_reverse_blend = params->fbzColorPath & (1 << 13); + int cc_add = (params->fbzColorPath >> 14) & 3; + int cc_add_alocal = params->fbzColorPath & (1 << 15); + int cc_invert_output = params->fbzColorPath & (1 << 16); + int cca_zero_other = params->fbzColorPath & (1 << 17); + int cca_sub_clocal = params->fbzColorPath & (1 << 18); + int cca_mselect = (params->fbzColorPath >> 19) & 7; + int cca_reverse_blend = params->fbzColorPath & (1 << 22); + int cca_add = (params->fbzColorPath >> 23) & 3; + int cca_invert_output = params->fbzColorPath & (1 << 25); + int src_afunc = (params->alphaMode >> 8) & 0xf; + int dest_afunc = (params->alphaMode >> 12) & 0xf; + int alpha_func = (params->alphaMode >> 1) & 7; + int a_ref = params->alphaMode >> 24; + int depth_op = (params->fbzMode >> 5) & 7; + int dither = params->fbzMode & FBZ_DITHER;*/ + int c; + uint8_t (*voodoo_draw)(voodoo_state_t *state, voodoo_params_t *params, int x, int real_y); + + state->clamp_s = params->textureMode & TEXTUREMODE_TCLAMPS; + state->clamp_t = params->textureMode & TEXTUREMODE_TCLAMPT; +// int last_x; +// pclog("voodoo_triangle : bottom-half %X %X %X %X %X %i %i %i %i\n", xstart, xend, dx1, dx2, dx2 * 36, xdir, y, yend, ydir); + + for (c = 0; c <= LOD_MAX; c++) + { + state->tex[c] = &voodoo->tex_mem[params->tex_base[c] & voodoo->texture_mask]; + state->tex_w[c] = (uint16_t *)state->tex[c]; + } + + state->tformat = params->tformat; + + state->tex_w_mask = params->tex_w_mask; + state->tex_h_mask = params->tex_h_mask; + state->tex_shift = params->tex_shift; + + if ((params->fbzMode & 1) && (ystart < params->clipLowY)) + { + int dy = params->clipLowY - ystart; + + state->base_r += params->dRdY*dy; + state->base_g += params->dGdY*dy; + state->base_b += params->dBdY*dy; + state->base_a += params->dAdY*dy; + state->base_z += params->dZdY*dy; + state->tmu[0].base_s += params->tmu[0].dSdY*dy; + state->tmu[0].base_t += params->tmu[0].dTdY*dy; + state->tmu[0].base_w += params->tmu[0].dWdY*dy; + state->base_w += params->dWdY*dy; + state->xstart += state->dx1*dy; + state->xend += state->dx2*dy; + + ystart = params->clipLowY; + } + + if ((params->fbzMode & 1) && (yend > params->clipHighY)) + yend = params->clipHighY; + + state->y = ystart; +// yend--; + +#ifndef NO_CODEGEN + if (voodoo->use_recompiler) + voodoo_draw = voodoo_get_block(voodoo, params, state, odd_even); +#endif + +#if 0 + if (voodoo_output) + pclog("dxAB=%08x dxBC=%08x dxAC=%08x\n", state->dxAB, state->dxBC, state->dxAC); +#endif +// pclog("Start %i %i\n", ystart, voodoo->fbzMode & (1 << 17)); + for (; state->y < yend; state->y++) + { + int x, x2; + int real_y = (state->y << 4) + 8; + int start_x, start_x2; + int dx; + uint16_t *fb_mem, *aux_mem; + + state->ir = state->base_r; + state->ig = state->base_g; + state->ib = state->base_b; + state->ia = state->base_a; + state->z = state->base_z; + state->tmu0_s = state->tmu[0].base_s; + state->tmu0_t = state->tmu[0].base_t; + state->tmu0_w = state->tmu[0].base_w; + state->w = state->base_w; + + x = (state->vertexAx << 12) + ((state->dxAC * (real_y - state->vertexAy)) >> 4); + + if (real_y < state->vertexBy) + x2 = (state->vertexAx << 12) + ((state->dxAB * (real_y - state->vertexAy)) >> 4); + else + x2 = (state->vertexBx << 12) + ((state->dxBC * (real_y - state->vertexBy)) >> 4); + + if (params->fbzMode & (1 << 17)) + real_y = (voodoo->v_disp-1) - (real_y >> 4); + else + real_y >>= 4; + + if ((real_y & voodoo->odd_even_mask) != odd_even) + goto next_line; + + start_x = x; + + if (state->xdir > 0) + x2 -= (1 << 16); + else + x -= (1 << 16); + dx = ((x + 0x7000) >> 16) - (((state->vertexAx << 12) + 0x7000) >> 16); + start_x2 = x + 0x7000; + x = (x + 0x7000) >> 16; + x2 = (x2 + 0x7000) >> 16; + +#if 0 + if (voodoo_output) + pclog("%03i:%03i : Ax=%08x start_x=%08x dSdX=%016llx dx=%08x s=%08x -> ", x, state->y, state->vertexAx << 8, start_x, params->tmu[0].dTdX, dx, state->tmu0_t); +#endif + + state->ir += (params->dRdX * dx); + state->ig += (params->dGdX * dx); + state->ib += (params->dBdX * dx); + state->ia += (params->dAdX * dx); + state->z += (params->dZdX * dx); + state->tmu0_s += (params->tmu[0].dSdX * dx); + state->tmu0_t += (params->tmu[0].dTdX * dx); + state->tmu0_w += (params->tmu[0].dWdX * dx); + state->w += (params->dWdX * dx); + +#if 0 + if (voodoo_output) + pclog("%08llx %lli %lli\n", state->tmu0_t, state->tmu0_t >> (18+state->lod), (state->tmu0_t + (1 << 17+state->lod)) >> (18+state->lod)); +#endif + + if (params->fbzMode & 1) + { + if (state->xdir > 0) + { + if (x < params->clipLeft) + { + int dx = params->clipLeft - x; + + state->ir += params->dRdX*dx; + state->ig += params->dGdX*dx; + state->ib += params->dBdX*dx; + state->ia += params->dAdX*dx; + state->z += params->dZdX*dx; + state->tmu0_s += params->tmu[0].dSdX*dx; + state->tmu0_t += params->tmu[0].dTdX*dx; + state->tmu0_w += params->tmu[0].dWdX*dx; + state->w += params->dWdX*dx; + + x = params->clipLeft; + } + if (x2 > params->clipRight) + x2 = params->clipRight; + } + else + { + if (x > params->clipRight) + { + int dx = params->clipRight - x; + + state->ir += params->dRdX*dx; + state->ig += params->dGdX*dx; + state->ib += params->dBdX*dx; + state->ia += params->dAdX*dx; + state->z += params->dZdX*dx; + state->tmu0_s += params->tmu[0].dSdX*dx; + state->tmu0_t += params->tmu[0].dTdX*dx; + state->tmu0_w += params->tmu[0].dWdX*dx; + state->w += params->dWdX*dx; + + x = params->clipRight; + } + if (x2 < params->clipLeft) + x2 = params->clipLeft; + } + } + + if (x2 < x && state->xdir > 0) + goto next_line; + if (x2 > x && state->xdir < 0) + goto next_line; + + state->fb_mem = fb_mem = &voodoo->fb_mem[params->draw_offset + (real_y * voodoo->row_width)]; + state->aux_mem = aux_mem = &voodoo->fb_mem[params->aux_offset + (real_y * voodoo->row_width)]; + +#if 0 + if (voodoo_output) + pclog("%03i: x=%08x x2=%08x xstart=%08x xend=%08x dx=%08x start_x2=%08x\n", state->y, x, x2, state->xstart, state->xend, dx, start_x2); +#endif + + state->pixel_count = 0; + state->x = x; + state->x2 = x2; + +#ifndef NO_CODEGEN + if (voodoo->use_recompiler) + { + voodoo_draw(state, params, x, real_y); + } + else +#endif + do + { + start_x = x; + voodoo->pixel_count[odd_even]++; + voodoo->fbiPixelsIn++; +#if 0 + if (voodoo_output) + pclog(" X=%03i T=%08x\n", x, state->tmu0_t); +#endif +// if (voodoo->fbzMode & FBZ_RGB_WMASK) + { + int update = 1; + uint8_t cother_r, cother_g, cother_b, aother; + uint8_t clocal_r, clocal_g, clocal_b, alocal; + int src_r, src_g, src_b, src_a; + int msel_r, msel_g, msel_b, msel_a; + uint8_t dest_r, dest_g, dest_b, dest_a; + uint16_t dat; + uint16_t aux_dat; + int sel; + int32_t new_depth, w_depth; + + if (state->w & 0xffff00000000) + w_depth = 0; + else if (!(state->w & 0xffff0000)) + w_depth = 0xf001; + else + { + int exp = fls((uint16_t)((uint32_t)state->w >> 16)); + int mant = ((~(uint32_t)state->w >> (19 - exp))) & 0xfff; + w_depth = (exp << 12) + mant + 1; + if (w_depth > 0xffff) + w_depth = 0xffff; + } + +// w_depth = CLAMP16(w_depth); + + if (params->fbzMode & FBZ_W_BUFFER) + new_depth = w_depth; + else + new_depth = CLAMP16(state->z >> 12); + + if (params->fbzMode & FBZ_DEPTH_BIAS) + new_depth = (new_depth + params->zaColor) & 0xffff; + + if (params->fbzMode & FBZ_DEPTH_ENABLE) + { + uint16_t old_depth = aux_mem[x]; + + DEPTH_TEST(); + } + + dat = fb_mem[x]; + dest_r = (dat >> 8) & 0xf8; + dest_g = (dat >> 3) & 0xfc; + dest_b = (dat << 3) & 0xf8; + dest_r |= (dest_r >> 5); + dest_g |= (dest_g >> 6); + dest_b |= (dest_b >> 5); + dest_a = 0xff; + + if (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) + { + if (params->textureMode & 1) + { + int64_t _w = 0; + if (state->tmu0_w) + _w = (int64_t)((1ULL << 48) / state->tmu0_w); + + state->tex_s = (int32_t)(((state->tmu0_s >> 14) * _w) >> 30); + state->tex_t = (int32_t)(((state->tmu0_t >> 14) * _w) >> 30); +// state->lod = state->tmu[0].lod + (int)(log2((double)_w / (double)(1 << 19)) * 256.0); + state->lod = state->tmu[0].lod + (fastlog(_w) - (19 << 8)); + } + else + { + state->tex_s = (int32_t)(state->tmu0_s >> (14+14)); + state->tex_t = (int32_t)(state->tmu0_t >> (14+14)); + state->lod = state->tmu[0].lod; + } + + if (state->lod < state->lod_min) + state->lod = state->lod_min; + else if (state->lod > state->lod_max) + state->lod = state->lod_max; + state->lod >>= 8; + + voodoo_get_texture(voodoo, params, state); + + if ((params->fbzMode & FBZ_CHROMAKEY) && + state->tex_r == params->chromaKey_r && + state->tex_g == params->chromaKey_g && + state->tex_b == params->chromaKey_b) + { + voodoo->fbiChromaFail++; + goto skip_pixel; + } + } + + if (voodoo->trexInit1 & (1 << 18)) + { + state->tex_r = state->tex_g = 0; + state->tex_b = 1; + } + + if (cc_localselect_override) + sel = (state->tex_a & 0x80) ? 1 : 0; + else + sel = cc_localselect; + + if (sel) + { + clocal_r = (params->color0 >> 16) & 0xff; + clocal_g = (params->color0 >> 8) & 0xff; + clocal_b = params->color0 & 0xff; + } + else + { + clocal_r = CLAMP(state->ir >> 12); + clocal_g = CLAMP(state->ig >> 12); + clocal_b = CLAMP(state->ib >> 12); + } + + switch (_rgb_sel) + { + case CC_LOCALSELECT_ITER_RGB: /*Iterated RGB*/ + cother_r = CLAMP(state->ir >> 12); + cother_g = CLAMP(state->ig >> 12); + cother_b = CLAMP(state->ib >> 12); + break; + + case CC_LOCALSELECT_TEX: /*TREX Color Output*/ + cother_r = state->tex_r; + cother_g = state->tex_g; + cother_b = state->tex_b; + break; + + case CC_LOCALSELECT_COLOR1: /*Color1 RGB*/ + cother_r = (params->color1 >> 16) & 0xff; + cother_g = (params->color1 >> 8) & 0xff; + cother_b = params->color1 & 0xff; + break; + + case CC_LOCALSELECT_LFB: /*Linear Frame Buffer*/ + cother_r = src_r; + cother_g = src_g; + cother_b = src_b; + break; + } + + switch (cca_localselect) + { + case CCA_LOCALSELECT_ITER_A: + alocal = CLAMP(state->ia >> 12); + break; + + case CCA_LOCALSELECT_COLOR0: + alocal = (params->color0 >> 24) & 0xff; + break; + + case CCA_LOCALSELECT_ITER_Z: + alocal = CLAMP(state->z >> 20); + break; + + default: + alocal = 0xff; + break; + } + + switch (a_sel) + { + case A_SEL_ITER_A: + aother = CLAMP(state->ia >> 12); + break; + case A_SEL_TEX: + aother = state->tex_a; + break; + case A_SEL_COLOR1: + aother = (params->color1 >> 24) & 0xff; + break; + default: + aother = 0; + break; + } + + if (cc_zero_other) + { + src_r = 0; + src_g = 0; + src_b = 0; + } + else + { + src_r = cother_r; + src_g = cother_g; + src_b = cother_b; + } + + if (cca_zero_other) + src_a = 0; + else + src_a = aother; + + if (cc_sub_clocal) + { + src_r -= clocal_r; + src_g -= clocal_g; + src_b -= clocal_b; + } + + if (cca_sub_clocal) + src_a -= alocal; + + switch (cc_mselect) + { + case CC_MSELECT_ZERO: + msel_r = 0; + msel_g = 0; + msel_b = 0; + break; + case CC_MSELECT_CLOCAL: + msel_r = clocal_r; + msel_g = clocal_g; + msel_b = clocal_b; + break; + case CC_MSELECT_AOTHER: + msel_r = aother; + msel_g = aother; + msel_b = aother; + break; + case CC_MSELECT_ALOCAL: + msel_r = alocal; + msel_g = alocal; + msel_b = alocal; + break; + case CC_MSELECT_TEX: + msel_r = state->tex_a; + msel_g = state->tex_a; + msel_b = state->tex_a; + break; + + default: + msel_r = 0; + msel_g = 0; + msel_b = 0; + break; + } + + switch (cca_mselect) + { + case CCA_MSELECT_ZERO: + msel_a = 0; + break; + case CCA_MSELECT_ALOCAL: + msel_a = alocal; + break; + case CCA_MSELECT_AOTHER: + msel_a = aother; + break; + case CCA_MSELECT_ALOCAL2: + msel_a = alocal; + break; + case CCA_MSELECT_TEX: + msel_a = state->tex_a; + break; + + default: + msel_a = 0; + break; + } + + if (!cc_reverse_blend) + { + msel_r ^= 0xff; + msel_g ^= 0xff; + msel_b ^= 0xff; + } + msel_r++; + msel_g++; + msel_b++; + + if (!cca_reverse_blend) + msel_a ^= 0xff; + msel_a++; + + src_r = (src_r * msel_r) >> 8; + src_g = (src_g * msel_g) >> 8; + src_b = (src_b * msel_b) >> 8; + src_a = (src_a * msel_a) >> 8; + + switch (cc_add) + { + case CC_ADD_CLOCAL: + src_r += clocal_r; + src_g += clocal_g; + src_b += clocal_b; + break; + case CC_ADD_ALOCAL: + src_r += alocal; + src_g += alocal; + src_b += alocal; + break; + } + + if (cca_add) + src_a += alocal; + + src_r = CLAMP(src_r); + src_g = CLAMP(src_g); + src_b = CLAMP(src_b); + src_a = CLAMP(src_a); + + if (cc_invert_output) + { + src_r ^= 0xff; + src_g ^= 0xff; + src_b ^= 0xff; + } + if (cca_invert_output) + src_a ^= 0xff; + + if (params->fogMode & FOG_ENABLE) + APPLY_FOG(src_r, src_g, src_b, state->z, state->ia); + + if (params->alphaMode & 1) + ALPHA_TEST(src_a); + + if (params->alphaMode & (1 << 4)) + ALPHA_BLEND(src_r, src_g, src_b, src_a); + + if (update) + { + if (dither) + { + if (dither2x2) + { + src_r = dither_rb2x2[src_r][real_y & 1][x & 1]; + src_g = dither_g2x2[src_g][real_y & 1][x & 1]; + src_b = dither_rb2x2[src_b][real_y & 1][x & 1]; + } + else + { + src_r = dither_rb[src_r][real_y & 3][x & 3]; + src_g = dither_g[src_g][real_y & 3][x & 3]; + src_b = dither_rb[src_b][real_y & 3][x & 3]; + } + } + else + { + src_r >>= 3; + src_g >>= 2; + src_b >>= 3; + } + + if (params->fbzMode & FBZ_RGB_WMASK) + fb_mem[x] = src_b | (src_g << 5) | (src_r << 11); + if (params->fbzMode & FBZ_DEPTH_WMASK) + aux_mem[x] = new_depth; + } + } + voodoo_output &= ~2; + voodoo->fbiPixelsOut++; +skip_pixel: + if (state->xdir > 0) + { + state->ir += params->dRdX; + state->ig += params->dGdX; + state->ib += params->dBdX; + state->ia += params->dAdX; + state->z += params->dZdX; + state->tmu0_s += params->tmu[0].dSdX; + state->tmu0_t += params->tmu[0].dTdX; + state->tmu0_w += params->tmu[0].dWdX; + state->w += params->dWdX; + } + else + { + state->ir -= params->dRdX; + state->ig -= params->dGdX; + state->ib -= params->dBdX; + state->ia -= params->dAdX; + state->z -= params->dZdX; + state->tmu0_s -= params->tmu[0].dSdX; + state->tmu0_t -= params->tmu[0].dTdX; + state->tmu0_w -= params->tmu[0].dWdX; + state->w -= params->dWdX; + } + + x += state->xdir; + } while (start_x != x2); + + voodoo->pixel_count[odd_even] += state->pixel_count; + voodoo->fbiPixelsIn += state->pixel_count; + + if (voodoo->params.draw_offset == voodoo->params.front_offset) + voodoo->dirty_line[real_y] = 1; +next_line: + state->base_r += params->dRdY; + state->base_g += params->dGdY; + state->base_b += params->dBdY; + state->base_a += params->dAdY; + state->base_z += params->dZdY; + state->tmu[0].base_s += params->tmu[0].dSdY; + state->tmu[0].base_t += params->tmu[0].dTdY; + state->tmu[0].base_w += params->tmu[0].dWdY; + state->base_w += params->dWdY; + state->xstart += state->dx1; + state->xend += state->dx2; + } +} + +static void voodoo_triangle(voodoo_t *voodoo, voodoo_params_t *params, int odd_even) +{ + voodoo_state_t state; + int vertexAy_adjusted; + int vertexBy_adjusted; + int vertexCy_adjusted; + int dx, dy; + + uint64_t tempdx, tempdy; + uint64_t tempLOD; + int LOD; + int lodbias; + + voodoo->tri_count++; + + dx = 8 - (params->vertexAx & 0xf); + if ((params->vertexAx & 0xf) > 8) + dx += 16; + dy = 8 - (params->vertexAy & 0xf); + if ((params->vertexAy & 0xf) > 8) + dy += 16; + +/* pclog("voodoo_triangle %i %i %i : vA %f, %f vB %f, %f vC %f, %f f %i %08x %08x %08x\n", odd_even, voodoo->params_read_idx[odd_even], voodoo->params_read_idx[odd_even] & PARAM_MASK, (float)params->vertexAx / 16.0, (float)params->vertexAy / 16.0, + (float)params->vertexBx / 16.0, (float)params->vertexBy / 16.0, + (float)params->vertexCx / 16.0, (float)params->vertexCy / 16.0, (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) ? params->tformat : 0, params->fbzColorPath, params->alphaMode, params->textureMode);*/ + + state.base_r = params->startR; + state.base_g = params->startG; + state.base_b = params->startB; + state.base_a = params->startA; + state.base_z = params->startZ; + state.tmu[0].base_s = params->tmu[0].startS; + state.tmu[0].base_t = params->tmu[0].startT; + state.tmu[0].base_w = params->tmu[0].startW; + state.base_w = params->startW; + + if (params->fbzColorPath & FBZ_PARAM_ADJUST) + { + state.base_r += (dx*params->dRdX + dy*params->dRdY) >> 4; + state.base_g += (dx*params->dGdX + dy*params->dGdY) >> 4; + state.base_b += (dx*params->dBdX + dy*params->dBdY) >> 4; + state.base_a += (dx*params->dAdX + dy*params->dAdY) >> 4; + state.base_z += (dx*params->dZdX + dy*params->dZdY) >> 4; + state.tmu[0].base_s += (dx*params->tmu[0].dSdX + dy*params->tmu[0].dSdY) >> 4; + state.tmu[0].base_t += (dx*params->tmu[0].dTdX + dy*params->tmu[0].dTdY) >> 4; + state.tmu[0].base_w += (dx*params->tmu[0].dWdX + dy*params->tmu[0].dWdY) >> 4; + state.base_w += (dx*params->dWdX + dy*params->dWdY) >> 4; + } + + tris++; + + state.vertexAy = params->vertexAy & ~0xffff0000; + if (state.vertexAy & 0x8000) + state.vertexAy |= 0xffff0000; + state.vertexBy = params->vertexBy & ~0xffff0000; + if (state.vertexBy & 0x8000) + state.vertexBy |= 0xffff0000; + state.vertexCy = params->vertexCy & ~0xffff0000; + if (state.vertexCy & 0x8000) + state.vertexCy |= 0xffff0000; + + state.vertexAx = params->vertexAx & ~0xffff0000; + if (state.vertexAx & 0x8000) + state.vertexAx |= 0xffff0000; + state.vertexBx = params->vertexBx & ~0xffff0000; + if (state.vertexBx & 0x8000) + state.vertexBx |= 0xffff0000; + state.vertexCx = params->vertexCx & ~0xffff0000; + if (state.vertexCx & 0x8000) + state.vertexCx |= 0xffff0000; + + vertexAy_adjusted = (state.vertexAy+7) >> 4; + vertexBy_adjusted = (state.vertexBy+7) >> 4; + vertexCy_adjusted = (state.vertexCy+7) >> 4; + + if (state.vertexBy - state.vertexAy) + state.dxAB = (int)((((int64_t)state.vertexBx << 12) - ((int64_t)state.vertexAx << 12)) << 4) / (int)(state.vertexBy - state.vertexAy); + else + state.dxAB = 0; + if (state.vertexCy - state.vertexAy) + state.dxAC = (int)((((int64_t)state.vertexCx << 12) - ((int64_t)state.vertexAx << 12)) << 4) / (int)(state.vertexCy - state.vertexAy); + else + state.dxAC = 0; + if (state.vertexCy - state.vertexBy) + state.dxBC = (int)((((int64_t)state.vertexCx << 12) - ((int64_t)state.vertexBx << 12)) << 4) / (int)(state.vertexCy - state.vertexBy); + else + state.dxBC = 0; + + state.lod_min = (params->tLOD & 0x3f) << 6; + state.lod_max = ((params->tLOD >> 6) & 0x3f) << 6; + if (state.lod_max > 0x800) + state.lod_max = 0x800; + state.xstart = state.xend = state.vertexAx << 8; + state.xdir = params->sign ? -1 : 1; + + state.y = (state.vertexAy + 8) >> 4; + state.ydir = 1; + + tempdx = (params->tmu[0].dSdX >> 14) * (params->tmu[0].dSdX >> 14) + (params->tmu[0].dTdX >> 14) * (params->tmu[0].dTdX >> 14); + tempdy = (params->tmu[0].dSdY >> 14) * (params->tmu[0].dSdY >> 14) + (params->tmu[0].dTdY >> 14) * (params->tmu[0].dTdY >> 14); + + if (tempdx > tempdy) + tempLOD = tempdx; + else + tempLOD = tempdy; + + LOD = (int)(log2((double)tempLOD / (double)(1ULL << 36)) * 256); + LOD >>= 2; + + lodbias = (params->tLOD >> 12) & 0x3f; + if (lodbias & 0x20) + lodbias |= ~0x3f; + state.tmu[0].lod = LOD + (lodbias << 6); + + state.palette = params->palette; + + voodoo_half_triangle(voodoo, params, &state, vertexAy_adjusted, vertexCy_adjusted, odd_even); +} + +static inline void wake_render_thread(voodoo_t *voodoo) +{ + thread_set_event(voodoo->wake_render_thread[0]); /*Wake up render thread if moving from idle*/ + if (voodoo->render_threads == 2) + thread_set_event(voodoo->wake_render_thread[1]); /*Wake up render thread if moving from idle*/ +} + +static inline void wait_for_render_thread_idle(voodoo_t *voodoo) +{ + while (!PARAM_EMPTY_1 || (voodoo->render_threads == 2 && !PARAM_EMPTY_2) || voodoo->render_voodoo_busy[0] || (voodoo->render_threads == 2 && voodoo->render_voodoo_busy[1])) + { + wake_render_thread(voodoo); + if (!PARAM_EMPTY_1 || voodoo->render_voodoo_busy[0]) + thread_wait_event(voodoo->render_not_full_event[0], 1); + if (voodoo->render_threads == 2 && (!PARAM_EMPTY_2 || voodoo->render_voodoo_busy[1])) + thread_wait_event(voodoo->render_not_full_event[1], 1); + } +} + +static void render_thread(void *param, int odd_even) +{ + voodoo_t *voodoo = (voodoo_t *)param; + + while (1) + { + thread_set_event(voodoo->render_not_full_event[odd_even]); + thread_wait_event(voodoo->wake_render_thread[odd_even], -1); + thread_reset_event(voodoo->wake_render_thread[odd_even]); + voodoo->render_voodoo_busy[odd_even] = 1; + + while (!(odd_even ? PARAM_EMPTY_2 : PARAM_EMPTY_1)) + { + uint64_t start_time = timer_read(); + uint64_t end_time; + voodoo_params_t *params = &voodoo->params_buffer[voodoo->params_read_idx[odd_even] & PARAM_MASK]; + + voodoo_triangle(voodoo, params, odd_even); + + voodoo->params_read_idx[odd_even]++; + + if ((odd_even ? PARAM_ENTRIES_2 : PARAM_ENTRIES_1) > (PARAM_SIZE - 10)) + thread_set_event(voodoo->render_not_full_event[odd_even]); + + end_time = timer_read(); + voodoo_render_time[odd_even] += end_time - start_time; + } + + voodoo->render_voodoo_busy[odd_even] = 0; + } +} + +static void render_thread_1(void *param) +{ + render_thread(param, 0); +} +static void render_thread_2(void *param) +{ + render_thread(param, 1); +} + +static inline void queue_triangle(voodoo_t *voodoo, voodoo_params_t *params) +{ + voodoo_params_t *params_new = &voodoo->params_buffer[voodoo->params_write_idx & PARAM_MASK]; + + while (PARAM_FULL_1 || (voodoo->render_threads == 2 && PARAM_FULL_2)) + { + thread_reset_event(voodoo->render_not_full_event[0]); + if (voodoo->render_threads == 2) + thread_reset_event(voodoo->render_not_full_event[1]); + if (PARAM_FULL_1) + { + thread_wait_event(voodoo->render_not_full_event[0], -1); /*Wait for room in ringbuffer*/ + } + if (voodoo->render_threads == 2 && PARAM_FULL_2) + { + thread_wait_event(voodoo->render_not_full_event[1], -1); /*Wait for room in ringbuffer*/ + } + } + + memcpy(params_new, params, sizeof(voodoo_params_t) - sizeof(voodoo->palette)); + + /*Copy palette data if required*/ + switch (params->tformat) + { + case TEX_PAL8: case TEX_APAL88: + memcpy(params_new->palette, voodoo->palette, sizeof(voodoo->palette)); + break; + case TEX_Y4I2Q2: + memcpy(params_new->palette, voodoo->ncc_lookup[(params->textureMode & TEXTUREMODE_NCC_SEL) ? 1 : 0], sizeof(voodoo->palette)); + break; + } + + voodoo->params_write_idx++; + + if (PARAM_ENTRIES_1 < 4 || (voodoo->render_threads == 2 && PARAM_ENTRIES_2 < 4)) + wake_render_thread(voodoo); +} + +static void voodoo_fastfill(voodoo_t *voodoo, voodoo_params_t *params) +{ + int y; + + if (params->fbzMode & FBZ_RGB_WMASK) + { + int r, g, b; + uint16_t col; + + r = ((params->color1 >> 16) >> 3) & 0x1f; + g = ((params->color1 >> 8) >> 2) & 0x3f; + b = (params->color1 >> 3) & 0x1f; + col = b | (g << 5) | (r << 11); + + for (y = params->clipLowY; y < params->clipHighY; y++) + { + uint16_t *cbuf = (uint16_t *)&voodoo->fb_mem[(params->draw_offset + y*voodoo->row_width) & voodoo->fb_mask]; + int x; + + for (x = params->clipLeft; x < params->clipRight; x++) + cbuf[x] = col; + } + } + if (params->fbzMode & FBZ_DEPTH_WMASK) + { + for (y = params->clipLowY; y < params->clipHighY; y++) + { + uint16_t *abuf = (uint16_t *)&voodoo->fb_mem[(params->aux_offset + y*voodoo->row_width) & voodoo->fb_mask]; + int x; + + for (x = params->clipLeft; x < params->clipRight; x++) + abuf[x] = params->zaColor & 0xffff; + } + } +} + +static uint32_t voodoo_reg_readl(uint32_t addr, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + uint32_t temp; + + switch (addr & 0x3fc) + { + + case SST_lfbMode: + temp = voodoo->lfbMode; + break; + + case SST_fbiInit4: + temp = voodoo->fbiInit4; + break; + case SST_fbiInit0: + temp = voodoo->fbiInit0; + break; + case SST_fbiInit1: + temp = voodoo->fbiInit1 & ~5; /*Pass-thru board with one SST-1*/ + break; + case SST_fbiInit2: + if (voodoo->initEnable & 0x04) + temp = voodoo->dac_readdata; + else + temp = voodoo->fbiInit2; + break; + case SST_fbiInit3: + temp = voodoo->fbiInit3; + break; + + default: + fatal("voodoo_readl : bad addr %08X\n", addr); + temp = 0xffffffff; + } + + return temp; +} + +enum +{ + CHIP_FBI = 0x1, + CHIP_TREX0 = 0x2, + CHIP_TREX1 = 0x2, + CHIP_TREX2 = 0x2 +}; + +static void voodoo_reg_writel(uint32_t addr, uint32_t val, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + union + { + uint32_t i; + float f; + } tempif; + int ad21 = addr & (1 << 21); + int chip = (addr >> 10) & 0xf; + if (!chip) + chip = 0xf; + + tempif.i = val; +//pclog("voodoo_write_l: addr=%08x val=%08x(%f) chip=%x\n", addr, val, tempif.f, chip); + addr &= 0x3fc; + + if ((voodoo->fbiInit3 & FBIINIT3_REMAP) && addr < 0x100 && ad21) + addr |= 0x400; + switch (addr) + { + case SST_swapbufferCMD: +// pclog(" start swap buffer command\n"); + + voodoo->disp_buffer = !voodoo->disp_buffer; + voodoo_recalc(voodoo); + + voodoo->params.swapbufferCMD = val; + +#if 0 + pclog("Swap buffer %08x %d %p\n", val, voodoo->swap_count, &voodoo->swap_count); +#endif +// voodoo->front_offset = params->front_offset; + wait_for_render_thread_idle(voodoo); + if (!(val & 1)) + { + memset(voodoo->dirty_line, 1, 1024); + voodoo->front_offset = voodoo->params.front_offset; + voodoo->swap_count--; + } + else + { + voodoo->swap_interval = (val >> 1) & 0xff; + voodoo->swap_offset = voodoo->params.front_offset; + voodoo->swap_pending = 1; + + while (voodoo->swap_pending) + { + thread_wait_event(voodoo->wake_fifo_thread, -1); + thread_reset_event(voodoo->wake_fifo_thread); + if ((voodoo->swap_pending && voodoo->flush) || FIFO_ENTRIES == 65536) + { + /*Main thread is waiting for FIFO to empty, so skip vsync wait and just swap*/ + memset(voodoo->dirty_line, 1, 1024); + voodoo->front_offset = voodoo->params.front_offset; + voodoo->swap_count--; + voodoo->swap_pending = 0; + break; + } + } + } + voodoo->cmd_read++; + break; + + case SST_vertexAx: case SST_remap_vertexAx: + voodoo->params.vertexAx = val & 0xffff; + break; + case SST_vertexAy: case SST_remap_vertexAy: + voodoo->params.vertexAy = val & 0xffff; + break; + case SST_vertexBx: case SST_remap_vertexBx: + voodoo->params.vertexBx = val & 0xffff; + break; + case SST_vertexBy: case SST_remap_vertexBy: + voodoo->params.vertexBy = val & 0xffff; + break; + case SST_vertexCx: case SST_remap_vertexCx: + voodoo->params.vertexCx = val & 0xffff; + break; + case SST_vertexCy: case SST_remap_vertexCy: + voodoo->params.vertexCy = val & 0xffff; + break; + + case SST_startR: case SST_remap_startR: + voodoo->params.startR = val & 0xffffff; + break; + case SST_startG: case SST_remap_startG: + voodoo->params.startG = val & 0xffffff; + break; + case SST_startB: case SST_remap_startB: + voodoo->params.startB = val & 0xffffff; + break; + case SST_startZ: case SST_remap_startZ: + voodoo->params.startZ = val; + break; + case SST_startA: case SST_remap_startA: + voodoo->params.startA = val & 0xffffff; + break; + case SST_startS: case SST_remap_startS: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].startS = ((int64_t)(int32_t)val) << 14; + break; + case SST_startT: case SST_remap_startT: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].startT = ((int64_t)(int32_t)val) << 14; + break; + case SST_startW: case SST_remap_startW: + if (chip & CHIP_FBI) + voodoo->params.startW = (int64_t)(int32_t)val << 2; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].startW = (int64_t)(int32_t)val << 2; + break; + + case SST_dRdX: case SST_remap_dRdX: + voodoo->params.dRdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dGdX: case SST_remap_dGdX: + voodoo->params.dGdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dBdX: case SST_remap_dBdX: + voodoo->params.dBdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dZdX: case SST_remap_dZdX: + voodoo->params.dZdX = val; + break; + case SST_dAdX: case SST_remap_dAdX: + voodoo->params.dAdX = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dSdX: case SST_remap_dSdX: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dSdX = ((int64_t)(int32_t)val) << 14; + break; + case SST_dTdX: case SST_remap_dTdX: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dTdX = ((int64_t)(int32_t)val) << 14; + break; + case SST_dWdX: case SST_remap_dWdX: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dWdX = (int64_t)(int32_t)val << 2; + if (chip & CHIP_FBI) + voodoo->params.dWdX = (int64_t)(int32_t)val << 2; + break; + + case SST_dRdY: case SST_remap_dRdY: + voodoo->params.dRdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dGdY: case SST_remap_dGdY: + voodoo->params.dGdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dBdY: case SST_remap_dBdY: + voodoo->params.dBdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dZdY: case SST_remap_dZdY: + voodoo->params.dZdY = val; + break; + case SST_dAdY: case SST_remap_dAdY: + voodoo->params.dAdY = (val & 0xffffff) | ((val & 0x800000) ? 0xff000000 : 0); + break; + case SST_dSdY: case SST_remap_dSdY: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dSdY = ((int64_t)(int32_t)val) << 14; + break; + case SST_dTdY: case SST_remap_dTdY: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dTdY = ((int64_t)(int32_t)val) << 14; + break; + case SST_dWdY: case SST_remap_dWdY: + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dWdY = (int64_t)(int32_t)val << 2; + if (chip & CHIP_FBI) + voodoo->params.dWdY = (int64_t)(int32_t)val << 2; + break; + + case SST_triangleCMD: case SST_remap_triangleCMD: + voodoo->params.sign = val & (1 << 31); + + if (voodoo->ncc_dirty) + voodoo_update_ncc(voodoo); + voodoo->ncc_dirty = 0; + + queue_triangle(voodoo, &voodoo->params); + + voodoo->cmd_read++; + break; + + case SST_fvertexAx: case SST_remap_fvertexAx: + voodoo->fvertexAx.i = val; + voodoo->params.vertexAx = (int32_t)(int16_t)(int32_t)(voodoo->fvertexAx.f * 16.0f) & 0xffff; + break; + case SST_fvertexAy: case SST_remap_fvertexAy: + voodoo->fvertexAy.i = val; + voodoo->params.vertexAy = (int32_t)(int16_t)(int32_t)(voodoo->fvertexAy.f * 16.0f) & 0xffff; + break; + case SST_fvertexBx: case SST_remap_fvertexBx: + voodoo->fvertexBx.i = val; + voodoo->params.vertexBx = (int32_t)(int16_t)(int32_t)(voodoo->fvertexBx.f * 16.0f) & 0xffff; + break; + case SST_fvertexBy: case SST_remap_fvertexBy: + voodoo->fvertexBy.i = val; + voodoo->params.vertexBy = (int32_t)(int16_t)(int32_t)(voodoo->fvertexBy.f * 16.0f) & 0xffff; + break; + case SST_fvertexCx: case SST_remap_fvertexCx: + voodoo->fvertexCx.i = val; + voodoo->params.vertexCx = (int32_t)(int16_t)(int32_t)(voodoo->fvertexCx.f * 16.0f) & 0xffff; + break; + case SST_fvertexCy: case SST_remap_fvertexCy: + voodoo->fvertexCy.i = val; + voodoo->params.vertexCy = (int32_t)(int16_t)(int32_t)(voodoo->fvertexCy.f * 16.0f) & 0xffff; + break; + + case SST_fstartR: case SST_remap_fstartR: + tempif.i = val; + voodoo->params.startR = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fstartG: case SST_remap_fstartG: + tempif.i = val; + voodoo->params.startG = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fstartB: case SST_remap_fstartB: + tempif.i = val; + voodoo->params.startB = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fstartZ: case SST_remap_fstartZ: + tempif.i = val; + voodoo->params.startZ = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fstartA: case SST_remap_fstartA: + tempif.i = val; + voodoo->params.startA = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fstartS: case SST_remap_fstartS: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].startS = (int64_t)(tempif.f * 4294967296.0f); + break; + case SST_fstartT: case SST_remap_fstartT: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].startT = (int64_t)(tempif.f * 4294967296.0f); + break; + case SST_fstartW: case SST_remap_fstartW: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].startW = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_FBI) + voodoo->params.startW = (int64_t)(tempif.f * 4294967296.0f); + break; + + case SST_fdRdX: case SST_remap_fdRdX: + tempif.i = val; + voodoo->params.dRdX = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdGdX: case SST_remap_fdGdX: + tempif.i = val; + voodoo->params.dGdX = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdBdX: case SST_remap_fdBdX: + tempif.i = val; + voodoo->params.dBdX = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdZdX: case SST_remap_fdZdX: + tempif.i = val; + voodoo->params.dZdX = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdAdX: case SST_remap_fdAdX: + tempif.i = val; + voodoo->params.dAdX = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdSdX: case SST_remap_fdSdX: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dSdX = (int64_t)(tempif.f * 4294967296.0f); + break; + case SST_fdTdX: case SST_remap_fdTdX: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dTdX = (int64_t)(tempif.f * 4294967296.0f); + break; + case SST_fdWdX: case SST_remap_fdWdX: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dWdX = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_FBI) + voodoo->params.dWdX = (int64_t)(tempif.f * 4294967296.0f); + break; + + case SST_fdRdY: case SST_remap_fdRdY: + tempif.i = val; + voodoo->params.dRdY = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdGdY: case SST_remap_fdGdY: + tempif.i = val; + voodoo->params.dGdY = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdBdY: case SST_remap_fdBdY: + tempif.i = val; + voodoo->params.dBdY = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdZdY: case SST_remap_fdZdY: + tempif.i = val; + voodoo->params.dZdY = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdAdY: case SST_remap_fdAdY: + tempif.i = val; + voodoo->params.dAdY = (int32_t)(tempif.f * 4096.0f); + break; + case SST_fdSdY: case SST_remap_fdSdY: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dSdY = (int64_t)(tempif.f * 4294967296.0f); + break; + case SST_fdTdY: case SST_remap_fdTdY: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dTdY = (int64_t)(tempif.f * 4294967296.0f); + break; + case SST_fdWdY: case SST_remap_fdWdY: + tempif.i = val; + if (chip & CHIP_TREX0) + voodoo->params.tmu[0].dWdY = (int64_t)(tempif.f * 4294967296.0f); + if (chip & CHIP_FBI) + voodoo->params.dWdY = (int64_t)(tempif.f * 4294967296.0f); + break; + + case SST_ftriangleCMD: + voodoo->params.sign = val & (1 << 31); + + if (voodoo->ncc_dirty) + voodoo_update_ncc(voodoo); + voodoo->ncc_dirty = 0; + + queue_triangle(voodoo, &voodoo->params); + + voodoo->cmd_read++; + break; + + case SST_fbzColorPath: + voodoo->params.fbzColorPath = val; + voodoo->rgb_sel = val & 3; + break; + + case SST_fogMode: + voodoo->params.fogMode = val; + break; + case SST_alphaMode: + voodoo->params.alphaMode = val; + break; + case SST_fbzMode: + voodoo->params.fbzMode = val; + voodoo_recalc(voodoo); + break; + case SST_lfbMode: + voodoo->lfbMode = val; + voodoo_recalc(voodoo); + break; + + case SST_clipLeftRight: + voodoo->params.clipRight = val & 0x3ff; + voodoo->params.clipLeft = (val >> 16) & 0x3ff; + break; + case SST_clipLowYHighY: + voodoo->params.clipHighY = val & 0x3ff; + voodoo->params.clipLowY = (val >> 16) & 0x3ff; + break; + + case SST_nopCMD: + voodoo->cmd_read++; + voodoo->fbiPixelsIn = 0; + voodoo->fbiChromaFail = 0; + voodoo->fbiZFuncFail = 0; + voodoo->fbiAFuncFail = 0; + voodoo->fbiPixelsOut = 0; + break; + case SST_fastfillCMD: + wait_for_render_thread_idle(voodoo); + voodoo_fastfill(voodoo, &voodoo->params); + voodoo->cmd_read++; + break; + + case SST_fogColor: + voodoo->params.fogColor.r = (val >> 16) & 0xff; + voodoo->params.fogColor.g = (val >> 8) & 0xff; + voodoo->params.fogColor.b = val & 0xff; + break; + + case SST_zaColor: + voodoo->params.zaColor = val; + break; + case SST_chromaKey: + voodoo->params.chromaKey_r = (val >> 16) & 0xff; + voodoo->params.chromaKey_g = (val >> 8) & 0xff; + voodoo->params.chromaKey_b = val & 0xff; + voodoo->params.chromaKey = val & 0xffffff; + break; + + case SST_color0: + voodoo->params.color0 = val; + break; + case SST_color1: + voodoo->params.color1 = val; + break; + + case SST_fogTable00: case SST_fogTable01: case SST_fogTable02: case SST_fogTable03: + case SST_fogTable04: case SST_fogTable05: case SST_fogTable06: case SST_fogTable07: + case SST_fogTable08: case SST_fogTable09: case SST_fogTable0a: case SST_fogTable0b: + case SST_fogTable0c: case SST_fogTable0d: case SST_fogTable0e: case SST_fogTable0f: + case SST_fogTable10: case SST_fogTable11: case SST_fogTable12: case SST_fogTable13: + case SST_fogTable14: case SST_fogTable15: case SST_fogTable16: case SST_fogTable17: + case SST_fogTable18: case SST_fogTable19: case SST_fogTable1a: case SST_fogTable1b: + case SST_fogTable1c: case SST_fogTable1d: case SST_fogTable1e: case SST_fogTable1f: + addr = (addr - SST_fogTable00) >> 1; + voodoo->params.fogTable[addr].dfog = val & 0xff; + voodoo->params.fogTable[addr].fog = (val >> 8) & 0xff; + voodoo->params.fogTable[addr+1].dfog = (val >> 16) & 0xff; + voodoo->params.fogTable[addr+1].fog = (val >> 24) & 0xff; + break; + + case SST_textureMode: + voodoo->params.textureMode = val; + voodoo->params.tformat = (val >> 8) & 0xf; + break; + case SST_tLOD: + voodoo->params.tLOD = val; + voodoo_recalc_tex(voodoo); + break; + + case SST_texBaseAddr: +// pclog("Write texBaseAddr %08x\n", val); + voodoo->params.texBaseAddr = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo); + break; + case SST_texBaseAddr1: + voodoo->params.texBaseAddr1 = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo); + break; + case SST_texBaseAddr2: + voodoo->params.texBaseAddr2 = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo); + break; + case SST_texBaseAddr38: + voodoo->params.texBaseAddr38 = (val & 0x7ffff) << 3; + voodoo_recalc_tex(voodoo); + break; + + case SST_trexInit1: + voodoo->trexInit1 = val; + break; + + case SST_nccTable0_Y0: + voodoo->nccTable[0].y[0] = val; + voodoo->ncc_dirty = 1; + break; + case SST_nccTable0_Y1: + voodoo->nccTable[0].y[1] = val; + voodoo->ncc_dirty = 1; + break; + case SST_nccTable0_Y2: + voodoo->nccTable[0].y[2] = val; + voodoo->ncc_dirty = 1; + break; + case SST_nccTable0_Y3: + voodoo->nccTable[0].y[3] = val; + voodoo->ncc_dirty = 1; + break; + + case SST_nccTable0_I0: + if (!(val & (1 << 31))) + { + voodoo->nccTable[0].i[0] = val; + voodoo->ncc_dirty = 1; + break; + } + case SST_nccTable0_I2: + if (!(val & (1 << 31))) + { + voodoo->nccTable[0].i[2] = val; + voodoo->ncc_dirty = 1; + break; + } + case SST_nccTable0_Q0: + if (!(val & (1 << 31))) + { + voodoo->nccTable[0].q[0] = val; + voodoo->ncc_dirty = 1; + break; + } + case SST_nccTable0_Q2: + if (!(val & (1 << 31))) + { + voodoo->nccTable[0].q[2] = val; + voodoo->ncc_dirty = 1; + break; + } + if (val & (1 << 31)) + { + int p = (val >> 23) & 0xfe; + voodoo->palette[p].u = val | 0xff000000; + } + break; + + case SST_nccTable0_I1: + if (!(val & (1 << 31))) + { + voodoo->nccTable[0].i[1] = val; + voodoo->ncc_dirty = 1; + break; + } + case SST_nccTable0_I3: + if (!(val & (1 << 31))) + { + voodoo->nccTable[0].i[3] = val; + voodoo->ncc_dirty = 1; + break; + } + case SST_nccTable0_Q1: + if (!(val & (1 << 31))) + { + voodoo->nccTable[0].q[1] = val; + voodoo->ncc_dirty = 1; + break; + } + case SST_nccTable0_Q3: + if (!(val & (1 << 31))) + { + voodoo->nccTable[0].q[3] = val; + voodoo->ncc_dirty = 1; + break; + } + if (val & (1 << 31)) + { + int p = ((val >> 23) & 0xfe) | 0x01; + voodoo->palette[p].u = val | 0xff000000; + } + break; + + case SST_nccTable1_Y0: + voodoo->nccTable[1].y[0] = val; + voodoo->ncc_dirty = 1; + break; + case SST_nccTable1_Y1: + voodoo->nccTable[1].y[1] = val; + voodoo->ncc_dirty = 1; + break; + case SST_nccTable1_Y2: + voodoo->nccTable[1].y[2] = val; + voodoo->ncc_dirty = 1; + break; + case SST_nccTable1_Y3: + voodoo->nccTable[1].y[3] = val; + voodoo->ncc_dirty = 1; + break; + case SST_nccTable1_I0: + voodoo->nccTable[1].i[0] = val; + voodoo->ncc_dirty = 1; + break; + case SST_nccTable1_I1: + voodoo->nccTable[1].i[1] = val; + voodoo->ncc_dirty = 1; + break; + case SST_nccTable1_I2: + voodoo->nccTable[1].i[2] = val; + voodoo->ncc_dirty = 1; + break; + case SST_nccTable1_I3: + voodoo->nccTable[1].i[3] = val; + voodoo->ncc_dirty = 1; + break; + case SST_nccTable1_Q0: + voodoo->nccTable[1].q[0] = val; + voodoo->ncc_dirty = 1; + break; + case SST_nccTable1_Q1: + voodoo->nccTable[1].q[1] = val; + voodoo->ncc_dirty = 1; + break; + case SST_nccTable1_Q2: + voodoo->nccTable[1].q[2] = val; + voodoo->ncc_dirty = 1; + break; + case SST_nccTable1_Q3: + voodoo->nccTable[1].q[3] = val; + voodoo->ncc_dirty = 1; + break; + } +} + + +static uint16_t voodoo_fb_readw(uint32_t addr, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + int x, y; + uint32_t read_addr; + uint16_t temp; + + x = (addr >> 1) & 0x3ff; + y = (addr >> 11) & 0x3ff; + read_addr = voodoo->fb_read_offset + (x << 1) + (y * voodoo->row_width); + + if (read_addr > voodoo->fb_mask) + return 0xffff; + + temp = *(uint16_t *)(&voodoo->fb_mem[read_addr & voodoo->fb_mask]); + +// pclog("voodoo_fb_readw : %08X %08X %i %i %08X %08X %08x:%08x %i\n", addr, temp, x, y, read_addr, *(uint32_t *)(&voodoo->fb_mem[4]), cs, pc, fb_reads++); + return temp; +} +static uint32_t voodoo_fb_readl(uint32_t addr, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + int x, y; + uint32_t read_addr; + uint32_t temp; + + x = addr & 0x7fe; + y = (addr >> 11) & 0x3ff; + read_addr = voodoo->fb_read_offset + x + (y * voodoo->row_width); + + if (read_addr > voodoo->fb_mask) + return 0xffffffff; + + temp = *(uint32_t *)(&voodoo->fb_mem[read_addr & voodoo->fb_mask]); + +// pclog("voodoo_fb_readl : %08X %08x %08X x=%i y=%i %08X %08X %08x:%08x %i ro=%08x rw=%i\n", addr, read_addr, temp, x, y, read_addr, *(uint32_t *)(&voodoo->fb_mem[4]), cs, pc, fb_reads++, voodoo->fb_read_offset, voodoo->row_width); + return temp; +} + +static inline uint16_t do_dither(voodoo_params_t *params, rgba8_t col, int x, int y) +{ + int r, g, b; + + if (dither) + { + if (dither2x2) + { + r = dither_rb2x2[col.r][y & 1][x & 1]; + g = dither_g2x2[col.g][y & 1][x & 1]; + b = dither_rb2x2[col.b][y & 1][x & 1]; + } + else + { + r = dither_rb[col.r][y & 3][x & 3]; + g = dither_g[col.g][y & 3][x & 3]; + b = dither_rb[col.b][y & 3][x & 3]; + } + } + else + { + r = col.r >> 3; + g = col.g >> 2; + b = col.b >> 3; + } + + return b | (g << 5) | (r << 11); +} + +static void voodoo_fb_writew(uint32_t addr, uint16_t val, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + voodoo_params_t *params = &voodoo->params; + int x, y; + uint32_t write_addr, write_addr_aux; + rgba8_t colour_data; + uint16_t depth_data; + uint8_t alpha_data; + int write_mask; + + depth_data = voodoo->params.zaColor & 0xffff; + alpha_data = voodoo->params.zaColor >> 24; + +// while (!RB_EMPTY) +// thread_reset_event(voodoo->not_full_event); + +// pclog("voodoo_fb_writew : %08X %04X\n", addr, val); + + + switch (voodoo->lfbMode & LFB_FORMAT_MASK) + { + case LFB_FORMAT_RGB565: + colour_data = rgb565[val]; + alpha_data = 0xff; + write_mask = LFB_WRITE_COLOUR; + break; + case LFB_FORMAT_RGB555: + colour_data = argb1555[val]; + alpha_data = 0xff; + write_mask = LFB_WRITE_COLOUR; + break; + case LFB_FORMAT_ARGB1555: + colour_data = argb1555[val]; + alpha_data = colour_data.a; + write_mask = LFB_WRITE_COLOUR; + break; + + default: + fatal("voodoo_fb_writew : bad LFB format %08X\n", voodoo->lfbMode); + } + + x = addr & 0x7fe; + y = (addr >> 11) & 0x3ff; + + if (voodoo->fb_write_offset == voodoo->params.front_offset) + voodoo->dirty_line[y] = 1; + + write_addr = voodoo->fb_write_offset + x + (y * voodoo->row_width); + write_addr_aux = voodoo->params.aux_offset + x + (y * voodoo->row_width); + +// pclog("fb_writew %08x %i %i %i %08x\n", addr, x, y, voodoo->row_width, write_addr); + + if (voodoo->lfbMode & 0x100) + { + { + rgba8_t write_data = colour_data; + uint16_t new_depth = depth_data; + + if (params->fbzMode & FBZ_DEPTH_ENABLE) + { + uint16_t old_depth = *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]); + + DEPTH_TEST(); + } + + if ((params->fbzMode & FBZ_CHROMAKEY) && + write_data.r == params->chromaKey_r && + write_data.g == params->chromaKey_g && + write_data.b == params->chromaKey_b) + goto skip_pixel; + + if (params->fogMode & FOG_ENABLE) + { + int32_t z = new_depth << 12; + int32_t w_depth = new_depth; + int32_t ia = alpha_data << 12; + + APPLY_FOG(write_data.r, write_data.g, write_data.b, z, ia); + } + + if (params->alphaMode & 1) + ALPHA_TEST(alpha_data); + + if (params->alphaMode & (1 << 4)) + { + uint16_t dat = *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]); + int dest_r, dest_g, dest_b, dest_a; + + dest_r = (dat >> 8) & 0xf8; + dest_g = (dat >> 3) & 0xfc; + dest_b = (dat << 3) & 0xf8; + dest_r |= (dest_r >> 5); + dest_g |= (dest_g >> 6); + dest_b |= (dest_b >> 5); + dest_a = 0xff; + + ALPHA_BLEND(write_data.r, write_data.g, write_data.b, alpha_data); + } + + if (params->fbzMode & FBZ_RGB_WMASK) + *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]) = do_dither(&voodoo->params, write_data, x >> 1, y); + if (params->fbzMode & FBZ_DEPTH_WMASK) + *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]) = new_depth; + +skip_pixel: + x = x; + } + } + else + { + if (write_mask & LFB_WRITE_COLOUR) + *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]) = do_dither(&voodoo->params, colour_data, x >> 1, y); + if (write_mask & LFB_WRITE_DEPTH) + *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]) = depth_data; + } +} + + +static void voodoo_fb_writel(uint32_t addr, uint32_t val, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + voodoo_params_t *params = &voodoo->params; + int x, y; + uint32_t write_addr, write_addr_aux; + rgba8_t colour_data[2]; + uint16_t depth_data[2]; + uint8_t alpha_data[2]; + int write_mask, count = 1; + + depth_data[0] = depth_data[1] = voodoo->params.zaColor & 0xffff; + alpha_data[0] = alpha_data[1] = voodoo->params.zaColor >> 24; +// while (!RB_EMPTY) +// thread_reset_event(voodoo->not_full_event); + +// pclog("voodoo_fb_writel : %08X %08X\n", addr, val); + + switch (voodoo->lfbMode & LFB_FORMAT_MASK) + { + case LFB_FORMAT_RGB565: + colour_data[0] = rgb565[val & 0xffff]; + colour_data[1] = rgb565[val >> 16]; + write_mask = LFB_WRITE_COLOUR; + count = 2; + break; + case LFB_FORMAT_RGB555: + colour_data[0] = argb1555[val & 0xffff]; + colour_data[1] = argb1555[val >> 16]; + write_mask = LFB_WRITE_COLOUR; + count = 2; + break; + case LFB_FORMAT_ARGB1555: + colour_data[0] = argb1555[val & 0xffff]; + alpha_data[0] = colour_data[0].a; + colour_data[1] = argb1555[val >> 16]; + alpha_data[1] = colour_data[1].a; + write_mask = LFB_WRITE_COLOUR; + count = 2; + break; + + case LFB_FORMAT_ARGB8888: + colour_data[0].b = val & 0xff; + colour_data[0].g = (val >> 8) & 0xff; + colour_data[0].r = (val >> 16) & 0xff; + alpha_data[0] = (val >> 24) & 0xff; + write_mask = LFB_WRITE_COLOUR; + addr >>= 1; + break; + + case LFB_FORMAT_DEPTH: + depth_data[0] = val; + depth_data[1] = val >> 16; + write_mask = LFB_WRITE_DEPTH; + count = 2; + break; + + default: + fatal("voodoo_fb_writel : bad LFB format %08X\n", voodoo->lfbMode); + } + + x = addr & 0x7fe; + y = (addr >> 11) & 0x3ff; + + if (voodoo->fb_write_offset == voodoo->params.front_offset) + voodoo->dirty_line[y] = 1; + + write_addr = voodoo->fb_write_offset + x + (y * voodoo->row_width); + write_addr_aux = voodoo->params.aux_offset + x + (y * voodoo->row_width); + +// pclog("fb_writel %08x x=%i y=%i rw=%i %08x wo=%08x\n", addr, x, y, voodoo->row_width, write_addr, voodoo->fb_write_offset); + + if (voodoo->lfbMode & 0x100) + { + int c; + + for (c = 0; c < count; c++) + { + rgba8_t write_data = colour_data[c]; + uint16_t new_depth = depth_data[c]; + + if (params->fbzMode & FBZ_DEPTH_ENABLE) + { + uint16_t old_depth = *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]); + + DEPTH_TEST(); + } + + if ((params->fbzMode & FBZ_CHROMAKEY) && + write_data.r == params->chromaKey_r && + write_data.g == params->chromaKey_g && + write_data.b == params->chromaKey_b) + goto skip_pixel; + + if (params->fogMode & FOG_ENABLE) + { + int32_t z = new_depth << 12; + int32_t w_depth = new_depth; + int32_t ia = alpha_data[c] << 12; + + APPLY_FOG(write_data.r, write_data.g, write_data.b, z, ia); + } + + if (params->alphaMode & 1) + ALPHA_TEST(alpha_data[c]); + + if (params->alphaMode & (1 << 4)) + { + uint16_t dat = *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]); + int dest_r, dest_g, dest_b, dest_a; + + dest_r = (dat >> 8) & 0xf8; + dest_g = (dat >> 3) & 0xfc; + dest_b = (dat << 3) & 0xf8; + dest_r |= (dest_r >> 5); + dest_g |= (dest_g >> 6); + dest_b |= (dest_b >> 5); + dest_a = 0xff; + + ALPHA_BLEND(write_data.r, write_data.g, write_data.b, alpha_data[c]); + } + + if (params->fbzMode & FBZ_RGB_WMASK) + *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]) = do_dither(&voodoo->params, write_data, (x >> 1) + c, y); + if (params->fbzMode & FBZ_DEPTH_WMASK) + *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]) = new_depth; + +skip_pixel: + write_addr += 2; + write_addr_aux += 2; + } + } + else + { + int c; + + for (c = 0; c < count; c++) + { + if (write_mask & LFB_WRITE_COLOUR) + *(uint16_t *)(&voodoo->fb_mem[write_addr & voodoo->fb_mask]) = do_dither(&voodoo->params, colour_data[c], (x >> 1) + c, y); + if (write_mask & LFB_WRITE_DEPTH) + *(uint16_t *)(&voodoo->fb_mem[write_addr_aux & voodoo->fb_mask]) = depth_data[c]; + + write_addr += 2; + write_addr_aux += 2; + } + } +} + +static void voodoo_tex_writel(uint32_t addr, uint32_t val, void *p) +{ + int lod, s, t; + voodoo_t *voodoo = (voodoo_t *)p; + + if (addr & 0x600000) + return; /*TREX != 0*/ + +// pclog("voodoo_tex_writel : %08X %08X %i\n", addr, val, voodoo->params.tformat); + + lod = (addr >> 17) & 0xf; + t = (addr >> 9) & 0xff; + if (voodoo->params.tformat & 8) + s = (addr >> 1) & 0xfe; + else + { + if (voodoo->params.textureMode & (1 << 31)) + s = addr & 0xfc; + else + s = (addr >> 1) & 0xfc; + } + + if (lod > LOD_MAX) + return; + +// if (addr >= 0x200000) +// return; + + if (voodoo->params.tformat & 8) + addr = voodoo->params.tex_base[lod] + s*2 + (t << voodoo->params.tex_shift[lod])*2; + else + addr = voodoo->params.tex_base[lod] + s + (t << voodoo->params.tex_shift[lod]); + *(uint32_t *)(&voodoo->tex_mem[addr & voodoo->texture_mask]) = val; +} + +static inline void wake_fifo_thread(voodoo_t *voodoo) +{ + thread_set_event(voodoo->wake_fifo_thread); /*Wake up FIFO thread if moving from idle*/ +} + +static inline void queue_command(voodoo_t *voodoo, uint32_t addr_type, uint32_t val) +{ + fifo_entry_t *fifo = &voodoo->fifo[voodoo->fifo_write_idx & FIFO_MASK]; + int c; + + if (FIFO_FULL) + { + thread_reset_event(voodoo->fifo_not_full_event); + if (FIFO_FULL) + { + thread_wait_event(voodoo->fifo_not_full_event, -1); /*Wait for room in ringbuffer*/ + } + } + + fifo->val = val; + fifo->addr_type = addr_type; + + voodoo->fifo_write_idx++; + + if (FIFO_ENTRIES > 0xe000) + wake_fifo_thread(voodoo); +} + +static uint16_t voodoo_readw(uint32_t addr, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + + addr &= 0xffffff; + + cycles -= pci_nonburst_time; + + if ((addr & 0xc00000) == 0x400000) /*Framebuffer*/ + { + voodoo->flush = 1; + while (!FIFO_EMPTY) + { + wake_fifo_thread(voodoo); + thread_wait_event(voodoo->fifo_not_full_event, 1); + } + wait_for_render_thread_idle(voodoo); + voodoo->flush = 0; + + return voodoo_fb_readw(addr, voodoo); + } + + return 0xffff; +} + +static uint32_t voodoo_readl(uint32_t addr, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + uint32_t temp; + int fifo_size; + voodoo->rd_count++; + addr &= 0xffffff; + + cycles -= pci_nonburst_time; + + if (addr & 0x800000) /*Texture*/ + { + } + else if (addr & 0x400000) /*Framebuffer*/ + { + voodoo->flush = 1; + while (!FIFO_EMPTY) + { + wake_fifo_thread(voodoo); + thread_wait_event(voodoo->fifo_not_full_event, 1); + } + wait_for_render_thread_idle(voodoo); + voodoo->flush = 0; + + temp = voodoo_fb_readl(addr, voodoo); + } + else switch (addr & 0x3fc) + { + case SST_status: + fifo_size = 0xffff - FIFO_ENTRIES; + temp = fifo_size << 12; + if (fifo_size < 0x40) + temp |= fifo_size; + else + temp |= 0x3f; + temp |= (voodoo->swap_count << 28); + if (voodoo->cmd_written - voodoo->cmd_read) + temp |= 0x380; /*Busy*/ + if (!voodoo->v_retrace) + temp |= 0x40; + if (!voodoo->voodoo_busy) + wake_fifo_thread(voodoo); + break; + + case SST_lfbMode: + voodoo->flush = 1; + while (!FIFO_EMPTY) + { + wake_fifo_thread(voodoo); + thread_wait_event(voodoo->fifo_not_full_event, 1); + } + wait_for_render_thread_idle(voodoo); + voodoo->flush = 0; + + temp = voodoo->lfbMode; + break; + + case SST_fbiPixelsIn: + temp = voodoo->fbiPixelsIn & 0xffffff; + break; + case SST_fbiChromaFail: + temp = voodoo->fbiChromaFail & 0xffffff; + break; + case SST_fbiZFuncFail: + temp = voodoo->fbiZFuncFail & 0xffffff; + break; + case SST_fbiAFuncFail: + temp = voodoo->fbiAFuncFail & 0xffffff; + break; + case SST_fbiPixelsOut: + temp = voodoo->fbiPixelsOut & 0xffffff; + break; + + case SST_fbiInit4: + temp = voodoo->fbiInit4; + break; + case SST_fbiInit0: + temp = voodoo->fbiInit0; + break; + case SST_fbiInit1: + temp = voodoo->fbiInit1 & ~5; /*Pass-thru board with one SST-1*/ + break; + case SST_fbiInit2: + if (voodoo->initEnable & 0x04) + temp = voodoo->dac_readdata; + else + temp = voodoo->fbiInit2; + break; + case SST_fbiInit3: + temp = voodoo->fbiInit3; + break; + + default: + fatal("voodoo_readl : bad addr %08X\n", addr); + temp = 0xffffffff; + } + + return temp; +} + +static void voodoo_writew(uint32_t addr, uint16_t val, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + voodoo->wr_count++; + addr &= 0xffffff; + + if (addr == voodoo->last_write_addr+4) + cycles -= pci_burst_time; + else + cycles -= pci_nonburst_time; + voodoo->last_write_addr = addr; + + if ((addr & 0xc00000) == 0x400000) /*Framebuffer*/ + queue_command(voodoo, addr | FIFO_WRITEW_FB, val); +} + +static void voodoo_pixelclock_update(voodoo_t *voodoo) +{ + int m = (voodoo->dac_pll_regs[0] & 0x7f) + 2; + int n1 = ((voodoo->dac_pll_regs[0] >> 8) & 0x1f) + 2; + int n2 = ((voodoo->dac_pll_regs[0] >> 13) & 0x07); + float t = (14318184.0 * ((float)m / (float)n1)) / (float)(1 << n2); + double clock_const; + int line_length; + + if ((voodoo->dac_data[6] & 0xf0) == 0x20 || + (voodoo->dac_data[6] & 0xf0) == 0x60 || + (voodoo->dac_data[6] & 0xf0) == 0x70) + t /= 2.0f; + + line_length = (voodoo->hSync & 0xff) + ((voodoo->hSync >> 16) & 0x3ff); + +// pclog("Pixel clock %f MHz hsync %08x line_length %d\n", t, voodoo->hSync, line_length); + + voodoo->pixel_clock = t; + + clock_const = cpuclock / t; + voodoo->line_time = (int)((double)line_length * clock_const * (double)(1 << TIMER_SHIFT)); +} + +static void voodoo_writel(uint32_t addr, uint32_t val, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + voodoo->wr_count++; + addr &= 0xffffff; + + if (addr == voodoo->last_write_addr+4) + cycles -= pci_burst_time; + else + cycles -= pci_nonburst_time; + voodoo->last_write_addr = addr; + + if (addr & 0x800000) /*Texture*/ + { + voodoo->tex_count++; + queue_command(voodoo, addr | FIFO_WRITEL_TEX, val); + } + else if (addr & 0x400000) /*Framebuffer*/ + { + queue_command(voodoo, addr | FIFO_WRITEL_FB, val); + } + else switch (addr & 0x3fc) + { + case SST_swapbufferCMD: + voodoo->cmd_written++; + voodoo->swap_count++; + queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + wake_fifo_thread(voodoo); + break; + case SST_triangleCMD: + voodoo->cmd_written++; + queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + wake_fifo_thread(voodoo); + break; + case SST_ftriangleCMD: + voodoo->cmd_written++; + queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + wake_fifo_thread(voodoo); + break; + case SST_fastfillCMD: + voodoo->cmd_written++; + queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + wake_fifo_thread(voodoo); + break; + case SST_nopCMD: + voodoo->cmd_written++; + queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + if (!voodoo->voodoo_busy) + wake_fifo_thread(voodoo); + break; + + case SST_fbiInit4: + if (voodoo->initEnable & 0x01) + voodoo->fbiInit4 = val; + break; + case SST_backPorch: + voodoo->backPorch = val; + break; + case SST_videoDimensions: + voodoo->videoDimensions = val; + voodoo->h_disp = (val & 0xfff) + 1; + voodoo->v_disp = (val >> 16) & 0xfff; + break; + case SST_fbiInit0: + if (voodoo->initEnable & 0x01) + { + voodoo->fbiInit0 = val; + svga_set_override(voodoo->svga, val & 1); + } + break; + case SST_fbiInit1: + if (voodoo->initEnable & 0x01) + voodoo->fbiInit1 = val; + break; + case SST_fbiInit2: + if (voodoo->initEnable & 0x01) + { + voodoo->fbiInit2 = val; + voodoo_recalc(voodoo); + } + break; + case SST_fbiInit3: + if (voodoo->initEnable & 0x01) + voodoo->fbiInit3 = val; + break; + + case SST_hSync: + voodoo->hSync = val; + voodoo_pixelclock_update(voodoo); + break; + case SST_vSync: + voodoo->vSync = val; + voodoo->v_total = (val & 0xffff) + (val >> 16); + break; + + case SST_clutData: + voodoo->clutData[(val >> 24) & 0x3f].b = val & 0xff; + voodoo->clutData[(val >> 24) & 0x3f].g = (val >> 8) & 0xff; + voodoo->clutData[(val >> 24) & 0x3f].r = (val >> 16) & 0xff; + voodoo->clutData_dirty = 1; + break; + + case SST_dacData: + voodoo->dac_reg = (val >> 8) & 7; + voodoo->dac_readdata = 0xff; + if (val & 0x800) + { +// pclog(" dacData read %i %02X\n", voodoo->dac_reg, voodoo->dac_data[7]); + if (voodoo->dac_reg == 5) + { + switch (voodoo->dac_data[7]) + { + case 0x01: voodoo->dac_readdata = 0x55; break; + case 0x07: voodoo->dac_readdata = 0x71; break; + case 0x0b: voodoo->dac_readdata = 0x79; break; + } + } + else + voodoo->dac_readdata = voodoo->dac_data[voodoo->dac_reg]; + } + else + { + if (voodoo->dac_reg == 5) + { + if (!voodoo->dac_reg_ff) + voodoo->dac_pll_regs[voodoo->dac_data[4] & 0xf] = (voodoo->dac_pll_regs[voodoo->dac_data[4] & 0xf] & 0xff00) | val; + else + voodoo->dac_pll_regs[voodoo->dac_data[4] & 0xf] = (voodoo->dac_pll_regs[voodoo->dac_data[4] & 0xf] & 0xff) | (val << 8); +// pclog("Write PLL reg %x %04x\n", voodoo->dac_data[4] & 0xf, voodoo->dac_pll_regs[voodoo->dac_data[4] & 0xf]); + voodoo->dac_reg_ff = !voodoo->dac_reg_ff; + if (!voodoo->dac_reg_ff) + voodoo->dac_data[4]++; + + } + else + { + voodoo->dac_data[voodoo->dac_reg] = val & 0xff; + voodoo->dac_reg_ff = 0; + } + voodoo_pixelclock_update(voodoo); + } + break; + + default: + queue_command(voodoo, addr | FIFO_WRITEL_REG, val); + break; + } +} + +static void fifo_thread(void *param) +{ + voodoo_t *voodoo = (voodoo_t *)param; + + while (1) + { + thread_set_event(voodoo->fifo_not_full_event); + thread_wait_event(voodoo->wake_fifo_thread, -1); + thread_reset_event(voodoo->wake_fifo_thread); + voodoo->voodoo_busy = 1; + while (!FIFO_EMPTY) + { + uint64_t start_time = timer_read(); + uint64_t end_time; + fifo_entry_t *fifo = &voodoo->fifo[voodoo->fifo_read_idx & FIFO_MASK]; + + switch (fifo->addr_type & FIFO_TYPE) + { + case FIFO_WRITEL_REG: + voodoo_reg_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo); + break; + case FIFO_WRITEW_FB: + wait_for_render_thread_idle(voodoo); + voodoo_fb_writew(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo); + break; + case FIFO_WRITEL_FB: + wait_for_render_thread_idle(voodoo); + voodoo_fb_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo); + break; + case FIFO_WRITEL_TEX: + if (!(fifo->addr_type & 0x600000)) + { + wait_for_render_thread_idle(voodoo); + voodoo_tex_writel(fifo->addr_type & FIFO_ADDR, fifo->val, voodoo); + } + break; + } + + voodoo->fifo_read_idx++; + fifo->addr_type = FIFO_INVALID; + + if (FIFO_ENTRIES > 0xe000) + thread_set_event(voodoo->fifo_not_full_event); + + end_time = timer_read(); + voodoo_time += end_time - start_time; + } + voodoo->voodoo_busy = 0; + + } +} + +static void voodoo_recalcmapping(voodoo_t *voodoo) +{ + if (voodoo->pci_enable && voodoo->memBaseAddr) + { +#if 0 + pclog("voodoo_recalcmapping : memBaseAddr %08X\n", voodoo->memBaseAddr); +#endif + mem_mapping_set_addr(&voodoo->mapping, voodoo->memBaseAddr, 0x01000000); + } + else + { +#if 0 + pclog("voodoo_recalcmapping : disabled\n"); +#endif + mem_mapping_disable(&voodoo->mapping); + } +} + +uint8_t voodoo_pci_read(int func, int addr, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + +#if 0 + pclog("Voodoo PCI read %08X\n", addr); +#endif + switch (addr) + { + case 0x00: return 0x1a; /*3dfx*/ + case 0x01: return 0x12; + + case 0x02: return 0x01; /*SST-1 (Voodoo Graphics)*/ + case 0x03: return 0x00; + + case 0x04: return voodoo->pci_enable ? 0x02 : 0x00; /*Respond to memory accesses*/ + + case 0x08: return 2; /*Revision ID*/ + case 0x09: return 0; /*Programming interface*/ + + case 0x10: return 0x00; /*memBaseAddr*/ + case 0x11: return 0x00; + case 0x12: return 0x00; + case 0x13: return voodoo->memBaseAddr >> 24; + + case 0x40: return voodoo->initEnable; + } + return 0; +} + +void voodoo_pci_write(int func, int addr, uint8_t val, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + +#if 0 + pclog("Voodoo PCI write %04X %02X\n", addr, val); +#endif + switch (addr) + { + case 0x04: + voodoo->pci_enable = val & 2; + voodoo_recalcmapping(voodoo); + break; + + case 0x13: + voodoo->memBaseAddr = val << 24; + voodoo_recalcmapping(voodoo); + break; + + case 0x40: + voodoo->initEnable = val; + break; + } +} + +static void voodoo_calc_clutData(voodoo_t *voodoo) +{ + int c; + + for (c = 0; c < 256; c++) + { + voodoo->clutData256[c].r = (voodoo->clutData[c >> 3].r*(8-(c & 7)) + + voodoo->clutData[(c >> 3)+1].r*(c & 7)) >> 3; + voodoo->clutData256[c].g = (voodoo->clutData[c >> 3].g*(8-(c & 7)) + + voodoo->clutData[(c >> 3)+1].g*(c & 7)) >> 3; + voodoo->clutData256[c].b = (voodoo->clutData[c >> 3].b*(8-(c & 7)) + + voodoo->clutData[(c >> 3)+1].b*(c & 7)) >> 3; + } + + for (c = 0; c < 65536; c++) + { + int r = (c >> 8) & 0xf8; + int g = (c >> 3) & 0xfc; + int b = (c << 3) & 0xf8; +// r |= (r >> 5); +// g |= (g >> 6); +// b |= (b >> 5); + + voodoo->video_16to32[c] = (voodoo->clutData256[r].r << 16) | (voodoo->clutData256[g].g << 8) | voodoo->clutData256[b].b; + } +} + +#define FILTCAP 64.0f /* Needs tuning to match DAC */ +#define FILTCAPG (FILTCAP / 2) + +static void voodoo_generate_filter(voodoo_t *voodoo) +{ + int g, h, i; + float difference, diffg; + float color; + float thiscol, thiscolg, lined; + + for (g=0;g<1024;g++) // pixel 1 + { + for (h=0;h<1024;h++) // pixel 2 + { + difference = h - g; + diffg = difference / 2; + + if (difference > FILTCAP) + difference = FILTCAP; + if (difference < -FILTCAP) + difference = -FILTCAP; + + if (diffg > FILTCAPG) + diffg = FILTCAPG; + if (diffg < -FILTCAPG) + diffg = -FILTCAPG; + + thiscol = g + (difference / 3); + thiscolg = g + (diffg / 3); + + if (thiscol < 0) + thiscol = 0; + if (thiscol > 1023) + thiscol = 1023; + + if (thiscolg < 0) + thiscolg = 0; + if (thiscolg > 1023) + thiscolg = 1023; + + voodoo->thefilter[g][h] = thiscol; + voodoo->thefilterg[g][h] = thiscolg; + } + + lined = g + 4; + if (lined > 1023) + lined = 1023; + voodoo->purpleline[g] = lined; + } +} + +static void voodoo_filterline(voodoo_t *voodoo, uint16_t *fil, int column, uint16_t *src, int line) +{ + int x; + + /* 16 to 32-bit */ + for (x=0; x> 5) & 63) << 4); + fil[x*3+2] = (((src[x] >> 11) & 31) << 5); + } + fil[x*3] = 0; + fil[x*3+1] = 0; + fil[x*3+2] = 0; + + /* filtering time */ + + for (x=1; xthefilter[fil[x*3]][fil[(x-1)*3]]; + fil[x*3+1] = voodoo->thefilterg[fil[x*3+1]][fil[(x-1)*3+1]]; + fil[x*3+2] = voodoo->thefilter[fil[x*3+2]][fil[(x-1)*3+2]]; + } + for (x=1; xthefilter[fil[x*3]][fil[(x-1)*3]]; + fil[x*3+1] = voodoo->thefilterg[fil[x*3+1]][fil[(x-1)*3+1]]; + fil[x*3+2] = voodoo->thefilter[fil[x*3+2]][fil[(x-1)*3+2]]; + } + for (x=1; xthefilter[fil[x*3]][fil[(x-1)*3]]; + fil[x*3+1] = voodoo->thefilterg[fil[x*3+1]][fil[(x-1)*3+1]]; + fil[x*3+2] = voodoo->thefilter[fil[x*3+2]][fil[(x-1)*3+2]]; + } + + for (x=0; xthefilter[fil[x*3]][fil[(x+1)*3]]) >> 2; + fil[x*3+1] = (voodoo->thefilterg[fil[x*3+1]][fil[(x+1)*3+1]]) >> 2; + fil[x*3+2] = (voodoo->thefilter[fil[x*3+2]][fil[(x+1)*3+2]]) >> 2; + } + + /* lines */ + + if (line & 1) + { + for (x=0; xpurpleline[fil[x*3]]; + fil[x*3+2] = voodoo->purpleline[fil[x*3+2]]; + } + } +} + +void voodoo_callback(void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + int y_add = enable_overscan ? 16 : 0; + int x_add = enable_overscan ? 8 : 0; + + if (voodoo->fbiInit0 & FBIINIT0_VGA_PASS) + { + if (voodoo->line < voodoo->v_disp) + { + if (voodoo->dirty_line[voodoo->line]) + { + uint32_t *p = &((uint32_t *)buffer32->line[voodoo->line + y_add])[32 + x_add]; + uint16_t *src = (uint16_t *)&voodoo->fb_mem[voodoo->front_offset + voodoo->line*voodoo->row_width]; + int x; + + voodoo->dirty_line[voodoo->line] = 0; + + if (voodoo->line < voodoo->dirty_line_low) + voodoo->dirty_line_low = voodoo->line; + if (voodoo->line > voodoo->dirty_line_high) + voodoo->dirty_line_high = voodoo->line; + + if (voodoo->scrfilter) + { + int j, offset; + uint16_t fil[(voodoo->h_disp + 1) * 3]; /* interleaved 24-bit RGB */ + + voodoo_filterline(voodoo, fil, voodoo->h_disp, src, voodoo->line); + + for (x = 0; x < voodoo->h_disp; x++) + { + p[x] = (voodoo->clutData256[fil[x*3]].b << 0 | voodoo->clutData256[fil[x*3+1]].g << 8 | voodoo->clutData256[fil[x*3+2]].r << 16); + } + } + else + { + for (x = 0; x < voodoo->h_disp; x++) + { + p[x] = voodoo->video_16to32[src[x]]; + } + } + } + } + } + if (voodoo->line == voodoo->v_disp) + { +// pclog("retrace %i %i %08x %i\n", voodoo->retrace_count, voodoo->swap_interval, voodoo->swap_offset, voodoo->swap_pending); + voodoo->retrace_count++; + if (voodoo->swap_pending && (voodoo->retrace_count > voodoo->swap_interval)) + { + memset(voodoo->dirty_line, 1, 1024); + voodoo->retrace_count = 0; + voodoo->front_offset = voodoo->swap_offset; + voodoo->swap_count--; + voodoo->swap_pending = 0; + thread_set_event(voodoo->wake_fifo_thread); + voodoo->frame_count++; + } + voodoo->v_retrace = 1; + } + voodoo->line++; + + if (voodoo->fbiInit0 & FBIINIT0_VGA_PASS) + { + if (voodoo->line == voodoo->v_disp) + { + if (voodoo->dirty_line_high > voodoo->dirty_line_low) + svga_doblit(0, voodoo->v_disp, voodoo->h_disp, voodoo->v_disp, voodoo->svga); + if (voodoo->clutData_dirty) + { + voodoo->clutData_dirty = 0; + voodoo_calc_clutData(voodoo); + } + voodoo->dirty_line_high = -1; + voodoo->dirty_line_low = 2000; + } + } + + if (voodoo->line >= voodoo->v_total) + { + voodoo->line = 0; + voodoo->v_retrace = 0; + } + if (voodoo->line_time) + voodoo->timer_count += voodoo->line_time; + else + voodoo->timer_count += TIMER_USEC * 32; +} + +static void voodoo_add_status_info(char *s, int max_len, void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + char temps[256]; + int pixel_count_current[2]; + int pixel_count_total; + uint64_t new_time = timer_read(); + uint64_t status_diff = new_time - status_time; + status_time = new_time; + + if (!status_diff) + status_diff = 1; + + svga_add_status_info(s, max_len, &voodoo->svga); + + pixel_count_current[0] = voodoo->pixel_count[0]; + pixel_count_current[1] = voodoo->pixel_count[1]; + pixel_count_total = (pixel_count_current[0] + pixel_count_current[1]) - (voodoo->pixel_count_old[0] + voodoo->pixel_count_old[1]); + sprintf(temps, "%f Mpixels/sec (%f)\n%f ktris/sec\n%f%% CPU (%f%% real)\n%d frames/sec (%i)\n%f%% CPU (%f%% real)\n%f%% CPU (%f%% real)\n"/*%d reads/sec\n%d write/sec\n%d tex/sec\n*/, + (double)pixel_count_total/1000000.0, + ((double)pixel_count_total/1000000.0) / ((double)voodoo_render_time[0] / status_diff), + (double)voodoo->tri_count/1000.0, ((double)voodoo_time * 100.0) / timer_freq, ((double)voodoo_time * 100.0) / status_diff, voodoo->frame_count, voodoo_recomp, + ((double)voodoo_render_time[0] * 100.0) / timer_freq, ((double)voodoo_render_time[0] * 100.0) / status_diff, + ((double)voodoo_render_time[1] * 100.0) / timer_freq, ((double)voodoo_render_time[1] * 100.0) / status_diff); + strncat(s, temps, max_len); + + voodoo->pixel_count_old[0] = pixel_count_current[0]; + voodoo->pixel_count_old[1] = pixel_count_current[1]; + voodoo->tri_count = voodoo->frame_count = 0; + voodoo->rd_count = voodoo->wr_count = voodoo->tex_count = 0; + voodoo_time = 0; + voodoo_render_time[0] = voodoo_render_time[1] = 0; + voodoo_recomp = 0; +} + +static void voodoo_speed_changed(void *p) +{ + voodoo_t *voodoo = (voodoo_t *)p; + + voodoo_pixelclock_update(voodoo); +} + +void *voodoo_init() +{ + int c; + voodoo_t *voodoo = malloc(sizeof(voodoo_t)); + memset(voodoo, 0, sizeof(voodoo_t)); + + voodoo->bilinear_enabled = device_get_config_int("bilinear"); + voodoo->scrfilter = device_get_config_int("dacfilter"); + voodoo->texture_size = device_get_config_int("texture_memory"); + voodoo->texture_mask = (voodoo->texture_size << 20) - 1; + voodoo->fb_size = device_get_config_int("framebuffer_memory"); + voodoo->fb_mask = (voodoo->fb_size << 20) - 1; + voodoo->render_threads = device_get_config_int("render_threads"); + voodoo->odd_even_mask = voodoo->render_threads - 1; +#ifndef NO_CODEGEN + voodoo->use_recompiler = device_get_config_int("recompiler"); +#endif + voodoo_generate_filter(voodoo); /*generate filter lookup tables*/ + + pci_add(voodoo_pci_read, voodoo_pci_write, voodoo); + + mem_mapping_add(&voodoo->mapping, 0, 0, NULL, voodoo_readw, voodoo_readl, NULL, voodoo_writew, voodoo_writel, NULL, 0, voodoo); + + voodoo->fb_mem = malloc(4 * 1024 * 1024); + voodoo->tex_mem = malloc(voodoo->texture_size * 1024 * 1024); + voodoo->tex_mem_w = (uint16_t *)voodoo->tex_mem; + + timer_add(voodoo_callback, &voodoo->timer_count, TIMER_ALWAYS_ENABLED, voodoo); + + voodoo->svga = svga_get_pri(); + voodoo->fbiInit0 = 0; + + voodoo->wake_fifo_thread = thread_create_event(); + voodoo->wake_render_thread[0] = thread_create_event(); + voodoo->wake_render_thread[1] = thread_create_event(); + voodoo->wake_main_thread = thread_create_event(); + voodoo->fifo_not_full_event = thread_create_event(); + voodoo->render_not_full_event[0] = thread_create_event(); + voodoo->render_not_full_event[1] = thread_create_event(); + voodoo->fifo_thread = thread_create(fifo_thread, voodoo); + voodoo->render_thread[0] = thread_create(render_thread_1, voodoo); + if (voodoo->render_threads == 2) + voodoo->render_thread[1] = thread_create(render_thread_2, voodoo); + + for (c = 0; c < 0x100; c++) + { + rgb332[c].r = c & 0xe0; + rgb332[c].g = (c << 3) & 0xe0; + rgb332[c].b = (c << 6) & 0xc0; + rgb332[c].r = rgb332[c].r | (rgb332[c].r >> 3) | (rgb332[c].r >> 6); + rgb332[c].g = rgb332[c].g | (rgb332[c].g >> 3) | (rgb332[c].g >> 6); + rgb332[c].b = rgb332[c].b | (rgb332[c].b >> 2); + rgb332[c].b = rgb332[c].b | (rgb332[c].b >> 4); + rgb332[c].a = 0xff; + + ai44[c].a = (c & 0xf0) | ((c & 0xf0) >> 4); + ai44[c].r = (c & 0x0f) | ((c & 0x0f) << 4); + ai44[c].g = ai44[c].b = ai44[c].r; + } + + for (c = 0; c < 0x10000; c++) + { + rgb565[c].r = (c >> 8) & 0xf8; + rgb565[c].g = (c >> 3) & 0xfc; + rgb565[c].b = (c << 3) & 0xf8; + rgb565[c].r |= (rgb565[c].r >> 5); + rgb565[c].g |= (rgb565[c].g >> 6); + rgb565[c].b |= (rgb565[c].b >> 5); + rgb565[c].a = 0xff; + + argb1555[c].r = (c >> 7) & 0xf8; + argb1555[c].g = (c >> 2) & 0xf8; + argb1555[c].b = (c << 3) & 0xf8; + argb1555[c].r |= (argb1555[c].r >> 5); + argb1555[c].g |= (argb1555[c].g >> 5); + argb1555[c].b |= (argb1555[c].b >> 5); + argb1555[c].a = (c & 0x8000) ? 0xff : 0; + + argb4444[c].a = (c >> 8) & 0xf0; + argb4444[c].r = (c >> 4) & 0xf0; + argb4444[c].g = c & 0xf0; + argb4444[c].b = (c << 4) & 0xf0; + argb4444[c].a |= (argb4444[c].a >> 4); + argb4444[c].r |= (argb4444[c].r >> 4); + argb4444[c].g |= (argb4444[c].g >> 4); + argb4444[c].b |= (argb4444[c].b >> 4); + + ai88[c].a = (c >> 8); + ai88[c].r = c & 0xff; + ai88[c].g = c & 0xff; + ai88[c].b = c & 0xff; + } +#ifndef NO_CODEGEN + voodoo_codegen_init(voodoo); +#endif + return voodoo; +} + +void voodoo_close(void *p) +{ + FILE *f; + voodoo_t *voodoo = (voodoo_t *)p; +#ifndef RELEASE_BUILD + f = romfopen("texram.dmp", "wb"); + fwrite(voodoo->tex_mem, 2048*1024, 1, f); + fclose(f); +#endif + + thread_kill(voodoo->fifo_thread); + thread_kill(voodoo->render_thread[0]); + if (voodoo->render_threads == 2) + thread_kill(voodoo->render_thread[1]); + thread_destroy_event(voodoo->fifo_not_full_event); + thread_destroy_event(voodoo->wake_main_thread); + thread_destroy_event(voodoo->wake_fifo_thread); + thread_destroy_event(voodoo->wake_render_thread[0]); + thread_destroy_event(voodoo->wake_render_thread[1]); + thread_destroy_event(voodoo->render_not_full_event[0]); + thread_destroy_event(voodoo->render_not_full_event[1]); +#ifndef NO_CODEGEN + voodoo_codegen_close(voodoo); +#endif + free(voodoo->fb_mem); + free(voodoo->tex_mem); + free(voodoo); +} + +static device_config_t voodoo_config[] = +{ + { + .name = "framebuffer_memory", + .description = "Framebuffer memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } + }, + .default_int = 2 + }, + { + .name = "texture_memory", + .description = "Texture memory size", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "2 MB", + .value = 2 + }, + { + .description = "4 MB", + .value = 4 + }, + { + .description = "" + } + }, + .default_int = 2 + }, + { + .name = "bilinear", + .description = "Bilinear filtering", + .type = CONFIG_BINARY, + .default_int = 1 + }, + { + .name = "dacfilter", + .description = "Screen Filter", + .type = CONFIG_BINARY, + .default_int = 0 + }, + { + .name = "render_threads", + .description = "Render threads", + .type = CONFIG_SELECTION, + .selection = + { + { + .description = "1", + .value = 1 + }, + { + .description = "2", + .value = 2 + }, + { + .description = "" + } + }, + .default_int = 2 + }, +#ifndef NO_CODEGEN + { + .name = "recompiler", + .description = "Recompiler", + .type = CONFIG_BINARY, + .default_int = 1 + }, +#endif + { + .type = -1 + } +}; + +device_t voodoo_device = +{ + "3DFX Voodoo Graphics", + 0, + voodoo_init, + voodoo_close, + NULL, + voodoo_speed_changed, + NULL, + voodoo_add_status_info, + voodoo_config +}; diff --git a/src/vid_voodoo.h b/src/vid_voodoo.h new file mode 100644 index 000000000..047978327 --- /dev/null +++ b/src/vid_voodoo.h @@ -0,0 +1 @@ +extern device_t voodoo_device; diff --git a/src/vid_voodoo_codegen_x86-64.h b/src/vid_voodoo_codegen_x86-64.h new file mode 100644 index 000000000..fcd84c433 --- /dev/null +++ b/src/vid_voodoo_codegen_x86-64.h @@ -0,0 +1,3720 @@ +/*Registers : + + alphaMode + fbzMode & 0x1f3fff + fbzColorPath +*/ + +#ifdef __linux__ +#include +#include +#endif +#if WIN64 +#define BITMAP windows_BITMAP +#include +#undef BITMAP +#endif + +#include + +#define BLOCK_NUM 8 +#define BLOCK_MASK (BLOCK_NUM-1) +#define BLOCK_SIZE 8192 + +typedef struct voodoo_x86_data_t +{ + uint8_t code_block[BLOCK_SIZE]; + int xdir; + uint32_t alphaMode; + uint32_t fbzMode; + uint32_t fogMode; + uint32_t fbzColorPath; + uint32_t textureMode; + uint32_t trexInit1; +} voodoo_x86_data_t; + +//static voodoo_x86_data_t voodoo_x86_data[2][BLOCK_NUM]; + +static int last_block[2] = {0, 0}; +static int next_block_to_write[2] = {0, 0}; + +#define addbyte(val) \ + code_block[block_pos++] = val; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n") + +#define addword(val) \ + *(uint16_t *)&code_block[block_pos] = val; \ + block_pos += 2; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n") + +#define addlong(val) \ + *(uint32_t *)&code_block[block_pos] = val; \ + block_pos += 4; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n") + +#define addquad(val) \ + *(uint64_t *)&code_block[block_pos] = val; \ + block_pos += 8; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n") + + +static __m128i xmm_01_w;// = 0x0001000100010001ull; +static __m128i xmm_ff_w;// = 0x00ff00ff00ff00ffull; +static __m128i xmm_ff_b;// = 0x00000000ffffffffull; + +static uint32_t zero = 0; +static double const_1_48 = (double)(1ull << 4); + +static __m128i alookup[257], aminuslookup[256]; +static __m128i minus_254;// = 0xff02ff02ff02ff02ull; +static __m128i bilinear_lookup[256*4]; + +static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int depthop) +{ + int block_pos = 0; + int z_skip_pos = 0; + int a_skip_pos = 0; + int chroma_skip_pos = 0; + int depth_jump_pos = 0; + int depth_jump_pos2 = 0; + int loop_jump_pos = 0; +// xmm_01_w = (__m128i)0x0001000100010001ull; +// xmm_ff_w = (__m128i)0x00ff00ff00ff00ffull; +// xmm_ff_b = (__m128i)0x00000000ffffffffull; + xmm_01_w = _mm_set_epi32(0, 0, 0x00010001, 0x00010001); + xmm_ff_w = _mm_set_epi32(0, 0, 0x00ff00ff, 0x00ff00ff); + xmm_ff_b = _mm_set_epi32(0, 0, 0, 0x00ffffff); + minus_254 = _mm_set_epi32(0, 0, 0xff02ff02, 0xff02ff02); +// *(uint64_t *)&const_1_48 = 0x45b0000000000000ull; +// block_pos = 0; +// voodoo_get_depth = &code_block[block_pos]; + /*W at (%esp+4) + Z at (%esp+12) + new_depth at (%esp+16)*/ +// if ((params->fbzMode & FBZ_DEPTH_ENABLE) && (depth_op == DEPTHOP_NEVER)) +// { +// addbyte(0xC3); /*RET*/ +// return; +// } + addbyte(0x55); /*PUSH RBP*/ + addbyte(0x57); /*PUSH RDI*/ + addbyte(0x56); /*PUSH RSI*/ + addbyte(0x53); /*PUSH RBX*/ + addbyte(0x41); /*PUSH R14*/ + addbyte(0x56); + addbyte(0x41); /*PUSH R15*/ + addbyte(0x57); + +#if WIN64 + addbyte(0x48); /*MOV RDI, RCX (voodoo_state)*/ + addbyte(0x89); + addbyte(0xcf); + addbyte(0x49); /*MOV R15, RDX (voodoo_params)*/ + addbyte(0x89); + addbyte(0xd7); + addbyte(0x4d); /*MOV R14, R9 (real_y)*/ + addbyte(0x89); + addbyte(0xce); +#else + addbyte(0x49); /*MOV R9, RCX (real_y)*/ + addbyte(0x89); + addbyte(0xc9); + addbyte(0x49); /*MOV R15, RSI (voodoo_state)*/ + addbyte(0x89); + addbyte(0xf7); +#endif + loop_jump_pos = block_pos; + addbyte(0x4c); /*MOV RSI, R15*/ + addbyte(0x89); + addbyte(0xfe); + addbyte(0x66); /*PXOR XMM2, XMM2*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xd2); + + if ((params->fbzMode & FBZ_W_BUFFER) || (params->fogMode & (FOG_ENABLE|FOG_CONSTANT|FOG_Z|FOG_ALPHA)) == FOG_ENABLE) + { + addbyte(0xb8); /*MOV new_depth, 0*/ + addlong(0); + addbyte(0x66); /*TEST w+4, 0xffff*/ + addbyte(0xf7); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w)+4); + addword(0xffff); + addbyte(0x75); /*JNZ got_depth*/ + depth_jump_pos = block_pos; + addbyte(0); +// addbyte(4+5+2+3+2+5+5+3+2+2+2+/*3+*/3+2+6+4+5+2+3); + addbyte(0x8b); /*MOV EDX, w*/ + addbyte(0x97); + addlong(offsetof(voodoo_state_t, w)); + addbyte(0xb8); /*MOV new_depth, 0xf001*/ + addlong(0xf001); + addbyte(0x89); /*MOV EBX, EDX*/ + addbyte(0xd3); + addbyte(0xc1); /*SHR EDX, 16*/ + addbyte(0xea); + addbyte(16); + addbyte(0x74); /*JZ got_depth*/ + depth_jump_pos2 = block_pos; + addbyte(0); +// addbyte(5+5+3+2+2+2+/*3+*/3+2+6+4+5+2+3); + addbyte(0xb9); /*MOV ECX, 19*/ + addlong(19); + addbyte(0x0f); /*BSR EAX, EDX*/ + addbyte(0xbd); + addbyte(0xc2); + addbyte(0xba); /*MOV EDX, 15*/ + addlong(15); + addbyte(0xf7); /*NOT EBX*/ + addbyte(0xd3); + addbyte(0x29); /*SUB EDX, EAX - EDX = exp*/ + addbyte(0xc2); + addbyte(0x29); /*SUB ECX, EDX*/ + addbyte(0xd1); + addbyte(0xc1); /*SHL EDX, 12*/ + addbyte(0xe2); + addbyte(12); + addbyte(0xd3); /*SHR EBX, CL*/ + addbyte(0xeb); + addbyte(0x81); /*AND EBX, 0xfff - EBX = mant*/ + addbyte(0xe3); + addlong(0xfff); + addbyte(0x67); /*LEA EAX, 1[EDX, EBX]*/ + addbyte(0x8d); + addbyte(0x44); + addbyte(0x13); + addbyte(1); + addbyte(0xbb); /*MOV EBX, 0xffff*/ + addlong(0xffff); + addbyte(0x39); /*CMP EAX, EBX*/ + addbyte(0xd8); + addbyte(0x0f); /*CMOVA EAX, EBX*/ + addbyte(0x47); + addbyte(0xc3); + + if (depth_jump_pos) + *(uint8_t *)&code_block[depth_jump_pos] = (block_pos - depth_jump_pos) - 1; + if (depth_jump_pos) + *(uint8_t *)&code_block[depth_jump_pos2] = (block_pos - depth_jump_pos2) - 1; + + if ((params->fogMode & (FOG_ENABLE|FOG_CONSTANT|FOG_Z|FOG_ALPHA)) == FOG_ENABLE) + { + addbyte(0x89); /*MOV state->w_depth[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w_depth)); + } + } + if (!(params->fbzMode & FBZ_W_BUFFER)) + { + addbyte(0x8b); /*MOV EAX, z*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, z)); + addbyte(0xbb); /*MOV EBX, 0xffff*/ + addlong(0xffff); + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + addbyte(0xc1); /*SAR EAX, 12*/ + addbyte(0xf8); + addbyte(12); + addbyte(0x0f); /*CMOVS EAX, ECX*/ + addbyte(0x48); + addbyte(0xc1); + addbyte(0x39); /*CMP EAX, EBX*/ + addbyte(0xd8); + addbyte(0x0f); /*CMOVA EAX, EBX*/ + addbyte(0x47); + addbyte(0xc3); + } + + if (params->fbzMode & FBZ_DEPTH_BIAS) + { + addbyte(0x03); /*ADD EAX, params->zaColor[ESI]*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, zaColor)); + addbyte(0x25); /*AND EAX, 0xffff*/ + addlong(0xffff); + } + + addbyte(0x89); /*MOV state->new_depth[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, new_depth)); + + if ((params->fbzMode & FBZ_DEPTH_ENABLE) && (depthop != DEPTHOP_ALWAYS) && (depthop != DEPTHOP_NEVER)) + { + addbyte(0x8b); /*MOV EBX, state->x[EDI]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, x)); + addbyte(0x48); /*MOV RCX, aux_mem[RDI]*/ + addbyte(0x8b); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, aux_mem)); + addbyte(0x0f); /*MOVZX EBX, [ECX+EBX*2]*/ + addbyte(0xb7); + addbyte(0x1c); + addbyte(0x59); + addbyte(0x39); /*CMP EAX, EBX*/ + addbyte(0xd8); + if (depthop == DEPTHOP_LESSTHAN) + { + addbyte(0x0f); /*JAE skip*/ + addbyte(0x83); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_EQUAL) + { + addbyte(0x0f); /*JNE skip*/ + addbyte(0x85); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_LESSTHANEQUAL) + { + addbyte(0x0f); /*JA skip*/ + addbyte(0x87); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_GREATERTHAN) + { + addbyte(0x0f); /*JBE skip*/ + addbyte(0x86); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_NOTEQUAL) + { + addbyte(0x0f); /*JE skip*/ + addbyte(0x84); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_GREATERTHANEQUAL) + { + addbyte(0x0f); /*JB skip*/ + addbyte(0x82); + z_skip_pos = block_pos; + addlong(0); + } + else + fatal("Bad depth_op\n"); + } + else if ((params->fbzMode & FBZ_DEPTH_ENABLE) && (depthop == DEPTHOP_NEVER)) + { + addbyte(0xC3); /*RET*/ + } + + /*XMM0 = colour*/ + /*XMM2 = 0 (for unpacking*/ + + /*EDI = state, ESI = params*/ + + if (params->textureMode & 1) + { + addbyte(0x48); /*MOV RBX, state->tmu0_s*/ + addbyte(0x8b); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tmu0_s)); + addbyte(0x48); /*MOV RAX, (1 << 48)*/ + addbyte(0xb8); + addquad(1ULL << 48); + addbyte(0x48); /*XOR RDX, RDX*/ + addbyte(0x31); + addbyte(0xd2); + addbyte(0x48); /*MOV RCX, state->tmu0_t*/ + addbyte(0x8b); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, tmu0_t)); + addbyte(0x48); /*CMP state->tmu_w, 0*/ + addbyte(0x83); + addbyte(0xbf); + addlong(offsetof(voodoo_state_t, tmu0_w)); + addbyte(0); + addbyte(0x74); /*JZ +*/ + addbyte(7); + addbyte(0x48); /*IDIV state->tmu_w*/ + addbyte(0xf7); + addbyte(0xbf); + addlong(offsetof(voodoo_state_t, tmu0_w)); + addbyte(0x48); /*SAR RBX, 14*/ + addbyte(0xc1); + addbyte(0xfb); + addbyte(14); + addbyte(0x48); /*SAR RCX, 14*/ + addbyte(0xc1); + addbyte(0xf9); + addbyte(14); + addbyte(0x48); /*IMUL RBX, RAX*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0xd8); + addbyte(0x48); /*IMUL RCX, RAX*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0xc8); + addbyte(0x48); /*SAR RBX, 30*/ + addbyte(0xc1); + addbyte(0xfb); + addbyte(30); + addbyte(0x48); /*SAR RCX, 30*/ + addbyte(0xc1); + addbyte(0xf9); + addbyte(30); + addbyte(0x48); /*BSR EDX, RAX*/ + addbyte(0x0f); + addbyte(0xbd); + addbyte(0xd0); + addbyte(0x48); /*SHL RAX, 8*/ + addbyte(0xc1); + addbyte(0xe0); + addbyte(8); + addbyte(0x89); /*MOV state->tex_t, ECX*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, tex_t)); + addbyte(0x89); /*MOV ECX, EDX*/ + addbyte(0xd1); + addbyte(0x83); /*SUB EDX, 19*/ + addbyte(0xea); + addbyte(19); + addbyte(0x48); /*SHR RAX, CL*/ + addbyte(0xd3); + addbyte(0xe8); + addbyte(0xc1); /*SHL EDX, 8*/ + addbyte(0xe2); + addbyte(8); + addbyte(0x25); /*AND EAX, 0xff*/ + addlong(0xff); + addbyte(0x89); /*MOV state->tex_s, EBX*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_s)); + addbyte(0x0f); /*MOVZX EAX, logtable[RAX]*/ + addbyte(0xb6); + addbyte(0x80); + addlong((uint32_t)logtable); + addbyte(0x09); /*OR EAX, EDX*/ + addbyte(0xd0); + addbyte(0x03); /*ADD EAX, state->lod*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tmu[0].lod)); + addbyte(0x3b); /*CMP EAX, state->lod_min*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_min)); + addbyte(0x0f); /*CMOVL EAX, state->lod_min*/ + addbyte(0x4c); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_min)); + addbyte(0x3b); /*CMP EAX, state->lod_max*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_max)); + addbyte(0x0f); /*CMOVNL EAX, state->lod_max*/ + addbyte(0x4d); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_max)); + addbyte(0xc1); /*SHR EAX, 8*/ + addbyte(0xe8); + addbyte(8); + addbyte(0x89); /*MOV state->lod, EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod)); + } + else + { + addbyte(0x48); /*MOV RAX, state->tmu0_s*/ + addbyte(0x8b); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tmu0_s)); + addbyte(0x48); /*MOV RCX, state->tmu0_t*/ + addbyte(0x8b); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, tmu0_t)); + addbyte(0x48); /*SHR RAX, 28*/ + addbyte(0xc1); + addbyte(0xe8); + addbyte(28); + addbyte(0x8b); /*MOV EBX, state->lod_min*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, lod_min)); + addbyte(0x48); /*SHR RCX, 28*/ + addbyte(0xc1); + addbyte(0xe9); + addbyte(28); + addbyte(0x48); /*MOV state->tex_s, RAX*/ + addbyte(0x89); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_s)); + addbyte(0xc1); /*SHR EBX, 8*/ + addbyte(0xeb); + addbyte(8); + addbyte(0x48); /*MOV state->tex_t, RCX*/ + addbyte(0x89); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, tex_t)); + addbyte(0x89); /*MOV state->lod, EBX*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, lod)); + } + + + if (voodoo->trexInit1 & (1 << 18)) + { + addbyte(0xb8); /*MOV EAX, 0x000001*/ + addlong(0x000001); + addbyte(0x66); /*MOVD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0); + } + else if (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) + { + if (voodoo->bilinear_enabled && (params->textureMode & 6)) + { + addbyte(0x8b); /*MOV ECX, state->lod[RDI]*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0xbd); /*MOV EBP, 1*/ + addlong(1); + addbyte(0x8a); /*MOV DL, params->tex_shift[RSI+ECX*4]*/ + addbyte(0x94); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_shift)); + addbyte(0xd3); /*SHL EBP, CL*/ + addbyte(0xe5); + addbyte(0x8b); /*MOV EAX, state->tex_s[RDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_s)); + addbyte(0xc1); /*SHL EBP, 3*/ + addbyte(0xe5); + addbyte(3); + addbyte(0x8b); /*MOV EBX, state->tex_t[RDI]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_t)); + addbyte(0x29); /*SUB EAX, EBP*/ + addbyte(0xe8); + addbyte(0x29); /*SUB EBX, EBP*/ + addbyte(0xeb); + addbyte(0xd3); /*SAR EAX, CL*/ + addbyte(0xf8); + addbyte(0xd3); /*SAR EBX, CL*/ + addbyte(0xfb); + addbyte(0x89); /*MOV EBP, EAX*/ + addbyte(0xc5); + addbyte(0x89); /*MOV ECX, EBX*/ + addbyte(0xd9); + addbyte(0x83); /*AND EBP, 0xf*/ + addbyte(0xe5); + addbyte(0xf); + addbyte(0xc1); /*SHL ECX, 4*/ + addbyte(0xe1); + addbyte(4); + addbyte(0xc1); /*SAR EAX, 4*/ + addbyte(0xf8); + addbyte(4); + addbyte(0x81); /*AND ECX, 0xf0*/ + addbyte(0xe1); + addlong(0xf0); + addbyte(0xc1); /*SAR EBX, 4*/ + addbyte(0xfb); + addbyte(4); + addbyte(0x09); /*OR EBP, ECX*/ + addbyte(0xcd); + addbyte(0x8b); /*MOV ECX, state->lod[RDI]*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0xc1); /*SHL EBP, 6*/ + addbyte(0xe5); + addbyte(6); + /*EAX = S, EBX = T, ECX = LOD, EDX = tex_shift, ESI=params, EDI=state, EBP = bilinear shift*/ + addbyte(0x48); /*LEA RSI, [RSI+RCX*4]*/ + addbyte(0x8d); + addbyte(0x34); + addbyte(0x8e); + addbyte(0x89); /*MOV ebp_store, EBP*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, ebp_store)); + addbyte(0x48); /*MOV RBP, state->tex[RDI+RCX*8]*/ + addbyte(0x8b); + addbyte(0xac); + addbyte(0xcf); + addlong(offsetof(voodoo_state_t, tex)); + addbyte(0x88); /*MOV CL, DL*/ + addbyte(0xd1); + addbyte(0x89); /*MOV EDX, EBX*/ + addbyte(0xda); + if (!state->clamp_s) + { + addbyte(0x23); /*AND EAX, params->tex_w_mask[ESI]*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, tex_w_mask)); + } + addbyte(0x83); /*ADD EDX, 1*/ + addbyte(0xc2); + addbyte(1); + if (state->clamp_t) + { + addbyte(0x0f); /*CMOVS EDX, zero*/ + addbyte(0x48); + addbyte(0x14); + addbyte(0x25); + addlong(&zero); + addbyte(0x3b); /*CMP EDX, params->tex_h_mask[ESI]*/ + addbyte(0x96); + addlong(offsetof(voodoo_params_t, tex_h_mask)); + addbyte(0x0f); /*CMOVA EDX, params->tex_h_mask[ESI]*/ + addbyte(0x47); + addbyte(0x96); + addlong(offsetof(voodoo_params_t, tex_h_mask)); + addbyte(0x85); /*TEST EBX,EBX*/ + addbyte(0xdb); + addbyte(0x0f); /*CMOVS EBX, zero*/ + addbyte(0x48); + addbyte(0x1c); + addbyte(0x25); + addlong(&zero); + addbyte(0x3b); /*CMP EBX, params->tex_h_mask[ESI]*/ + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, tex_h_mask)); + addbyte(0x0f); /*CMOVA EBX, params->tex_h_mask[ESI]*/ + addbyte(0x47); + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, tex_h_mask)); + } + else + { + addbyte(0x23); /*AND EDX, params->tex_h_mask[ESI]*/ + addbyte(0x96); + addlong(offsetof(voodoo_params_t, tex_h_mask)); + addbyte(0x23); /*AND EBX, params->tex_h_mask[ESI]*/ + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, tex_h_mask)); + } + /*EAX = S, EBX = T0, EDX = T1*/ + addbyte(0xd3); /*SHL EBX, CL*/ + addbyte(0xe3); + addbyte(0xd3); /*SHL EDX, CL*/ + addbyte(0xe2); + if (state->tformat & 8) + { + addbyte(0x48); /*LEA RBX,[RBP+RBX*2]*/ + addbyte(0x8d); + addbyte(0x5c); + addbyte(0x5d); + addbyte(0); + addbyte(0x48); /*LEA RDX,[RBP+RDX*2]*/ + addbyte(0x8d); + addbyte(0x54); + addbyte(0x55); + addbyte(0); + } + else + { + addbyte(0x48); /*ADD RBX, RBP*/ + addbyte(0x01); + addbyte(0xeb); + addbyte(0x48); /*ADD RDX, RBP*/ + addbyte(0x01); + addbyte(0xea); + } + if (state->clamp_s) + { + addbyte(0x8b); /*MOV EBP, params->tex_w_mask[ESI]*/ + addbyte(0xae); + addlong(offsetof(voodoo_params_t, tex_w_mask)); + addbyte(0x85); /*TEST EAX, EAX*/ + addbyte(0xc0); + addbyte(0x8b); /*MOV ebp_store2, RSI*/ + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, ebp_store)); + addbyte(0x0f); /*CMOVS EAX, zero*/ + addbyte(0x48); + addbyte(0x04); + addbyte(0x25); + addlong(&zero); + addbyte(0x78); /*JS + - clamp on 0*/ + addbyte(2+3+2+ ((state->tformat & 8) ? (3+3+2) : (4+4+2))); + addbyte(0x3b); /*CMP EAX, EBP*/ + addbyte(0xc5); + addbyte(0x0f); /*CMOVAE EAX, EBP*/ + addbyte(0x43); + addbyte(0xc5); + addbyte(0x73); /*JAE + - clamp on +*/ + addbyte((state->tformat & 8) ? (3+3+2) : (4+4+2)); + } + else + { + addbyte(0x3b); /*CMP EAX, params->tex_w_mask[ESI] - is S at texture edge (ie will wrap/clamp)?*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, tex_w_mask)); + addbyte(0x8b); /*MOV ebp_store2, ESI*/ + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, ebp_store)); + addbyte(0x74); /*JE +*/ + addbyte((state->tformat & 8) ? (3+3+2) : (4+4+2)); + } + + if (state->tformat & 8) + { + addbyte(0x8b); /*MOV EDX,[RDX+RAX*2]*/ + addbyte(0x14); + addbyte(0x42); + addbyte(0x8b); /*MOV EAX,[RBX+RAX*2]*/ + addbyte(0x04); + addbyte(0x43); + } + else + { + addbyte(0x0f); /*MOVZX EDX,W[RDX+RAX]*/ + addbyte(0xb7); + addbyte(0x14); + addbyte(0x02); + addbyte(0x0f); /*MOVZX EAX,W[RBX+RAX]*/ + addbyte(0xb7); + addbyte(0x04); + addbyte(0x03); + } + + if (state->clamp_s) + { + addbyte(0xeb); /*JMP +*/ + addbyte((state->tformat & 8) ? (3+4+3+3+4+3) : (4+4+2+2)); + + /*S clamped - the two S coordinates are the same*/ + if (state->tformat & 8) + { + addbyte(0x8b); /*MOV ECX, [RDX+RAX*2]*/ + addbyte(0x0c); + addbyte(0x42); + addbyte(0x8b); /*MOV EDX, [RDX+RAX*2-2]*/ + addbyte(0x54); + addbyte(0x42); + addbyte(-2); + addbyte(0x66); /*MOV DX, CX*/ + addbyte(0x89); + addbyte(0xca); + addbyte(0x8b); /*MOV ECX, [RBX+RAX*2]*/ + addbyte(0x0c); + addbyte(0x43); + addbyte(0x8b); /*MOV EAX, [RBX+RAX*2-2]*/ + addbyte(0x44); + addbyte(0x43); + addbyte(-2); + addbyte(0x66); /*MOV AX, CX*/ + addbyte(0x89); + addbyte(0xc8); + } + else + { + addbyte(0x0f); /*MOVZX EDX,W[RDX+RAX]*/ + addbyte(0xb7); + addbyte(0x14); + addbyte(0x02); + addbyte(0x0f); /*MOVZX EAX,W[RBX+RAX]*/ + addbyte(0xb7); + addbyte(0x04); + addbyte(0x03); + addbyte(0x88); /*MOV DH, DL*/ + addbyte(0xd6); + addbyte(0x88); /*MOV AH, AL*/ + addbyte(0xc4); + } + } + else + { + addbyte(0xeb); /*JMP +*/ + addbyte((state->tformat & 8) ? (3+3+3+3+3+3) : (2+2+4+4+2+2)); + + /*S wrapped - the two S coordinates are not contiguous*/ + if (state->tformat & 8) + { + addbyte(0x8b); /*MOV ECX, [RDX+RAX*2]*/ + addbyte(0x0c); + addbyte(0x42); + addbyte(0x8b); /*MOV EDX, [RDX-2]*/ + addbyte(0x52); + addbyte(-2); + addbyte(0x66); /*MOV DX, CX*/ + addbyte(0x89); + addbyte(0xca); + addbyte(0x8b); /*MOV ECX, [RBX+RAX*2]*/ + addbyte(0x0c); + addbyte(0x43); + addbyte(0x8b); /*MOV EAX, [RBX-2]*/ + addbyte(0x43); + addbyte(-2); + addbyte(0x66); /*MOV AX, CX*/ + addbyte(0x89); + addbyte(0xc8); + } + else + { + addbyte(0x8a); /*MOV CL, [RDX]*/ + addbyte(0x0a); + addbyte(0x8a); /*MOV CH, [RBX]*/ + addbyte(0x2b); + addbyte(0x0f); /*MOVZX EDX,B[RDX+RAX]*/ + addbyte(0xb6); + addbyte(0x14); + addbyte(0x02); + addbyte(0x0f); /*MOVZX EAX,B[RBX+RAX]*/ + addbyte(0xb6); + addbyte(0x04); + addbyte(0x03); + addbyte(0x88); /*MOV DH, CL*/ + addbyte(0xce); + addbyte(0x88); /*MOV AH, CH*/ + addbyte(0xec); + } + } + + addbyte(0x49); /*MOV R8, bilinear_lookup*/ + addbyte(0xb8); + addquad(bilinear_lookup); + addbyte(0x4c); /*ADD RSI, R8*/ + addbyte(0x01); + addbyte(0xc6); + + switch (state->tformat) + { + case TEX_RGB332: + addbyte(0x49); /*MOV R8, rgb332*/ + addbyte(0xb8); + addquad(rgb332); + addbyte(0x0f); /*MOVZX ECX, AL*/ + addbyte(0xb6); + addbyte(0xc8); + addbyte(0x66); /*MOVD XMM0, [R8+RCX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x04); + addbyte(0x88); + addbyte(0x0f); /*MOVZX ECX, AH*/ + addbyte(0xb6); + addbyte(0xcc); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x66); /*MOVD XMM1, [R8+RCX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x88); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x0f); /*MOVZX ECX, DL*/ + addbyte(0xb6); + addbyte(0xca); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*MOVD XMM3, [R8+ECX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x1c); + addbyte(0x88); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x0f); /*MOVZX ECX, DH*/ + addbyte(0xb6); + addbyte(0xce); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, [R8+RCX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x88); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_Y4I2Q2: + addbyte(0x48); /*MOV RBP, state->palette[EDI]*/ + addbyte(0x8b); + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, palette)); + addbyte(0x0f); /*MOVZX ECX, AL*/ + addbyte(0xb6); + addbyte(0xc8); + addbyte(0x66); /*MOVD XMM0, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x44); + addbyte(0x8d); + addbyte(0); + addbyte(0x0f); /*MOVZX ECX, AH*/ + addbyte(0xb6); + addbyte(0xcc); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x66); /*MOVD XMM1, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x4c); + addbyte(0x8d); + addbyte(0); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x0f); /*MOVZX ECX, DL*/ + addbyte(0xb6); + addbyte(0xca); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*MOVD XMM3, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x5c); + addbyte(0x8d); + addbyte(0); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x0f); /*MOVZX ECX, DH*/ + addbyte(0xb6); + addbyte(0xce); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x4c); + addbyte(0x8d); + addbyte(0); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_A8: + addbyte(0x66); /*MOVZX CX, AH*/ + addbyte(0x0f); + addbyte(0xb6); + addbyte(0xcc); + addbyte(0x66); /*MOVZX AX, AL*/ + addbyte(0x0f); + addbyte(0xb6); + addbyte(0xc0); + addbyte(0x66); /*IMUL CX, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x66); /*IMUL AX, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0x06); + addbyte(0x66); /*MOVZX BX, DH*/ + addbyte(0x0f); + addbyte(0xb6); + addbyte(0xde); + addbyte(0x66); /*MOVZX DX, DL*/ + addbyte(0x0f); + addbyte(0xb6); + addbyte(0xd2); + addbyte(0x66); /*ADD AX, CX*/ + addbyte(0x01); + addbyte(0xc8); + addbyte(0x66); /*IMUL BX, bilinear_lookup[ESI]+0x30*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0x5e); + addbyte(0x30); + addbyte(0x66); /*IMUL DX, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0x56); + addbyte(0x20); + addbyte(0x66); /*ADD AX, BX*/ + addbyte(0x01); + addbyte(0xd8); + addbyte(0x66); /*ADD AX, DX*/ + addbyte(0x01); + addbyte(0xd0); + addbyte(0x88); /*MOV AL, AH*/ + addbyte(0xe0); + addbyte(0x66); /*MOV BX, AX*/ + addbyte(0x89); + addbyte(0xc3); + addbyte(0x0f); /*BSWAP EAX*/ + addbyte(0xc8); + addbyte(0x66); /*MOV AX, BX*/ + addbyte(0x89); + addbyte(0xd8); + break; + + case TEX_I8: + addbyte(0x66); /*MOVZX CX, AH*/ + addbyte(0x0f); + addbyte(0xb6); + addbyte(0xcc); + addbyte(0x66); /*MOVZX AX, AL*/ + addbyte(0x0f); + addbyte(0xb6); + addbyte(0xc0); + addbyte(0x66); /*IMUL CX, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x66); /*IMUL AX, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0x06); + addbyte(0x66); /*MOVZX BX, DH*/ + addbyte(0x0f); + addbyte(0xb6); + addbyte(0xde); + addbyte(0x66); /*MOVZX DX, DL*/ + addbyte(0x0f); + addbyte(0xb6); + addbyte(0xd2); + addbyte(0x66); /*ADD AX, CX*/ + addbyte(0x01); + addbyte(0xc8); + addbyte(0x66); /*IMUL BX, bilinear_lookup[ESI]+0x30*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0x5e); + addbyte(0x30); + addbyte(0x66); /*IMUL DX, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0x56); + addbyte(0x20); + addbyte(0x66); /*ADD AX, BX*/ + addbyte(0x01); + addbyte(0xd8); + addbyte(0x66); /*ADD AX, DX*/ + addbyte(0x01); + addbyte(0xd0); + addbyte(0x88); /*MOV AL, AH*/ + addbyte(0xe0); + addbyte(0xc1); /*SHL EAX, 8*/ + addbyte(0xe0); + addbyte(8); + addbyte(0x88); /*MOV AL, AH*/ + addbyte(0xe0); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_AI8: + addbyte(0x49); /*MOV R8, ai44*/ + addbyte(0xb8); + addquad(ai44); + addbyte(0x0f); /*MOVZX ECX, AL*/ + addbyte(0xb6); + addbyte(0xc8); + addbyte(0x66); /*MOVD XMM0, [R8+RCX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x04); + addbyte(0x88); + addbyte(0x0f); /*MOVZX ECX, AH*/ + addbyte(0xb6); + addbyte(0xcc); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x66); /*MOVD XMM1, [R8+RCX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x88); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x0f); /*MOVZX ECX, DL*/ + addbyte(0xb6); + addbyte(0xca); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*MOVD XMM3, [R8+ECX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x1c); + addbyte(0x88); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x0f); /*MOVZX ECX, DH*/ + addbyte(0xb6); + addbyte(0xce); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, [R8+RCX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x88); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + break; + + case TEX_PAL8: + addbyte(0x48); /*MOV RBP, state->palette[EDI]*/ + addbyte(0x8b); + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, palette)); + addbyte(0x0f); /*MOVZX ECX, AL*/ + addbyte(0xb6); + addbyte(0xc8); + addbyte(0x66); /*MOVD XMM0, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x44); + addbyte(0x8d); + addbyte(0); + addbyte(0x0f); /*MOVZX ECX, AH*/ + addbyte(0xb6); + addbyte(0xcc); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x66); /*MOVD XMM1, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x4c); + addbyte(0x8d); + addbyte(0); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x0f); /*MOVZX ECX, DL*/ + addbyte(0xb6); + addbyte(0xca); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*MOVD XMM3, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x5c); + addbyte(0x8d); + addbyte(0); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x0f); /*MOVZX ECX, DH*/ + addbyte(0xb6); + addbyte(0xce); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x4c); + addbyte(0x8d); + addbyte(0); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x30*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_R5G6B5: + addbyte(0x49); /*MOV R8, rgb565*/ + addbyte(0xb8); + addquad(rgb565); + addbyte(0x0f); /*MOVZX ECX, AX*/ + addbyte(0xb7); + addbyte(0xc8); + addbyte(0xc1); /*SHR EAX, 16*/ + addbyte(0xe8); + addbyte(16); + addbyte(0x66); /*MOVD XMM0, [R8+RCX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x04); + addbyte(0x88); + addbyte(0x66); /*MOVD XMM1, [R8+RAX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x80); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x0f); /*MOVZX ECX, DX*/ + addbyte(0xb7); + addbyte(0xca); + addbyte(0xc1); /*SHR EDX, 16*/ + addbyte(0xea); + addbyte(16); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*MOVD XMM3, [R8+RCX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x1c); + addbyte(0x88); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, [R8+EDX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x90); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x30*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_ARGB1555: + addbyte(0x49); /*MOV R8, argb1555*/ + addbyte(0xb8); + addquad(argb1555); + addbyte(0x0f); /*MOVZX ECX, AX*/ + addbyte(0xb7); + addbyte(0xc8); + addbyte(0xc1); /*SHR EAX, 16*/ + addbyte(0xe8); + addbyte(16); + addbyte(0x66); /*MOVD XMM0, [R8+RCX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x04); + addbyte(0x88); + addbyte(0x66); /*MOVD XMM1, [R8+RAX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x80); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x0f); /*MOVZX ECX, DX*/ + addbyte(0xb7); + addbyte(0xca); + addbyte(0xc1); /*SHR EDX, 16*/ + addbyte(0xea); + addbyte(16); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*MOVD XMM3, [R8+RCX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x1c); + addbyte(0x88); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, [R8+EDX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x90); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x30*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + break; + + case TEX_ARGB4444: + addbyte(0x49); /*MOV R8, argb4444*/ + addbyte(0xb8); + addquad(argb4444); + addbyte(0x0f); /*MOVZX ECX, AX*/ + addbyte(0xb7); + addbyte(0xc8); + addbyte(0xc1); /*SHR EAX, 16*/ + addbyte(0xe8); + addbyte(16); + addbyte(0x66); /*MOVD XMM0, [R8+RCX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x04); + addbyte(0x88); + addbyte(0x66); /*MOVD XMM1, [R8+RAX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x80); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x0f); /*MOVZX ECX, DX*/ + addbyte(0xb7); + addbyte(0xca); + addbyte(0xc1); /*SHR EDX, 16*/ + addbyte(0xea); + addbyte(16); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*MOVD XMM3, [R8+RCX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x1c); + addbyte(0x88); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, [R8+EDX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x90); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x30*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + break; + + case TEX_A8I8: + addbyte(0x49); /*MOV R8, ai88*/ + addbyte(0xb8); + addquad(ai88); + addbyte(0x0f); /*MOVZX ECX, AX*/ + addbyte(0xb7); + addbyte(0xc8); + addbyte(0xc1); /*SHR EAX, 16*/ + addbyte(0xe8); + addbyte(16); + addbyte(0x66); /*MOVD XMM0, [R8+RCX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x04); + addbyte(0x88); + addbyte(0x66); /*MOVD XMM1, [R8+RAX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x80); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x0f); /*MOVZX ECX, DX*/ + addbyte(0xb7); + addbyte(0xca); + addbyte(0xc1); /*SHR EDX, 16*/ + addbyte(0xea); + addbyte(16); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*MOVD XMM3, [R8+RCX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x1c); + addbyte(0x88); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, [R8+EDX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x90); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x30*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + break; + + case TEX_APAL88: + addbyte(0x48); /*MOV RBP, state->palette[EDI]*/ + addbyte(0x8b); + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, palette)); + addbyte(0x0f); /*MOVZX ECX, AL*/ + addbyte(0xb6); + addbyte(0xc8); + addbyte(0x66); /*MOVD XMM0, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x44); + addbyte(0x8d); + addbyte(0); + addbyte(0x0f); /*MOVZX ECX, AH*/ + addbyte(0xb6); + addbyte(0xcc); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0xc1); /*SHR EAX, 16*/ + addbyte(0xe8); + addbyte(16); + addbyte(0x66); /*PINSRW XMM0, ECX, 3*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0xc1); + addbyte(3); + addbyte(0x0f); /*MOVZX ECX, AL*/ + addbyte(0xb6); + addbyte(0xc8); + addbyte(0x0f); /*MOVZX EAX, AH*/ + addbyte(0xb6); + addbyte(0xc4); + addbyte(0x66); /*MOVD XMM1, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x4c); + addbyte(0x8d); + addbyte(0); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x0f); /*MOVZX ECX, DL*/ + addbyte(0xb6); + addbyte(0xca); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PINSRW XMM1, EAX, 3*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0xc8); + addbyte(3); + addbyte(0x66); /*MOVD XMM3, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x5c); + addbyte(0x8d); + addbyte(0); + addbyte(0x0f); /*MOVZX ECX, DH*/ + addbyte(0xb6); + addbyte(0xce); + addbyte(0xc1); /*SHR EDX, 16*/ + addbyte(0xea); + addbyte(16); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x66); /*PINSRW XMM3, ECX, 3*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0xd9); + addbyte(3); + addbyte(0x0f); /*MOVZX ECX, DL*/ + addbyte(0xb6); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x4c); + addbyte(0x8d); + addbyte(0); + addbyte(0x0f); /*MOVZX ECX, DH*/ + addbyte(0xb6); + addbyte(0xce); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PINSR1 XMM1, ECX, 3*/ + addbyte(0x0f); + addbyte(0xc4); + + addbyte(0xc9); + addbyte(3); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x30*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + break; + + default: + fatal("Unknown texture format %i\n", state->tformat); + } + + addbyte(0x4c); /*MOV RSI, R15*/ + addbyte(0x89); + addbyte(0xfe); + } + else + { + addbyte(0x8b); /*MOV ECX, state->lod[RDI]*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0x8a); /*MOV DL, params->tex_shift[RSI+RCX*4]*/ + addbyte(0x94); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_shift)); + addbyte(0x48); /*MOV RBP, state->tex[RDI+RCX*8]*/ + addbyte(0x8b); + addbyte(0xac); + addbyte(0xcf); + addlong(offsetof(voodoo_state_t, tex)); + addbyte(0x80); /*ADD CL, 4*/ + addbyte(0xc1); + addbyte(4); + addbyte(0x8b); /*MOV EAX, state->tex_s[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_s)); + addbyte(0x8b); /*MOV EBX, state->tex_t[EDI]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_t)); + addbyte(0xd3); /*SHR EAX, CL*/ + addbyte(0xe8); + addbyte(0xd3); /*SHR EBX, CL*/ + addbyte(0xeb); + if (state->clamp_s) + { + addbyte(0x85); /*TEST EAX, EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*CMOVS EAX, zero*/ + addbyte(0x48); + addbyte(0x04); + addbyte(0x25); + addlong(&zero); + addbyte(0x3b); /*CMP EAX, params->tex_w_mask[ESI+ECX*4]*/ + addbyte(0x84); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_w_mask) - 0x10); + addbyte(0x0f); /*CMOVAE EAX, params->tex_w_mask[ESI+ECX*4]*/ + addbyte(0x43); + addbyte(0x84); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_w_mask) - 0x10); + + } + else + { + addbyte(0x23); /*AND EAX, params->tex_w_mask-0x10[ESI+ECX*4]*/ + addbyte(0x84); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_w_mask) - 0x10); + } + if (state->clamp_t) + { + addbyte(0x85); /*TEST EBX, EBX*/ + addbyte(0xdb); + addbyte(0x0f); /*CMOVS EBX, zero*/ + addbyte(0x48); + addbyte(0x1c); + addbyte(0x25); + addlong(&zero); + addbyte(0x3b); /*CMP EBX, params->tex_h_mask[ESI+ECX*4]*/ + addbyte(0x9c); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_h_mask) - 0x10); + addbyte(0x0f); /*CMOVAE EBX, params->tex_h_mask[ESI+ECX*4]*/ + addbyte(0x43); + addbyte(0x9c); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_h_mask) - 0x10); + } + else + { + addbyte(0x23); /*AND EBX, params->tex_h_mask-0x10[ESI+ECX*4]*/ + addbyte(0x9c); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_h_mask) - 0x10); + } + addbyte(0x88); /*MOV CL, DL*/ + addbyte(0xd1); + addbyte(0xd3); /*SHL EBX, CL*/ + addbyte(0xe3); + addbyte(0x01); /*ADD EBX, EAX*/ + addbyte(0xc3); + + if (state->tformat & 8) + { + addbyte(0x0f); /*MOVZX EAX,W[EBP+EBX*2]*/ + addbyte(0xb7); + addbyte(0x44); + addbyte(0x5d); + addbyte(0); + } + else + { + addbyte(0x0f); /*MOVZX EAX,B[EBP+EBX]*/ + addbyte(0xb6); + addbyte(0x44); + addbyte(0x1d); + addbyte(0); + } + + switch (state->tformat) + { + case TEX_RGB332: + addbyte(0x49); /*MOV R8, rgb332*/ + addbyte(0xb8); + addquad(rgb332); + addbyte(0x41); /*MOV EAX, [R8+EAX*4]*/ + addbyte(0x8b); + addbyte(0x04); + addbyte(0x80); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_Y4I2Q2: + addbyte(0x48); /*MOV RBP, state->palette[EDI]*/ + addbyte(0x8b); + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, palette)); + addbyte(0x8b); /*MOV EAX, [EBP+EAX*4]*/ + addbyte(0x44); + addbyte(0x85); + addbyte(0); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_A8: + addbyte(0x88); /*MOV AH, AL*/ + addbyte(0xc4); + addbyte(0x66); /*MOV BX, AX*/ + addbyte(0x89); + addbyte(0xc3); + addbyte(0x0f); /*BSWAP EAX*/ + addbyte(0xc8); + addbyte(0x66); /*MOV AX, BX*/ + addbyte(0x89); + addbyte(0xd8); + break; + + case TEX_I8: + addbyte(0x88); /*MOV AH, AL*/ + addbyte(0xc4); + addbyte(0xc1); /*SHL EAX, 8*/ + addbyte(0xe0); + addbyte(8); + addbyte(0x88); /*MOV AL, AH*/ + addbyte(0xe0); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_AI8: + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + addbyte(0x83); /*AND EAX, 0x0f*/ + addbyte(0xe0); + addbyte(0x0f); + addbyte(0x81); /*AND EBX, 0xf0*/ + addbyte(0xe3); + addlong(0xf0); + addbyte(0x89); /*MOV ECX, EAX*/ + addbyte(0xc1); + addbyte(0x89); /*MOV EDX, EBX*/ + addbyte(0xda); + addbyte(0xc1); /*SHL ECX, 4*/ + addbyte(0xe1); + addbyte(4); + addbyte(0xc1); /*SHR EDX, 4*/ + addbyte(0xe2); + addbyte(4); + addbyte(0x09); /*OR EAX, ECX*/ + addbyte(0xc8); + addbyte(0x09); /*OR EBX, EDX*/ + addbyte(0xd3); + addbyte(0x88); /*MOV AH, AL*/ + addbyte(0xc4); + addbyte(0xc1); /*SHL EBX, 24*/ + addbyte(0xe3); + addbyte(24); + addbyte(0xc1); /*SHL EAX, 8*/ + addbyte(0xe0); + addbyte(8); + addbyte(0x88); /*MOV AL, AH*/ + addbyte(0xe0); + addbyte(0x09); /*OR EAX, EBX*/ + addbyte(0xd8); + break; + + case TEX_PAL8: + addbyte(0x48); /*MOV RBP, state->palette[EDI]*/ + addbyte(0x8b); + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, palette)); + addbyte(0x8b); /*MOV EAX, [EBP+EAX*4]*/ + addbyte(0x44); + addbyte(0x85); + addbyte(0); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_R5G6B5: + addbyte(0x49); /*MOV R8, rgb565*/ + addbyte(0xb8); + addquad(rgb565); + addbyte(0x41); /*MOV EAX, [R8+EAX*4]*/ + addbyte(0x8b); + addbyte(0x04); + addbyte(0x80); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_ARGB1555: + addbyte(0x49); /*MOV R8, argb1555*/ + addbyte(0xb8); + addquad(argb1555); + addbyte(0x41); /*MOV EAX, [R8+EAX*4]*/ + addbyte(0x8b); + addbyte(0x04); + addbyte(0x80); + break; + + case TEX_ARGB4444: + addbyte(0x49); /*MOV R8, argb4444*/ + addbyte(0xb8); + addquad(argb4444); + addbyte(0x41); /*MOV EAX, [R8+EAX*4]*/ + addbyte(0x8b); + addbyte(0x04); + addbyte(0x80); + break; + + case TEX_A8I8: + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + addbyte(0xc1); /*SHL EAX, 16*/ + addbyte(0xe0); + addbyte(16); + addbyte(0x88); /*MOV AL, BL*/ + addbyte(0xd8); + addbyte(0x88); /*MOV AH, BL*/ + addbyte(0xdc); + break; + + case TEX_APAL88: + addbyte(0x48); /*MOV RBP, state->palette[EDI]*/ + addbyte(0x8b); + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, palette)); + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + addbyte(0x25); /*AND EAX, 0x000000ff*/ + addlong(0x000000ff); + addbyte(0x8b); /*MOV EAX, [EBP+EAX*4]*/ + addbyte(0x44); + addbyte(0x85); + addbyte(0); + addbyte(0xc1); /*SHL EBX, 16*/ + addbyte(0xe3); + addbyte(16); + addbyte(0x81); /*AND EBX, 0xff000000*/ + addbyte(0xe3); + addlong(0xff000000); + addbyte(0x25); /*AND EAX, 0x00ffffff*/ + addlong(0x00ffffff); + addbyte(0x09); /*OR EAX, EBX*/ + addbyte(0xd8); + break; + + default: + fatal("Unknown texture format %i\n", state->tformat); + } + } + if ((params->fbzMode & FBZ_CHROMAKEY)) + { + addbyte(0x8b); /*MOV EBX, params->chromaKey[ESI]*/ + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, chromaKey)); + addbyte(0x31); /*XOR EBX, EAX*/ + addbyte(0xc3); + addbyte(0x81); /*AND EBX, 0xffffff*/ + addbyte(0xe3); + addlong(0xffffff); + addbyte(0x0f); /*JE skip*/ + addbyte(0x84); + chroma_skip_pos = block_pos; + addlong(0); + } + addbyte(0x66); /*MOVD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0); + addbyte(0xc1); /*SHR EAX, 24*/ + addbyte(0xe8); + addbyte(24); + addbyte(0x89); /*MOV state->tex_a[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_a)); + } + + + if (params->alphaMode & ((1 << 0) | (1 << 4))) + { + /*EBX = a_other*/ + switch (a_sel) + { + case A_SEL_ITER_A: + addbyte(0x8b); /*MOV EBX, state->ia*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, ia)); + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + addbyte(0xba); /*MOV EDX, 0xff*/ + addlong(0xff); + addbyte(0xc1); /*SAR EBX, 12*/ + addbyte(0xfb); + addbyte(12); + addbyte(0x0f); /*CMOVS EBX, EAX*/ + addbyte(0x48); + addbyte(0xd8); + addbyte(0x39); /*CMP EBX, EDX*/ + addbyte(0xd3); + addbyte(0x0f); /*CMOVA EBX, EDX*/ + addbyte(0x47); + addbyte(0xda); + break; + case A_SEL_TEX: + addbyte(0x8b); /*MOV EBX, state->tex_a*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); + break; + case A_SEL_COLOR1: + addbyte(0x0f); /*MOVZX EBX, params->color1+3*/ + addbyte(0xb6); + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, color1)+3); + break; + default: + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + break; + } + /*ECX = a_local*/ + switch (cca_localselect) + { + case CCA_LOCALSELECT_ITER_A: + if (a_sel == A_SEL_ITER_A) + { + addbyte(0x89); /*MOV ECX, EBX*/ + addbyte(0xd9); + } + else + { + addbyte(0x8b); /*MOV ECX, state->ia*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ia)); + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + addbyte(0xba); /*MOV EDX, 0xff*/ + addlong(0xff); + addbyte(0xc1);/*SAR ECX, 12*/ + addbyte(0xf9); + addbyte(12); + addbyte(0x0f); /*CMOVS ECX, EAX*/ + addbyte(0x48); + addbyte(0xc8); + addbyte(0x39); /*CMP ECX, EDX*/ + addbyte(0xd1); + addbyte(0x0f); /*CMOVA ECX, EDX*/ + addbyte(0x47); + addbyte(0xca); + } + break; + case CCA_LOCALSELECT_COLOR0: + addbyte(0x0f); /*MOVZX ECX, params->color0+3*/ + addbyte(0xb6); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, color0)+3); + break; + case CCA_LOCALSELECT_ITER_Z: + addbyte(0x8b); /*MOV ECX, state->z*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, z)); + if (a_sel != A_SEL_ITER_A) + { + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + addbyte(0xba); /*MOV EDX, 0xff*/ + addlong(0xff); + } + addbyte(0xc1);/*SAR ECX, 20*/ + addbyte(0xf9); + addbyte(20); + addbyte(0x0f); /*CMOVS ECX, EAX*/ + addbyte(0x48); + addbyte(0xc8); + addbyte(0x39); /*CMP ECX, EDX*/ + addbyte(0xd1); + addbyte(0x0f); /*CMOVA ECX, EDX*/ + addbyte(0x47); + addbyte(0xca); + break; + + default: + addbyte(0xb9); /*MOV ECX, 0xff*/ + addlong(0xff); + break; + } + + if (cca_zero_other) + { + addbyte(0x31); /*XOR EDX, EDX*/ + addbyte(0xd2); + } + else + { + addbyte(0x89); /*MOV EDX, EBX*/ + addbyte(0xda); + } + + if (cca_sub_clocal) + { + addbyte(0x29); /*SUB EDX, ECX*/ + addbyte(0xca); + } + } + + if (cc_sub_clocal || cc_mselect == 1 || cc_add == 1) + { + /*XMM1 = local*/ + if (!cc_localselect_override) + { + if (cc_localselect) + { + addbyte(0x66); /*MOVD XMM1, params->color0*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, color0)); + } + else + { + addbyte(0xf3); /*MOVDQU XMM1, ib*/ /* ir, ig and ib must be in same dqword!*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0x66); /*PSRAD XMM1, 12*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe1); + addbyte(12); + addbyte(0x66); /*PACKSSDW XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc9); + addbyte(0x66); /*PACKUSWB XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc9); + } + } + else + { + addbyte(0xf6); /*TEST state->tex_a, 0x80*/ + addbyte(0x87); + addbyte(0x23); + addlong(offsetof(voodoo_state_t, tex_a)); + addbyte(0x80); + addbyte(0x74);/*JZ !cc_localselect*/ + addbyte(8+2); + addbyte(0x66); /*MOVD XMM1, params->color0*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, color0)); + /*JMP +*/ + /*!cc_localselect:*/ + addbyte(0xf3); /*MOVDQU XMM1, ib*/ /* ir, ig and ib must be in same dqword!*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0x66); /*PSRAD XMM1, 12*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe1); + addbyte(12); + addbyte(0x66); /*PACKSSDW XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc9); + addbyte(0x66); /*PACKUSWB XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc9); + } + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + } + if (!cc_zero_other) + { + if (_rgb_sel == CC_LOCALSELECT_ITER_RGB) + { + addbyte(0xf3); /*MOVDQU XMM0, ib*/ /* ir, ig and ib must be in same dqword!*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0x66); /*PSRAD XMM0, 12*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe0); + addbyte(12); + addbyte(0x66); /*PACKSSDW XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + } + else if (_rgb_sel == CC_LOCALSELECT_TEX) + { +#if 0 + addbyte(0xf3); /*MOVDQU XMM0, state->tex_b*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_b)); + addbyte(0x66); /*PACKSSDW XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); +#endif + } + else if (_rgb_sel == CC_LOCALSELECT_COLOR1) + { + addbyte(0x66); /*MOVD XMM0, params->color1*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x86); + addlong(offsetof(voodoo_params_t, color1)); + } + else + { + /*MOVD XMM0, src_r*/ + } + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + if (cc_sub_clocal) + { + addbyte(0x66); /*PSUBW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xc1); + } + } + else + { + addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc0); + if (cc_sub_clocal) + { + addbyte(0x66); /*PSUBW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xc1); + } + } + + if (params->alphaMode & ((1 << 0) | (1 << 4))) + { + if (!(cca_mselect == 0 && cca_reverse_blend == 0)) + { + switch (cca_mselect) + { + case CCA_MSELECT_ALOCAL: + addbyte(0x89); /*MOV EAX, ECX*/ + addbyte(0xc8); + break; + case CCA_MSELECT_AOTHER: + addbyte(0x89); /*MOV EAX, EBX*/ + addbyte(0xd8); + break; + case CCA_MSELECT_ALOCAL2: + addbyte(0x89); /*MOV EAX, ECX*/ + addbyte(0xc8); + break; + case CCA_MSELECT_TEX: + addbyte(0x0f); /*MOVZX EAX, state->tex_a*/ + addbyte(0xb6); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_a)); + break; + + case CCA_MSELECT_ZERO: + default: + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + break; + } + if (!cca_reverse_blend) + { + addbyte(0x35); /*XOR EAX, 0xff*/ + addlong(0xff); + } + addbyte(0x83); /*ADD EAX, 1*/ + addbyte(0xc0); + addbyte(1); + addbyte(0x0f); /*IMUL EDX, EAX*/ + addbyte(0xaf); + addbyte(0xd0); + addbyte(0xc1); /*SHR EDX, 8*/ + addbyte(0xea); + addbyte(8); + } + } + + if ((params->alphaMode & ((1 << 0) | (1 << 4)))) + { + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + } + + if (!(cc_mselect == 0 && cc_reverse_blend == 0) && cc_mselect == CC_MSELECT_AOTHER) + { + /*Copy a_other to XMM3 before it gets modified*/ + addbyte(0x66); /*MOVD XMM3, EDX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xda); + addbyte(0xf2); /*PSHUFLW XMM3, XMM3, 0*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xdb); + addbyte(0x00); + } + + if (cca_add && (params->alphaMode & ((1 << 0) | (1 << 4)))) + { + addbyte(0x01); /*ADD EDX, ECX*/ + addbyte(0xca); + } + + if ((params->alphaMode & ((1 << 0) | (1 << 4)))) + { + addbyte(0x85); /*TEST EDX, EDX*/ + addbyte(0xd2); + addbyte(0x0f); /*CMOVS EDX, EAX*/ + addbyte(0x48); + addbyte(0xd0); + addbyte(0xb8); /*MOV EAX, 0xff*/ + addlong(0xff); + addbyte(0x81); /*CMP EDX, 0xff*/ + addbyte(0xfa); + addlong(0xff); + addbyte(0x0f); /*CMOVA EDX, EAX*/ + addbyte(0x47); + addbyte(0xd0); + if (cca_invert_output) + { + addbyte(0x81); /*XOR EDX, 0xff*/ + addbyte(0xf2); + addlong(0xff); + } + } + + if (!(cc_mselect == 0 && cc_reverse_blend == 0)) + { + switch (cc_mselect) + { + case CC_MSELECT_ZERO: + addbyte(0x66); /*PXOR XMM3, XMM3*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xdb); + break; + case CC_MSELECT_CLOCAL: + addbyte(0xf3); /*MOV XMM3, XMM1*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xd9); + break; + case CC_MSELECT_ALOCAL: + addbyte(0x66); /*MOVD XMM3, ECX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xd9); + addbyte(0xf2); /*PSHUFLW XMM3, XMM3, 0*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xdb); + addbyte(0x00); + break; + case CC_MSELECT_AOTHER: + /*Handled above*/ + break; + case CC_MSELECT_TEX: + addbyte(0x66); /*PINSRW XMM3, state->tex_a, 0*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); + addbyte(0); + addbyte(0x66); /*PINSRW XMM3, state->tex_a, 1*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); + addbyte(1); + addbyte(0x66); /*PINSRW XMM3, state->tex_a, 2*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); + addbyte(2); + break; + default: + addbyte(0x66); /*PXOR XMM3, XMM3*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xdb); + break; + } + addbyte(0xf3); /*MOV XMM4, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe0); + if (!cc_reverse_blend) + { + addbyte(0x66); /*PXOR XMM3, 0xff*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x1c); + addbyte(0x25); + addlong(&xmm_ff_w); + } + addbyte(0x66); /*PADDW XMM3, 1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x1c); + addbyte(0x25); + addlong(&xmm_01_w); + addbyte(0x66); /*PMULLW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xc3); + addbyte(0x66); /*PMULHW XMM4, XMM3*/ + addbyte(0x0f); + addbyte(0xe5); + addbyte(0xe3); + addbyte(0x66); /*PUNPCKLWD XMM0, XMM4*/ + addbyte(0x0f); + addbyte(0x61); + addbyte(0xc4); + addbyte(0x66); /*PSRLD XMM0, 8*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe0); + addbyte(8); + addbyte(0x66); /*PACKSSDW XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0); + } + + if (cc_add == 1) + { + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + } + + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + + if (cc_invert_output) + { + addbyte(0x66); /*PXOR XMM0, 0xff*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x04); + addbyte(0x25); + addlong(&xmm_ff_b); + } + + if (params->fogMode & FOG_ENABLE) + { + if (params->fogMode & FOG_CONSTANT) + { + addbyte(0x66); /*MOVD XMM3, params->fogColor[ESI]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, fogColor)); + addbyte(0x66); /*PADDUSB XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xdc); + addbyte(0xc3); + } + else + { + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + + if (!(params->fogMode & FOG_ADD)) + { + addbyte(0x66); /*MOVD XMM3, params->fogColor[ESI]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, fogColor)); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + } + else + { + addbyte(0x66); /*PXOR XMM3, XMM3*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xdb); + } + + if (!(params->fogMode & FOG_MULT)) + { + addbyte(0x66); /*PSUBW XMM3, XMM0*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xd8); + } + + /*Divide by 2 to prevent overflow on multiply*/ + addbyte(0x66); /*PSRAW XMM3, 1*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xe3); + addbyte(1); + + if (params->fogMode & FOG_Z) + { + addbyte(0x8b); /*MOV EAX, state->z[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, z)); + addbyte(0xc1); /*SHR EAX, 12*/ + addbyte(0xe8); + addbyte(12); + addbyte(0x25); /*AND EAX, 0xff*/ + addlong(0xff); + } + else if (params->fogMode & FOG_ALPHA) + { + addbyte(0x8b); /*MOV EAX, state->ia[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, ia)); + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + addbyte(0xc1); /*SAR EAX, 12*/ + addbyte(0xf8); + addbyte(12); + addbyte(0x0f); /*CMOVS EAX, EBX*/ + addbyte(0x48); + addbyte(0xc3); + addbyte(0xbb); /*MOV EBX, 0xff*/ + addlong(0xff); + addbyte(0x3d); /*CMP EAX, 0xff*/ + addlong(0xff); + addbyte(0x0f); /*CMOVAE EAX, EBX*/ + addbyte(0x43); + addbyte(0xc3); + } + else + { + addbyte(0x8b); /*MOV EBX, state->w_depth[EDI]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, w_depth)); + addbyte(0x89); /*MOV EAX, EBX*/ + addbyte(0xd8); + addbyte(0xc1); /*SHR EBX, 10*/ + addbyte(0xeb); + addbyte(10); + addbyte(0xc1); /*SHR EAX, 2*/ + addbyte(0xe8); + addbyte(2); + addbyte(0x83); /*AND EBX, 0x3f*/ + addbyte(0xe3); + addbyte(0x3f); + addbyte(0x25); /*AND EAX, 0xff*/ + addlong(0xff); + addbyte(0xf6); /*MUL params->fogTable+1[ESI+EBX*2]*/ + addbyte(0xa4); + addbyte(0x5e); + addlong(offsetof(voodoo_params_t, fogTable)+1); + addbyte(0x0f); /*MOVZX EBX, params->fogTable[ESI+EBX*2]*/ + addbyte(0xb6); + addbyte(0x9c); + addbyte(0x5e); + addlong(offsetof(voodoo_params_t, fogTable)); + addbyte(0xc1); /*SHR EAX, 10*/ + addbyte(0xe8); + addbyte(10); + addbyte(0x01); /*ADD EAX, EBX*/ + addbyte(0xd8); + } + addbyte(0x01); /*ADD EAX, EAX*/ + addbyte(0xc0); + + addbyte(0x66); /*PMULLW XMM3, alookup+4[EAX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x1c); + addbyte(0xc5); + addlong(((uintptr_t)alookup) + 16); + addbyte(0x66); /*PSRAW XMM3, 7*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xe3); + addbyte(7); + + if (params->fogMode & FOG_MULT) + { + addbyte(0xf3); /*MOV XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc3); + } + else + { + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + } + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + } + } + + if ((params->alphaMode & 1) && (alpha_func != AFUNC_NEVER) && (alpha_func != AFUNC_ALWAYS)) + { + addbyte(0x0f); /*MOVZX ECX, params->alphaMode+3*/ + addbyte(0xb6); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, alphaMode) + 3); + addbyte(0x39); /*CMP EDX, ECX*/ + addbyte(0xca); + + switch (alpha_func) + { + case AFUNC_LESSTHAN: + addbyte(0x0f); /*JAE skip*/ + addbyte(0x83); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_EQUAL: + addbyte(0x0f); /*JNE skip*/ + addbyte(0x85); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_LESSTHANEQUAL: + addbyte(0x0f); /*JA skip*/ + addbyte(0x87); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_GREATERTHAN: + addbyte(0x0f); /*JBE skip*/ + addbyte(0x86); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_NOTEQUAL: + addbyte(0x0f); /*JE skip*/ + addbyte(0x84); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_GREATERTHANEQUAL: + addbyte(0x0f); /*JB skip*/ + addbyte(0x82); + a_skip_pos = block_pos; + addlong(0); + break; + } + } + else if ((params->alphaMode & 1) && (alpha_func == AFUNC_NEVER)) + { + addbyte(0xC3); /*RET*/ + } + + if (params->alphaMode & (1 << 4)) + { + addbyte(0x49); /*MOV R8, rgb565*/ + addbyte(0xb8); + addquad(rgb565); + addbyte(0x8b); /*MOV EAX, state->x[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x)); + addbyte(0x48); /*MOV RBP, fb_mem*/ + addbyte(0x8b); + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, fb_mem)); + addbyte(0x01); /*ADD EDX, EDX*/ + addbyte(0xd2); + addbyte(0x0f); /*MOVZX EAX, [RBP+RAX*2]*/ + addbyte(0xb7); + addbyte(0x44); + addbyte(0x45); + addbyte(0); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x66); /*MOVD XMM4, rgb565[EAX*4]*/ + addbyte(0x41); + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x24); + addbyte(0x80); + addbyte(0x66); /*PUNPCKLBW XMM4, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xe2); + addbyte(0xf3); /*MOV XMM6, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xf4); + + switch (dest_afunc) + { + case AFUNC_AZERO: + addbyte(0x66); /*PXOR XMM4, XMM4*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xe4); + break; + case AFUNC_ASRC_ALPHA: + addbyte(0x66); /*PMULLW XMM4, alookup[EDX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x24); + addbyte(0xd5); + addlong(alookup); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x24); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + break; + case AFUNC_A_COLOR: + addbyte(0x66); /*PMULLW XMM4, XMM0*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xe0); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x24); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + break; + case AFUNC_ADST_ALPHA: + break; + case AFUNC_AONE: + break; + case AFUNC_AOMSRC_ALPHA: + addbyte(0x66); /*PMULLW XMM4, aminuslookup[EDX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x24); + addbyte(0xd5); + addlong(aminuslookup); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x24); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + break; + case AFUNC_AOM_COLOR: + addbyte(0xf3); /*MOVQ XMM5, xmm_ff_w*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x2c); + addbyte(0x25); + addlong(&xmm_ff_w); + addbyte(0x66); /*PSUBW XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xe8); + addbyte(0x66); /*PMULLW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xe5); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x24); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + break; + case AFUNC_AOMDST_ALPHA: + addbyte(0x66); /*PXOR XMM4, XMM4*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xe4); + break; + case AFUNC_ASATURATE: + addbyte(0x66); /*PMULLW XMM4, minus_254*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x24); + addbyte(0xd5); + addlong(&minus_254); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x24); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + } + + switch (src_afunc) + { + case AFUNC_AZERO: + addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc0); + break; + case AFUNC_ASRC_ALPHA: + addbyte(0x66); /*PMULLW XMM0, alookup[EDX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x04); + addbyte(0xd5); + addlong(alookup); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + break; + case AFUNC_A_COLOR: + addbyte(0x66); /*PMULLW XMM0, XMM6*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xc6); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + break; + case AFUNC_ADST_ALPHA: + break; + case AFUNC_AONE: + break; + case AFUNC_AOMSRC_ALPHA: + addbyte(0x66); /*PMULLW XMM0, aminuslookup[EDX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x04); + addbyte(0xd5); + addlong(aminuslookup); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + break; + case AFUNC_AOM_COLOR: + addbyte(0xf3); /*MOVQ XMM5, xmm_ff_w*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x2c); + addbyte(0x25); + addlong(&xmm_ff_w); + addbyte(0x66); /*PSUBW XMM5, XMM6*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xee); + addbyte(0x66); /*PMULLW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xc5); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x04); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + break; + case AFUNC_AOMDST_ALPHA: + addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc0); + break; + case AFUNC_ACOLORBEFOREFOG: + break; + } + + addbyte(0x66); /*PADDW XMM0, XMM4*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc4); + + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + } + + addbyte(0x8b); /*MOV EDX, state->x[EDI]*/ + addbyte(0x97); + addlong(offsetof(voodoo_state_t, x)); + + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + + if (params->fbzMode & FBZ_RGB_WMASK) + { + if (dither) + { + addbyte(0x49); /*MOV R8, dither_rb*/ + addbyte(0xb8); + addquad(dither2x2 ? dither_rb2x2 : dither_rb); + addbyte(0x4c); /*MOV ESI, real_y (R14)*/ + addbyte(0x89); + addbyte(0xf6); + addbyte(0x0f); /*MOVZX EBX, AH*/ /*G*/ + addbyte(0xb6); + addbyte(0xdc); + if (dither2x2) + { + addbyte(0x83); /*AND EDX, 1*/ + addbyte(0xe2); + addbyte(1); + addbyte(0x83); /*AND ESI, 1*/ + addbyte(0xe6); + addbyte(1); + addbyte(0xc1); /*SHL EBX, 2*/ + addbyte(0xe3); + addbyte(2); + } + else + { + addbyte(0x83); /*AND EDX, 3*/ + addbyte(0xe2); + addbyte(3); + addbyte(0x83); /*AND ESI, 3*/ + addbyte(0xe6); + addbyte(3); + addbyte(0xc1); /*SHL EBX, 4*/ + addbyte(0xe3); + addbyte(4); + } + addbyte(0x0f); /*MOVZX ECX, AL*/ /*R*/ + addbyte(0xb6); + addbyte(0xc8); + if (dither2x2) + { + addbyte(0xc1); /*SHR EAX, 14*/ + addbyte(0xe8); + addbyte(14); + addbyte(0x8d); /*LEA ESI, RDX+RSI*2*/ + addbyte(0x34); + addbyte(0x72); + } + else + { + addbyte(0xc1); /*SHR EAX, 12*/ + addbyte(0xe8); + addbyte(12); + addbyte(0x8d); /*LEA ESI, RDX+RSI*4*/ + addbyte(0x34); + addbyte(0xb2); + } + addbyte(0x8b); /*MOV EDX, state->x[EDI]*/ + addbyte(0x97); + addlong(offsetof(voodoo_state_t, x)); + addbyte(0x4c); /*ADD RSI, R8*/ + addbyte(0x01); + addbyte(0xc6); + if (dither2x2) + { + addbyte(0xc1); /*SHL ECX, 2*/ + addbyte(0xe1); + addbyte(2); + addbyte(0x25); /*AND EAX, 0x3fc*/ /*B*/ + addlong(0x3fc); + } + else + { + addbyte(0xc1); /*SHL ECX, 4*/ + addbyte(0xe1); + addbyte(4); + addbyte(0x25); /*AND EAX, 0xff0*/ /*B*/ + addlong(0xff0); + } + addbyte(0x0f); /*MOVZX EBX, dither_g[EBX+ESI]*/ + addbyte(0xb6); + addbyte(0x9c); + addbyte(0x1e); + addlong(dither2x2 ? ((uintptr_t)dither_g2x2 - (uintptr_t)dither_rb2x2) : ((uintptr_t)dither_g - (uintptr_t)dither_rb)); + addbyte(0x0f); /*MOVZX ECX, dither_rb[RCX+RSI]*/ + addbyte(0xb6); + addbyte(0x0c); + addbyte(0x0e); + addbyte(0x0f); /*MOVZX EAX, dither_rb[RAX+RSI]*/ + addbyte(0xb6); + addbyte(0x04); + addbyte(0x06); + addbyte(0xc1); /*SHL EBX, 5*/ + addbyte(0xe3); + addbyte(5); + addbyte(0xc1); /*SHL EAX, 11*/ + addbyte(0xe0); + addbyte(11); + addbyte(0x09); /*OR EAX, EBX*/ + addbyte(0xd8); + addbyte(0x09); /*OR EAX, ECX*/ + addbyte(0xc8); + } + else + { + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + addbyte(0x0f); /*MOVZX ECX, AH*/ + addbyte(0xb6); + addbyte(0xcc); + addbyte(0xc1); /*SHR EAX, 3*/ + addbyte(0xe8); + addbyte(3); + addbyte(0xc1); /*SHR EBX, 8*/ + addbyte(0xeb); + addbyte(8); + addbyte(0xc1); /*SHL ECX, 3*/ + addbyte(0xe1); + addbyte(3); + addbyte(0x81); /*AND EAX, 0x001f*/ + addbyte(0xe0); + addlong(0x001f); + addbyte(0x81); /*AND EBX, 0xf800*/ + addbyte(0xe3); + addlong(0xf800); + addbyte(0x81); /*AND ECX, 0x07e0*/ + addbyte(0xe1); + addlong(0x07e0); + addbyte(0x09); /*OR EAX, EBX*/ + addbyte(0xd8); + addbyte(0x09); /*OR EAX, ECX*/ + addbyte(0xc8); + } + addbyte(0x48); /*MOV RSI, fb_mem*/ + addbyte(0x8b); + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, fb_mem)); + addbyte(0x66); /*MOV [ESI+EDX*2], AX*/ + addbyte(0x89); + addbyte(0x04); + addbyte(0x56); + } + + if (params->fbzMode & FBZ_DEPTH_WMASK) + { + addbyte(0x66); /*MOV AX, new_depth*/ + addbyte(0x8b); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, new_depth)); + addbyte(0x48); /*MOV RSI, aux_mem*/ + addbyte(0x8b); + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, aux_mem)); + addbyte(0x66); /*MOV [ESI+EDX*2], AX*/ + addbyte(0x89); + addbyte(0x04); + addbyte(0x56); + } + + if (z_skip_pos) + *(uint32_t *)&code_block[z_skip_pos] = (block_pos - z_skip_pos) - 4; + if (a_skip_pos) + *(uint32_t *)&code_block[a_skip_pos] = (block_pos - a_skip_pos) - 4; + if (chroma_skip_pos) + *(uint32_t *)&code_block[chroma_skip_pos] = (block_pos - chroma_skip_pos) - 4; + + addbyte(0x4c); /*MOV RSI, R15*/ + addbyte(0x89); + addbyte(0xfe); + + addbyte(0xf3); /*MOVDQU XMM1, state->ib[EDI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0xf3); /*MOVDQU XMM3, state->tmu0_s[EDI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tmu0_s)); + addbyte(0xf3); /*MOVQ XMM4, state->tmu0_w[EDI]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, tmu0_w)); + addbyte(0xf3); /*MOVDQU XMM0, params->dBdX[ESI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x86); + addlong(offsetof(voodoo_params_t, dBdX)); + addbyte(0x8b); /*MOV EAX, params->dZdX[ESI]*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, dZdX)); + addbyte(0xf3); /*MOVDQU XMM5, params->tmu[0].dSdX[ESI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0xae); + addlong(offsetof(voodoo_params_t, tmu[0].dSdX)); + addbyte(0xf3); /*MOVQ XMM6, params->tmu[0].dWdX[ESI]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xb6); + addlong(offsetof(voodoo_params_t, tmu[0].dWdX)); + + if (state->xdir > 0) + { + addbyte(0x66); /*PADDD XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0xfe); + addbyte(0xc8); + } + else + { + addbyte(0x66); /*PSUBD XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0xfa); + addbyte(0xc8); + } + + addbyte(0xf3); /*MOVQ XMM0, state->w*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w)); + addbyte(0xf3); /*MOVDQU state->ib, XMM1*/ + addbyte(0x0f); + addbyte(0x7f); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0xf3); /*MOVQ XMM7, params->dWdX*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xbe); + addlong(offsetof(voodoo_params_t, dWdX)); + + if (state->xdir > 0) + { + addbyte(0x66); /*PADDQ XMM3, XMM5*/ + addbyte(0x0f); + addbyte(0xd4); + addbyte(0xdd); + addbyte(0x66); /*PADDQ XMM4, XMM6*/ + addbyte(0x0f); + addbyte(0xd4); + addbyte(0xe6); + addbyte(0x66); /*PADDQ XMM0, XMM7*/ + addbyte(0x0f); + addbyte(0xd4); + addbyte(0xc7); + addbyte(0x01); /*ADD state->z[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, z)); + } + else + { + addbyte(0x66); /*PSUBQ XMM3, XMM5*/ + addbyte(0x0f); + addbyte(0xfb); + addbyte(0xdd); + addbyte(0x66); /*PSUBQ XMM4, XMM6*/ + addbyte(0x0f); + addbyte(0xfb); + addbyte(0xe6); + addbyte(0x66); /*PSUBQ XMM0, XMM7*/ + addbyte(0x0f); + addbyte(0xfb); + addbyte(0xc7); + addbyte(0x29); /*SUB state->z[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, z)); + } + + addbyte(0xf3); /*MOVDQU state->tmu0_s, XMM3*/ + addbyte(0x0f); + addbyte(0x7f); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tmu0_s)); + addbyte(0x66); /*MOVQ state->tmu0_w, XMM4*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, tmu0_w)); + addbyte(0x66); /*MOVQ state->w, XMM0*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w)); + + addbyte(0x83); /*ADD state->pixel_count[EDI], 1*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, pixel_count)); + addbyte(1); + + addbyte(0x8b); /*MOV EAX, state->x[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x)); + + if (state->xdir > 0) + { + addbyte(0x83); /*ADD state->x[EDI], 1*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x)); + addbyte(1); + } + else + { + addbyte(0x83); /*SUB state->x[EDI], 1*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, x)); + addbyte(1); + } + + addbyte(0x3b); /*CMP EAX, state->x2[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x2)); + addbyte(0x0f); /*JNZ loop_jump_pos*/ + addbyte(0x85); + addlong(loop_jump_pos - (block_pos + 4)); + + addbyte(0x41); /*POP R15*/ + addbyte(0x5f); + addbyte(0x41); /*POP R14*/ + addbyte(0x5e); + addbyte(0x5b); /*POP RBX*/ + addbyte(0x5e); /*POP RSI*/ + addbyte(0x5f); /*POP RDI*/ + addbyte(0x5d); /*POP RBP*/ + + addbyte(0xC3); /*RET*/ +} +static int voodoo_recomp = 0; +static inline void *voodoo_get_block(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int odd_even) +{ + int c; + int b = last_block[odd_even]; + voodoo_x86_data_t *voodoo_x86_data = voodoo->codegen_data; + voodoo_x86_data_t *data; + + for (c = 0; c < 8; c++) + { + data = &voodoo_x86_data[odd_even + c*2]; //&voodoo_x86_data[odd_even][b]; + + if (state->xdir == data->xdir && + params->alphaMode == data->alphaMode && + params->fbzMode == data->fbzMode && + params->fogMode == data->fogMode && + params->fbzColorPath == data->fbzColorPath && + (voodoo->trexInit1 & (1 << 18)) == data->trexInit1 && + params->textureMode == data->textureMode) + { + last_block[odd_even] = b; + return data->code_block; + } + + b = (b + 1) & 7; + } +voodoo_recomp++; + data = &voodoo_x86_data[odd_even + next_block_to_write[odd_even]*2]; +// code_block = data->code_block; + + voodoo_generate(data->code_block, voodoo, params, state, depth_op); + + data->xdir = state->xdir; + data->alphaMode = params->alphaMode; + data->fbzMode = params->fbzMode; + data->fogMode = params->fogMode; + data->fbzColorPath = params->fbzColorPath; + data->trexInit1 = voodoo->trexInit1 & (1 << 18); + data->textureMode = params->textureMode; + + next_block_to_write[odd_even] = (next_block_to_write[odd_even] + 1) & 7; + + return data->code_block; +} + +static void voodoo_codegen_init(voodoo_t *voodoo) +{ + int c; +#ifdef __linux__ + void *start; + size_t len; + long pagesize = sysconf(_SC_PAGESIZE); + long pagemask = ~(pagesize - 1); +#endif + +#if WIN64 + voodoo->codegen_data = VirtualAlloc(NULL, sizeof(voodoo_x86_data_t) * BLOCK_NUM * 2, MEM_COMMIT, PAGE_EXECUTE_READWRITE); +#else + voodoo->codegen_data = malloc(sizeof(voodoo_x86_data_t) * BLOCK_NUM * 2); +#endif + +#ifdef __linux__ + start = (void *)((long)voodoo->codegen_data & pagemask); + len = ((sizeof(voodoo_x86_data_t) * BLOCK_NUM * 2) + pagesize) & pagemask; + if (mprotect(start, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) + { + perror("mprotect"); + exit(-1); + } +#endif + + for (c = 0; c < 256; c++) + { + int d[4]; + int _ds = c & 0xf; + int dt = c >> 4; + + alookup[c] = _mm_set_epi32(0, 0, c | (c << 16), c | (c << 16)); + aminuslookup[c] = _mm_set_epi32(0, 0, (255-c) | ((255-c) << 16), (255-c) | ((255-c) << 16)); + + d[0] = (16 - _ds) * (16 - dt); + d[1] = _ds * (16 - dt); + d[2] = (16 - _ds) * dt; + d[3] = _ds * dt; + + bilinear_lookup[c*4] = _mm_set_epi32(0, 0, d[0] | (d[0] << 16), d[0] | (d[0] << 16)); + bilinear_lookup[c*4 + 1] = _mm_set_epi32(0, 0, d[1] | (d[1] << 16), d[1] | (d[1] << 16)); + bilinear_lookup[c*4 + 2] = _mm_set_epi32(0, 0, d[2] | (d[2] << 16), d[2] | (d[2] << 16)); + bilinear_lookup[c*4 + 3] = _mm_set_epi32(0, 0, d[3] | (d[3] << 16), d[3] | (d[3] << 16)); + } + alookup[256] = _mm_set_epi32(0, 0, 256 | (256 << 16), 256 | (256 << 16)); +} + +static void voodoo_codegen_close(voodoo_t *voodoo) +{ +#if WIN64 + VirtualFree(voodoo->codegen_data, 0, MEM_RELEASE); +#else + free(voodoo->codegen_data); +#endif +} + diff --git a/src/vid_voodoo_codegen_x86.h b/src/vid_voodoo_codegen_x86.h new file mode 100644 index 000000000..40d1503a7 --- /dev/null +++ b/src/vid_voodoo_codegen_x86.h @@ -0,0 +1,3725 @@ +/*Registers : + + alphaMode + fbzMode & 0x1f3fff + fbzColorPath +*/ + +#ifdef __linux__ +#include +#include +#endif +#if defined WIN32 || defined _WIN32 || defined _WIN32 +#define BITMAP windows_BITMAP +#include +#undef BITMAP +#endif + +#include + +#define BLOCK_NUM 8 +#define BLOCK_MASK (BLOCK_NUM-1) +#define BLOCK_SIZE 8192 + +typedef struct voodoo_x86_data_t +{ + uint8_t code_block[BLOCK_SIZE]; + int xdir; + uint32_t alphaMode; + uint32_t fbzMode; + uint32_t fogMode; + uint32_t fbzColorPath; + uint32_t textureMode; + uint32_t trexInit1; +} voodoo_x86_data_t; + +static int last_block[2] = {0, 0}; +static int next_block_to_write[2] = {0, 0}; + +#define addbyte(val) \ + code_block[block_pos++] = val; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n") + +#define addword(val) \ + *(uint16_t *)&code_block[block_pos] = val; \ + block_pos += 2; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n") + +#define addlong(val) \ + *(uint32_t *)&code_block[block_pos] = val; \ + block_pos += 4; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n") + +#define addquad(val) \ + *(uint64_t *)&code_block[block_pos] = val; \ + block_pos += 8; \ + if (block_pos >= BLOCK_SIZE) \ + fatal("Over!\n") + + +static __m128i xmm_01_w;// = 0x0001000100010001ull; +static __m128i xmm_ff_w;// = 0x00ff00ff00ff00ffull; +static __m128i xmm_ff_b;// = 0x00000000ffffffffull; + +static uint32_t zero = 0; +static double const_1_48 = (double)(1ull << 4); + +static __m128i alookup[257], aminuslookup[256]; +static __m128i minus_254;// = 0xff02ff02ff02ff02ull; +static __m128i bilinear_lookup[256*4]; + +static inline void voodoo_generate(uint8_t *code_block, voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int depthop) +{ + int block_pos = 0; + int z_skip_pos = 0; + int a_skip_pos = 0; + int chroma_skip_pos = 0; + int depth_jump_pos = 0; + int depth_jump_pos2 = 0; + int loop_jump_pos = 0; +// xmm_01_w = (__m128i)0x0001000100010001ull; +// xmm_ff_w = (__m128i)0x00ff00ff00ff00ffull; +// xmm_ff_b = (__m128i)0x00000000ffffffffull; + xmm_01_w = _mm_set_epi32(0, 0, 0x00010001, 0x00010001); + xmm_ff_w = _mm_set_epi32(0, 0, 0x00ff00ff, 0x00ff00ff); + xmm_ff_b = _mm_set_epi32(0, 0, 0, 0x00ffffff); + minus_254 = _mm_set_epi32(0, 0, 0xff02ff02, 0xff02ff02); +// *(uint64_t *)&const_1_48 = 0x45b0000000000000ull; +// block_pos = 0; +// voodoo_get_depth = &code_block[block_pos]; + /*W at (%esp+4) + Z at (%esp+12) + new_depth at (%esp+16)*/ +// if ((params->fbzMode & FBZ_DEPTH_ENABLE) && (depth_op == DEPTHOP_NEVER)) +// { +// addbyte(0xC3); /*RET*/ +// return; +// } + addbyte(0x55); /*PUSH EBP*/ + addbyte(0x57); /*PUSH EDI*/ + addbyte(0x56); /*PUSH ESI*/ + addbyte(0x53); /*PUSH EBX*/ + + addbyte(0x8b); /*MOV EDI, [ESP+4]*/ + addbyte(0x7c); + addbyte(0x24); + addbyte(4+16); + loop_jump_pos = block_pos; + addbyte(0x8b); /*MOV ESI, [ESP+8]*/ + addbyte(0x74); + addbyte(0x24); + addbyte(8+16); + addbyte(0x66); /*PXOR XMM2, XMM2*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xd2); + + if ((params->fbzMode & FBZ_W_BUFFER) || (params->fogMode & (FOG_ENABLE|FOG_CONSTANT|FOG_Z|FOG_ALPHA)) == FOG_ENABLE) + { + addbyte(0xb8); /*MOV new_depth, 0*/ + addlong(0); + addbyte(0x66); /*TEST w+4, 0xffff*/ + addbyte(0xf7); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w)+4); + addword(0xffff); + addbyte(0x75); /*JNZ got_depth*/ + depth_jump_pos = block_pos; + addbyte(0); +// addbyte(4+5+2+3+2+5+5+3+2+2+2+/*3+*/3+2+6+4+5+2+3); + addbyte(0x8b); /*MOV EDX, w*/ + addbyte(0x97); + addlong(offsetof(voodoo_state_t, w)); + addbyte(0xb8); /*MOV new_depth, 0xf001*/ + addlong(0xf001); + addbyte(0x89); /*MOV EBX, EDX*/ + addbyte(0xd3); + addbyte(0xc1); /*SHR EDX, 16*/ + addbyte(0xea); + addbyte(16); + addbyte(0x74); /*JZ got_depth*/ + depth_jump_pos2 = block_pos; + addbyte(0); +// addbyte(5+5+3+2+2+2+/*3+*/3+2+6+4+5+2+3); + addbyte(0xb9); /*MOV ECX, 19*/ + addlong(19); + addbyte(0x0f); /*BSR EAX, EDX*/ + addbyte(0xbd); + addbyte(0xc2); + addbyte(0xba); /*MOV EDX, 15*/ + addlong(15); + addbyte(0xf7); /*NOT EBX*/ + addbyte(0xd3); + addbyte(0x29); /*SUB EDX, EAX - EDX = exp*/ + addbyte(0xc2); + addbyte(0x29); /*SUB ECX, EDX*/ + addbyte(0xd1); + addbyte(0xc1); /*SHL EDX, 12*/ + addbyte(0xe2); + addbyte(12); + addbyte(0xd3); /*SHR EBX, CL*/ + addbyte(0xeb); + addbyte(0x81); /*AND EBX, 0xfff - EBX = mant*/ + addbyte(0xe3); + addlong(0xfff); + addbyte(0x8d); /*LEA EAX, 1[EDX, EBX]*/ + addbyte(0x44); + addbyte(0x13); + addbyte(1); + addbyte(0xbb); /*MOV EBX, 0xffff*/ + addlong(0xffff); + addbyte(0x39); /*CMP EAX, EBX*/ + addbyte(0xd8); + addbyte(0x0f); /*CMOVA EAX, EBX*/ + addbyte(0x47); + addbyte(0xc3); + + if (depth_jump_pos) + *(uint8_t *)&code_block[depth_jump_pos] = (block_pos - depth_jump_pos) - 1; + if (depth_jump_pos) + *(uint8_t *)&code_block[depth_jump_pos2] = (block_pos - depth_jump_pos2) - 1; + + if ((params->fogMode & (FOG_ENABLE|FOG_CONSTANT|FOG_Z|FOG_ALPHA)) == FOG_ENABLE) + { + addbyte(0x89); /*MOV state->w_depth[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w_depth)); + } + } + if (!(params->fbzMode & FBZ_W_BUFFER)) + { + addbyte(0x8b); /*MOV EAX, z*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, z)); + addbyte(0xbb); /*MOV EBX, 0xffff*/ + addlong(0xffff); + addbyte(0x31); /*XOR ECX, ECX*/ + addbyte(0xc9); + addbyte(0xc1); /*SAR EAX, 12*/ + addbyte(0xf8); + addbyte(12); + addbyte(0x0f); /*CMOVS EAX, ECX*/ + addbyte(0x48); + addbyte(0xc1); + addbyte(0x39); /*CMP EAX, EBX*/ + addbyte(0xd8); + addbyte(0x0f); /*CMOVA EAX, EBX*/ + addbyte(0x47); + addbyte(0xc3); + } + + if (params->fbzMode & FBZ_DEPTH_BIAS) + { + addbyte(0x03); /*ADD EAX, params->zaColor[ESI]*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, zaColor)); + addbyte(0x25); /*AND EAX, 0xffff*/ + addlong(0xffff); + } + + addbyte(0x89); /*MOV state->new_depth[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, new_depth)); + + if ((params->fbzMode & FBZ_DEPTH_ENABLE) && (depthop != DEPTHOP_ALWAYS) && (depthop != DEPTHOP_NEVER)) + { + addbyte(0x8b); /*MOV EBX, state->x[EDI]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, x)); + addbyte(0x8b);/*MOV ECX, aux_mem[EDI]*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, aux_mem)); + addbyte(0x0f); /*MOVZX EBX, [ECX+EBX*2]*/ + addbyte(0xb7); + addbyte(0x1c); + addbyte(0x59); + addbyte(0x39); /*CMP EAX, EBX*/ + addbyte(0xd8); + if (depthop == DEPTHOP_LESSTHAN) + { + addbyte(0x0f); /*JAE skip*/ + addbyte(0x83); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_EQUAL) + { + addbyte(0x0f); /*JNE skip*/ + addbyte(0x85); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_LESSTHANEQUAL) + { + addbyte(0x0f); /*JA skip*/ + addbyte(0x87); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_GREATERTHAN) + { + addbyte(0x0f); /*JBE skip*/ + addbyte(0x86); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_NOTEQUAL) + { + addbyte(0x0f); /*JE skip*/ + addbyte(0x84); + z_skip_pos = block_pos; + addlong(0); + } + else if (depthop == DEPTHOP_GREATERTHANEQUAL) + { + addbyte(0x0f); /*JB skip*/ + addbyte(0x82); + z_skip_pos = block_pos; + addlong(0); + } + else + fatal("Bad depth_op\n"); + } + else if ((params->fbzMode & FBZ_DEPTH_ENABLE) && (depthop == DEPTHOP_NEVER)) + { + addbyte(0xC3); /*RET*/ +// addbyte(0x30); /*XOR EAX, EAX*/ +// addbyte(0xc0); + } +// else +// { +// addbyte(0xb0); /*MOV AL, 1*/ +// addbyte(1); +// } + + +// voodoo_combine = &code_block[block_pos]; + /*XMM0 = colour*/ + /*XMM2 = 0 (for unpacking*/ + + /*EDI = state, ESI = params*/ + + if (params->textureMode & 1) + { + /*CVTSI2SSq XMM6, state->w*/ + /*MOVSS XMM7, const_1_48*/ + /*DIVSS XMM7, XMM6*/ + /*CVTSI2SSq XMM4, state->tmu0_s*/ + /*MULSS XMM7, const_1_44*/ + /*CVTSI2SSq XMM5, state->tmu0_t*/ + /*MULSS XMM4, XMM7*/ + /*CVTSS2SIq state->tex_s, XMM4*/ + /*MULSS XMM5, XMM7*/ + /*CVTSS2SIq state->tex_t, XMM5*/ + + addbyte(0xdf); /*FILDq state->tmu0_w*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, tmu0_w)); + addbyte(0xdd); /*FLDq const_1_48*/ + addbyte(0x05); + addlong(&const_1_48); + addbyte(0xde); /*FDIV ST(1)*/ + addbyte(0xf1); + addbyte(0xdf); /*FILDq state->tmu0_s*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, tmu0_s)); + addbyte(0xdf); /*FILDq state->tmu0_t*/ /*ST(0)=t, ST(1)=s, ST(2)=1/w*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, tmu0_t)); + addbyte(0xd9); /*FXCH ST(1)*/ /*ST(0)=s, ST(1)=t, ST(2)=1/w*/ + addbyte(0xc9); + addbyte(0xd8); /*FMUL ST(2)*/ /*ST(0)=s/w, ST(1)=t, ST(2)=1/w*/ + addbyte(0xca); + addbyte(0xd9); /*FXCH ST(1)*/ /*ST(0)=t, ST(1)=s/w, ST(2)=1/w*/ + addbyte(0xc9); + addbyte(0xd8); /*FMUL ST(2)*/ /*ST(0)=t/w, ST(1)=s/w, ST(2)=1/w*/ + addbyte(0xca); + addbyte(0xd9); /*FXCH ST(2)*/ /*ST(0)=1/w, ST(1)=s/w, ST(2)=t/w*/ + addbyte(0xca); + addbyte(0xd9); /*FSTPs log_temp*/ /*ST(0)=s/w, ST(1)=t/w*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, log_temp)); + addbyte(0xdf); /*FSITPq state->tex_s*/ + addbyte(0xbf); + addlong(offsetof(voodoo_state_t, tex_s)); + addbyte(0x8b); /*MOV EAX, log_temp*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, log_temp)); + addbyte(0xdf); /*FSITPq state->tex_t*/ + addbyte(0xbf); + addlong(offsetof(voodoo_state_t, tex_t)); + addbyte(0xc1); /*SHR EAX, 23-8*/ + addbyte(0xe8); + addbyte(15); + addbyte(0x0f); /*MOVZX EBX, AL*/ + addbyte(0xb6); + addbyte(0xd8); + addbyte(0x25); /*AND EAX, 0xff00*/ + addlong(0xff00); + addbyte(0x2d); /*SUB EAX, (127-44)<<8*/ + addlong((127-44+19) << 8); + addbyte(0x0f); /*MOVZX EBX, logtable[EBX]*/ + addbyte(0xb6); + addbyte(0x9b); + addlong(logtable); + addbyte(0x09); /*OR EAX, EBX*/ + addbyte(0xd8); +// addbyte(0x89); /*MOV state->lod_raw, EAX*/ +// addbyte(0x87); +// addlong(offsetof(voodoo_state_t, lod_raw)); + addbyte(0x03); /*ADD EAX, state->lod*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tmu[0].lod)); +/*HACK*/ +#if 0 + addbyte(0x8b); /*MOV EAX, state->lod_min*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_min)); +#endif + addbyte(0x3b); /*CMP EAX, state->lod_min*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_min)); + addbyte(0x0f); /*CMOVL EAX, state->lod_min*/ + addbyte(0x4c); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_min)); + addbyte(0x3b); /*CMP EAX, state->lod_max*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_max)); + addbyte(0x0f); /*CMOVNL EAX, state->lod_max*/ + addbyte(0x4d); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_max)); + addbyte(0xc1); /*SHR EAX, 8*/ + addbyte(0xe8); + addbyte(8); + addbyte(0x89); /*MOV state->lod, EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod)); + } + else + { + addbyte(0xf3); /*MOVQ XMM4, state->tmu0_s*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, tmu0_s)); + addbyte(0xf3); /*MOVQ XMM5, state->tmu0_t*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, tmu0_t)); + addbyte(0x66); /*SHRQ XMM4, 28*/ + addbyte(0x0f); + addbyte(0x73); + addbyte(0xd4); + addbyte(28); + addbyte(0x66); /*SHRQ XMM5, 28*/ + addbyte(0x0f); + addbyte(0x73); + addbyte(0xd5); + addbyte(28); + addbyte(0x66); /*MOVQ state->tex_s, XMM4*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, tex_s)); + addbyte(0x66); /*MOVQ state->tex_t, XMM5*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, tex_t)); + addbyte(0x8b); /*MOV EAX, state->lod_min*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod_min)); + addbyte(0xc1); /*SHR EAX, 8*/ + addbyte(0xe8); + addbyte(8); + addbyte(0x89); /*MOV state->lod, EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, lod)); + } + + + if (voodoo->trexInit1 & (1 << 18)) + { +#if 0 + addbyte(0xc7); /*MOV state->tex_r, 0*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_r)); + addlong(0); + addbyte(0xc7); /*MOV state->tex_g, 0*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_g)); + addlong(0); + addbyte(0xc7); /*MOV state->tex_b, 1*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_b)); + addlong(1); +#endif + addbyte(0xb8); /*MOV EAX, 0x000001*/ + addlong(0x000001); + addbyte(0x66); /*MOVD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0); + } + else if (params->fbzColorPath & FBZCP_TEXTURE_ENABLED) + { + if (voodoo->bilinear_enabled && (params->textureMode & 6)) + { + addbyte(0x8b); /*MOV ECX, state->lod[EDI]*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0xbd); /*MOV EBP, 1*/ + addlong(1); + addbyte(0x8a); /*MOV DL, params->tex_shift[ESI+ECX*4]*/ + addbyte(0x94); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_shift)); + addbyte(0xd3); /*SHL EBP, CL*/ + addbyte(0xe5); + addbyte(0x8b); /*MOV EAX, state->tex_s[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_s)); + addbyte(0xc1); /*SHL EBP, 3*/ + addbyte(0xe5); + addbyte(3); + addbyte(0x8b); /*MOV EBX, state->tex_t[EDI]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_t)); + addbyte(0x29); /*SUB EAX, EBP*/ + addbyte(0xe8); + addbyte(0x29); /*SUB EBX, EBP*/ + addbyte(0xeb); + addbyte(0xd3); /*SAR EAX, CL*/ + addbyte(0xf8); + addbyte(0xd3); /*SAR EBX, CL*/ + addbyte(0xfb); + addbyte(0x89); /*MOV EBP, EAX*/ + addbyte(0xc5); + addbyte(0x89); /*MOV ECX, EBX*/ + addbyte(0xd9); + addbyte(0x83); /*AND EBP, 0xf*/ + addbyte(0xe5); + addbyte(0xf); + addbyte(0xc1); /*SHL ECX, 4*/ + addbyte(0xe1); + addbyte(4); + addbyte(0xc1); /*SAR EAX, 4*/ + addbyte(0xf8); + addbyte(4); + addbyte(0x81); /*AND ECX, 0xf0*/ + addbyte(0xe1); + addlong(0xf0); + addbyte(0xc1); /*SAR EBX, 4*/ + addbyte(0xfb); + addbyte(4); + addbyte(0x09); /*OR EBP, ECX*/ + addbyte(0xcd); + addbyte(0x8b); /*MOV ECX, state->lod[EDI]*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0xc1); /*SHL EBP, 6*/ + addbyte(0xe5); + addbyte(6); + /*EAX = S, EBX = T, ECX = LOD, EDX = tex_shift, ESI=params, EDI=state, EBP = bilinear shift*/ + addbyte(0x8d); /*LEA ESI, [ESI+ECX*4]*/ + addbyte(0x34); + addbyte(0x8e); + addbyte(0x89); /*MOV ebp_store, EBP*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, ebp_store)); + addbyte(0x8b); /*MOV EBP, state->tex[EDI+ECX*4]*/ + addbyte(0xac); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, tex)); + addbyte(0x88); /*MOV CL, DL*/ + addbyte(0xd1); + addbyte(0x89); /*MOV EDX, EBX*/ + addbyte(0xda); + if (!state->clamp_s) + { + addbyte(0x23); /*AND EAX, params->tex_w_mask[ESI]*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, tex_w_mask)); + } + addbyte(0x83); /*ADD EDX, 1*/ + addbyte(0xc2); + addbyte(1); + if (state->clamp_t) + { + addbyte(0x0f); /*CMOVS EDX, zero*/ + addbyte(0x48); + addbyte(0x15); + addlong(&zero); + addbyte(0x3b); /*CMP EDX, params->tex_h_mask[ESI]*/ + addbyte(0x96); + addlong(offsetof(voodoo_params_t, tex_h_mask)); + addbyte(0x0f); /*CMOVA EDX, params->tex_h_mask[ESI]*/ + addbyte(0x47); + addbyte(0x96); + addlong(offsetof(voodoo_params_t, tex_h_mask)); + addbyte(0x85); /*TEST EBX,EBX*/ + addbyte(0xdb); + addbyte(0x0f); /*CMOVS EBX, zero*/ + addbyte(0x48); + addbyte(0x1d); + addlong(&zero); + addbyte(0x3b); /*CMP EBX, params->tex_h_mask[ESI]*/ + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, tex_h_mask)); + addbyte(0x0f); /*CMOVA EBX, params->tex_h_mask[ESI]*/ + addbyte(0x47); + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, tex_h_mask)); + } + else + { + addbyte(0x23); /*AND EDX, params->tex_h_mask[ESI]*/ + addbyte(0x96); + addlong(offsetof(voodoo_params_t, tex_h_mask)); + addbyte(0x23); /*AND EBX, params->tex_h_mask[ESI]*/ + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, tex_h_mask)); + } + /*EAX = S, EBX = T0, EDX = T1*/ + addbyte(0xd3); /*SHL EBX, CL*/ + addbyte(0xe3); + addbyte(0xd3); /*SHL EDX, CL*/ + addbyte(0xe2); + if (state->tformat & 8) + { + addbyte(0x8d); /*LEA EBX,[EBP+EBX*2]*/ + addbyte(0x5c); + addbyte(0x5d); + addbyte(0); + addbyte(0x8d); /*LEA EDX,[EBP+EDX*2]*/ + addbyte(0x54); + addbyte(0x55); + addbyte(0); + } + else + { + addbyte(0x01); /*ADD EBX, EBP*/ + addbyte(0xeb); + addbyte(0x01); /*ADD EDX, EBP*/ + addbyte(0xea); + } + if (state->clamp_s) + { + addbyte(0x8b); /*MOV EBP, params->tex_w_mask[ESI]*/ + addbyte(0xae); + addlong(offsetof(voodoo_params_t, tex_w_mask)); + addbyte(0x85); /*TEST EAX, EAX*/ + addbyte(0xc0); + addbyte(0x8b); /*MOV ebp_store2, ESI*/ + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, ebp_store)); + addbyte(0x0f); /*CMOVS EAX, zero*/ + addbyte(0x48); + addbyte(0x05); + addlong(&zero); + addbyte(0x78); /*JS + - clamp on 0*/ + addbyte(2+3+2+ ((state->tformat & 8) ? (3+3+2) : (4+4+2))); + addbyte(0x3b); /*CMP EAX, EBP*/ + addbyte(0xc5); + addbyte(0x0f); /*CMOVAE EAX, EBP*/ + addbyte(0x43); + addbyte(0xc5); + addbyte(0x73); /*JAE + - clamp on +*/ + addbyte((state->tformat & 8) ? (3+3+2) : (4+4+2)); + } + else + { + addbyte(0x3b); /*CMP EAX, params->tex_w_mask[ESI] - is S at texture edge (ie will wrap/clamp)?*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, tex_w_mask)); + addbyte(0x8b); /*MOV ebp_store2, ESI*/ + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, ebp_store)); + addbyte(0x74); /*JE +*/ + addbyte((state->tformat & 8) ? (3+3+2) : (4+4+2)); + } + + if (state->tformat & 8) + { + addbyte(0x8b); /*MOV EDX,[EDX+EAX*2]*/ + addbyte(0x14); + addbyte(0x42); + addbyte(0x8b); /*MOV EAX,[EBX+EAX*2]*/ + addbyte(0x04); + addbyte(0x43); + } + else + { + addbyte(0x0f); /*MOVZX EDX,W[EDX+EAX]*/ + addbyte(0xb7); + addbyte(0x14); + addbyte(0x02); + addbyte(0x0f); /*MOVZX EAX,W[EBX+EAX]*/ + addbyte(0xb7); + addbyte(0x04); + addbyte(0x03); + } + + if (state->clamp_s) + { + addbyte(0xeb); /*JMP +*/ + addbyte((state->tformat & 8) ? (3+4+3+3+4+3) : (4+4+2+2)); + + /*S clamped - the two S coordinates are the same*/ + if (state->tformat & 8) + { + addbyte(0x8b); /*MOV ECX, [EDX+EAX*2]*/ + addbyte(0x0c); + addbyte(0x42); + addbyte(0x8b); /*MOV EDX, [EDX+EAX*2-2]*/ + addbyte(0x54); + addbyte(0x42); + addbyte(-2); + addbyte(0x66); /*MOV DX, CX*/ + addbyte(0x89); + addbyte(0xca); + addbyte(0x8b); /*MOV ECX, [EBX+EAX*2]*/ + addbyte(0x0c); + addbyte(0x43); + addbyte(0x8b); /*MOV EAX, [EBX+EAX*2-2]*/ + addbyte(0x44); + addbyte(0x43); + addbyte(-2); + addbyte(0x66); /*MOV AX, CX*/ + addbyte(0x89); + addbyte(0xc8); + } + else + { + addbyte(0x0f); /*MOVZX EDX,W[EDX+EAX]*/ + addbyte(0xb7); + addbyte(0x14); + addbyte(0x02); + addbyte(0x0f); /*MOVZX EAX,W[EBX+EAX]*/ + addbyte(0xb7); + addbyte(0x04); + addbyte(0x03); + addbyte(0x88); /*MOV DH, DL*/ + addbyte(0xd6); + addbyte(0x88); /*MOV AH, AL*/ + addbyte(0xc4); + } + } + else + { + addbyte(0xeb); /*JMP +*/ + addbyte((state->tformat & 8) ? (3+3+3+3+3+3) : (2+2+4+4+2+2)); + + /*S wrapped - the two S coordinates are not contiguous*/ + if (state->tformat & 8) + { + addbyte(0x8b); /*MOV ECX, [EDX+EAX*2]*/ + addbyte(0x0c); + addbyte(0x42); + addbyte(0x8b); /*MOV EDX, [EDX-2]*/ + addbyte(0x52); + addbyte(-2); + addbyte(0x66); /*MOV DX, CX*/ + addbyte(0x89); + addbyte(0xca); + addbyte(0x8b); /*MOV ECX, [EBX+EAX*2]*/ + addbyte(0x0c); + addbyte(0x43); + addbyte(0x8b); /*MOV EAX, [EBX-2]*/ + addbyte(0x43); + addbyte(-2); + addbyte(0x66); /*MOV AX, CX*/ + addbyte(0x89); + addbyte(0xc8); + } + else + { + addbyte(0x8a); /*MOV CL, [EDX]*/ + addbyte(0x0a); + addbyte(0x8a); /*MOV CH, [EBX]*/ + addbyte(0x2b); + addbyte(0x0f); /*MOVZX EDX,B[EDX+EAX]*/ + addbyte(0xb6); + addbyte(0x14); + addbyte(0x02); + addbyte(0x0f); /*MOVZX EAX,B[EBX+EAX]*/ + addbyte(0xb6); + addbyte(0x04); + addbyte(0x03); + addbyte(0x88); /*MOV DH, CL*/ + addbyte(0xce); + addbyte(0x88); /*MOV AH, CH*/ + addbyte(0xec); + } + } + + addbyte(0x81); /*ADD ESI, bilinear_lookup*/ + addbyte(0xc6); + addlong(bilinear_lookup); + + switch (state->tformat) + { + case TEX_RGB332: + addbyte(0x0f); /*MOVZX ECX, AL*/ + addbyte(0xb6); + addbyte(0xc8); + addbyte(0x66); /*MOVD XMM0, rgb332[ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x04); + addbyte(0x8d); + addlong(rgb332); + addbyte(0x0f); /*MOVZX ECX, AH*/ + addbyte(0xb6); + addbyte(0xcc); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x66); /*MOVD XMM1, rgb332[ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x8d); + addlong(rgb332); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x0f); /*MOVZX ECX, DL*/ + addbyte(0xb6); + addbyte(0xca); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*MOVD XMM3, rgb332[ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x1c); + addbyte(0x8d); + addlong(rgb332); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x0f); /*MOVZX ECX, DH*/ + addbyte(0xb6); + addbyte(0xce); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, rgb332[ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x8d); + addlong(rgb332); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_Y4I2Q2: + addbyte(0x8b); /*MOV EBP, state->palette[EDI]*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, palette)); + addbyte(0x0f); /*MOVZX ECX, AL*/ + addbyte(0xb6); + addbyte(0xc8); + addbyte(0x66); /*MOVD XMM0, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x44); + addbyte(0x8d); + addbyte(0); + addbyte(0x0f); /*MOVZX ECX, AH*/ + addbyte(0xb6); + addbyte(0xcc); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x66); /*MOVD XMM1, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x4c); + addbyte(0x8d); + addbyte(0); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x0f); /*MOVZX ECX, DL*/ + addbyte(0xb6); + addbyte(0xca); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*MOVD XMM3, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x5c); + addbyte(0x8d); + addbyte(0); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x0f); /*MOVZX ECX, DH*/ + addbyte(0xb6); + addbyte(0xce); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x4c); + addbyte(0x8d); + addbyte(0); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_A8: + addbyte(0x66); /*MOVZX CX, AH*/ + addbyte(0x0f); + addbyte(0xb6); + addbyte(0xcc); + addbyte(0x66); /*MOVZX AX, AL*/ + addbyte(0x0f); + addbyte(0xb6); + addbyte(0xc0); + addbyte(0x66); /*IMUL CX, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x66); /*IMUL AX, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0x06); + addbyte(0x66); /*MOVZX BX, DH*/ + addbyte(0x0f); + addbyte(0xb6); + addbyte(0xde); + addbyte(0x66); /*MOVZX DX, DL*/ + addbyte(0x0f); + addbyte(0xb6); + addbyte(0xd2); + addbyte(0x66); /*ADD AX, CX*/ + addbyte(0x01); + addbyte(0xc8); + addbyte(0x66); /*IMUL BX, bilinear_lookup[ESI]+0x30*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0x5e); + addbyte(0x30); + addbyte(0x66); /*IMUL DX, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0x56); + addbyte(0x20); + addbyte(0x66); /*ADD AX, BX*/ + addbyte(0x01); + addbyte(0xd8); + addbyte(0x66); /*ADD AX, DX*/ + addbyte(0x01); + addbyte(0xd0); + addbyte(0x88); /*MOV AL, AH*/ + addbyte(0xe0); + addbyte(0x66); /*MOV BX, AX*/ + addbyte(0x89); + addbyte(0xc3); + addbyte(0x0f); /*BSWAP EAX*/ + addbyte(0xc8); + addbyte(0x66); /*MOV AX, BX*/ + addbyte(0x89); + addbyte(0xd8); + break; + + case TEX_I8: + addbyte(0x66); /*MOVZX CX, AH*/ + addbyte(0x0f); + addbyte(0xb6); + addbyte(0xcc); + addbyte(0x66); /*MOVZX AX, AL*/ + addbyte(0x0f); + addbyte(0xb6); + addbyte(0xc0); + addbyte(0x66); /*IMUL CX, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x66); /*IMUL AX, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0x06); + addbyte(0x66); /*MOVZX BX, DH*/ + addbyte(0x0f); + addbyte(0xb6); + addbyte(0xde); + addbyte(0x66); /*MOVZX DX, DL*/ + addbyte(0x0f); + addbyte(0xb6); + addbyte(0xd2); + addbyte(0x66); /*ADD AX, CX*/ + addbyte(0x01); + addbyte(0xc8); + addbyte(0x66); /*IMUL BX, bilinear_lookup[ESI]+0x30*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0x5e); + addbyte(0x30); + addbyte(0x66); /*IMUL DX, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xaf); + addbyte(0x56); + addbyte(0x20); + addbyte(0x66); /*ADD AX, BX*/ + addbyte(0x01); + addbyte(0xd8); + addbyte(0x66); /*ADD AX, DX*/ + addbyte(0x01); + addbyte(0xd0); + addbyte(0x88); /*MOV AL, AH*/ + addbyte(0xe0); + addbyte(0xc1); /*SHL EAX, 8*/ + addbyte(0xe0); + addbyte(8); + addbyte(0x88); /*MOV AL, AH*/ + addbyte(0xe0); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_AI8: + addbyte(0x0f); /*MOVZX ECX, AL*/ + addbyte(0xb6); + addbyte(0xc8); + addbyte(0x66); /*MOVD XMM0, ai44[ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x04); + addbyte(0x8d); + addlong(ai44); + addbyte(0x0f); /*MOVZX ECX, AH*/ + addbyte(0xb6); + addbyte(0xcc); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x66); /*MOVD XMM1, ai44[ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x8d); + addlong(ai44); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x0f); /*MOVZX ECX, DL*/ + addbyte(0xb6); + addbyte(0xca); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*MOVD XMM3, ai44[ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x1c); + addbyte(0x8d); + addlong(ai44); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x0f); /*MOVZX ECX, DH*/ + addbyte(0xb6); + addbyte(0xce); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, ai44[ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x8d); + addlong(ai44); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + break; + + case TEX_PAL8: + addbyte(0x8b); /*MOV EBP, state->palette[EDI]*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, palette)); + addbyte(0x0f); /*MOVZX ECX, AL*/ + addbyte(0xb6); + addbyte(0xc8); + addbyte(0x66); /*MOVD XMM0, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x44); + addbyte(0x8d); + addbyte(0); + addbyte(0x0f); /*MOVZX ECX, AH*/ + addbyte(0xb6); + addbyte(0xcc); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x66); /*MOVD XMM1, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x4c); + addbyte(0x8d); + addbyte(0); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x0f); /*MOVZX ECX, DL*/ + addbyte(0xb6); + addbyte(0xca); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*MOVD XMM3, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x5c); + addbyte(0x8d); + addbyte(0); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x0f); /*MOVZX ECX, DH*/ + addbyte(0xb6); + addbyte(0xce); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x4c); + addbyte(0x8d); + addbyte(0); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x30*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_R5G6B5: + addbyte(0x0f); /*MOVZX ECX, AX*/ + addbyte(0xb7); + addbyte(0xc8); + addbyte(0xc1); /*SHR EAX, 16*/ + addbyte(0xe8); + addbyte(16); + addbyte(0x66); /*MOVD XMM0, rgb565[ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x04); + addbyte(0x8d); + addlong(rgb565); + addbyte(0x66); /*MOVD XMM1, rgb565[EAX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x85); + addlong(rgb565); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x0f); /*MOVZX ECX, DX*/ + addbyte(0xb7); + addbyte(0xca); + addbyte(0xc1); /*SHR EDX, 16*/ + addbyte(0xea); + addbyte(16); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*MOVD XMM3, rgb565[ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x1c); + addbyte(0x8d); + addlong(rgb565); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, rgb565[EDX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x95); + addlong(rgb565); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x30*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_ARGB1555: + addbyte(0x0f); /*MOVZX ECX, AX*/ + addbyte(0xb7); + addbyte(0xc8); + addbyte(0xc1); /*SHR EAX, 16*/ + addbyte(0xe8); + addbyte(16); + addbyte(0x66); /*MOVD XMM0, argb1555[ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x04); + addbyte(0x8d); + addlong(argb1555); + addbyte(0x66); /*MOVD XMM1, argb1555[EAX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x85); + addlong(argb1555); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x0f); /*MOVZX ECX, DX*/ + addbyte(0xb7); + addbyte(0xca); + addbyte(0xc1); /*SHR EDX, 16*/ + addbyte(0xea); + addbyte(16); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*MOVD XMM3, argb1555[ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x1c); + addbyte(0x8d); + addlong(argb1555); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, argb1555[EDX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x95); + addlong(argb1555); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + break; + + case TEX_ARGB4444: + addbyte(0x0f); /*MOVZX ECX, AX*/ + addbyte(0xb7); + addbyte(0xc8); + addbyte(0xc1); /*SHR EAX, 16*/ + addbyte(0xe8); + addbyte(16); + addbyte(0x66); /*MOVD XMM0, argb4444[ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x04); + addbyte(0x8d); + addlong(argb4444); + addbyte(0x66); /*MOVD XMM1, argb4444[EAX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x85); + addlong(argb4444); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x0f); /*MOVZX ECX, DX*/ + addbyte(0xb7); + addbyte(0xca); + addbyte(0xc1); /*SHR EDX, 16*/ + addbyte(0xea); + addbyte(16); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*MOVD XMM3, argb4444[ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x1c); + addbyte(0x8d); + addlong(argb4444); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, argb4444[EDX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x95); + addlong(argb4444); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + break; + + case TEX_A8I8: + addbyte(0x0f); /*MOVZX ECX, AX*/ + addbyte(0xb7); + addbyte(0xc8); + addbyte(0xc1); /*SHR EAX, 16*/ + addbyte(0xe8); + addbyte(16); + addbyte(0x66); /*MOVD XMM0, ai88[ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x04); + addbyte(0x8d); + addlong(ai88); + addbyte(0x66); /*MOVD XMM1, ai88[EAX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x85); + addlong(ai88); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x0f); /*MOVZX ECX, DX*/ + addbyte(0xb7); + addbyte(0xca); + addbyte(0xc1); /*SHR EDX, 16*/ + addbyte(0xea); + addbyte(16); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*MOVD XMM3, ai88[ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x1c); + addbyte(0x8d); + addlong(ai88); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, ai88[EDX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x0c); + addbyte(0x95); + addlong(ai88); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + break; + + case TEX_APAL88: + addbyte(0x8b); /*MOV EBP, state->palette[EDI]*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, palette)); + addbyte(0x0f); /*MOVZX ECX, AL*/ + addbyte(0xb6); + addbyte(0xc8); + addbyte(0x66); /*MOVD XMM0, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x44); + addbyte(0x8d); + addbyte(0); + addbyte(0x0f); /*MOVZX ECX, AH*/ + addbyte(0xb6); + addbyte(0xcc); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0xc1); /*SHR EAX, 16*/ + addbyte(0xe8); + addbyte(16); + addbyte(0x66); /*PINSRW XMM0, ECX, 3*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0xc1); + addbyte(3); + addbyte(0x0f); /*MOVZX ECX, AL*/ + addbyte(0xb6); + addbyte(0xc8); + addbyte(0x0f); /*MOVZX EAX, AH*/ + addbyte(0xb6); + addbyte(0xc4); + addbyte(0x66); /*MOVD XMM1, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x4c); + addbyte(0x8d); + addbyte(0); + addbyte(0x66); /*PMULLW XMM0, bilinear_lookup[ESI]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x06); + addbyte(0x0f); /*MOVZX ECX, DL*/ + addbyte(0xb6); + addbyte(0xca); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PINSRW XMM1, EAX, 3*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0xc8); + addbyte(3); + addbyte(0x66); /*MOVD XMM3, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x5c); + addbyte(0x8d); + addbyte(0); + addbyte(0x0f); /*MOVZX ECX, DH*/ + addbyte(0xb6); + addbyte(0xce); + addbyte(0xc1); /*SHR EDX, 16*/ + addbyte(0xea); + addbyte(16); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x10*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x10); + addbyte(0x66); /*PINSRW XMM3, ECX, 3*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0xd9); + addbyte(3); + addbyte(0x0f); /*MOVZX ECX, DL*/ + addbyte(0xb6); + addbyte(0xca); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*MOVD XMM1, [EBP+ECX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x4c); + addbyte(0x8d); + addbyte(0); + addbyte(0x0f); /*MOVZX ECX, DH*/ + addbyte(0xb6); + addbyte(0xce); + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + addbyte(0x66); /*PMULLW XMM3, bilinear_lookup[ESI]+0x20*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x5e); + addbyte(0x20); + addbyte(0x66); /*PINSR1 XMM1, ECX, 3*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0xc9); + addbyte(3); + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); + addbyte(0x66); /*PMULLW XMM1, bilinear_lookup[ESI]+0x30*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x4e); + addbyte(0x30); + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + break; + + default: + fatal("Unknown texture format %i\n", state->tformat); + } + + addbyte(0x8b); /*MOV ESI, [ESP+8]*/ + addbyte(0x74); + addbyte(0x24); + addbyte(8+16); /*CHECK!*/ + } + else + { + addbyte(0x8b); /*MOV ECX, state->lod[EDI]*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, lod)); + addbyte(0x8a); /*MOV DL, params->tex_shift[ESI+ECX*4]*/ + addbyte(0x94); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_shift)); + addbyte(0x8b); /*MOV EBP, state->tex[EDI+ECX*4]*/ + addbyte(0xac); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, tex)); + addbyte(0x80); /*ADD CL, 4*/ + addbyte(0xc1); + addbyte(4); + addbyte(0x8b); /*MOV EAX, state->tex_s[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_s)); + addbyte(0x8b); /*MOV EBX, state->tex_t[EDI]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_t)); + addbyte(0xd3); /*SHR EAX, CL*/ + addbyte(0xe8); + addbyte(0xd3); /*SHR EBX, CL*/ + addbyte(0xeb); + if (state->clamp_s) + { + addbyte(0x85); /*TEST EAX, EAX*/ + addbyte(0xc0); + addbyte(0x0f); /*CMOVS EAX, zero*/ + addbyte(0x48); + addbyte(0x05); + addlong(&zero); + addbyte(0x3b); /*CMP EAX, params->tex_w_mask[ESI+ECX*4]*/ + addbyte(0x84); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_w_mask) - 0x10); + addbyte(0x0f); /*CMOVAE EAX, params->tex_w_mask[ESI+ECX*4]*/ + addbyte(0x43); + addbyte(0x84); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_w_mask) - 0x10); + + } + else + { + addbyte(0x23); /*AND EAX, params->tex_w_mask-0x10[ESI+ECX*4]*/ + addbyte(0x84); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_w_mask) - 0x10); + } + if (state->clamp_t) + { + addbyte(0x85); /*TEST EBX, EBX*/ + addbyte(0xdb); + addbyte(0x0f); /*CMOVS EBX, zero*/ + addbyte(0x48); + addbyte(0x1d); + addlong(&zero); + addbyte(0x3b); /*CMP EBX, params->tex_h_mask[ESI+ECX*4]*/ + addbyte(0x9c); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_h_mask) - 0x10); + addbyte(0x0f); /*CMOVAE EBX, params->tex_h_mask[ESI+ECX*4]*/ + addbyte(0x43); + addbyte(0x9c); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_h_mask) - 0x10); + } + else + { + addbyte(0x23); /*AND EBX, params->tex_h_mask-0x10[ESI+ECX*4]*/ + addbyte(0x9c); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, tex_h_mask) - 0x10); + } + addbyte(0x88); /*MOV CL, DL*/ + addbyte(0xd1); + addbyte(0xd3); /*SHL EBX, CL*/ + addbyte(0xe3); + addbyte(0x01); /*ADD EBX, EAX*/ + addbyte(0xc3); + + if (state->tformat & 8) + { + addbyte(0x0f); /*MOVZX EAX,W[EBP+EBX*2]*/ + addbyte(0xb7); + addbyte(0x44); + addbyte(0x5d); + addbyte(0); + } + else + { + addbyte(0x0f); /*MOVZX EAX,B[EBP+EBX]*/ + addbyte(0xb6); + addbyte(0x44); + addbyte(0x1d); + addbyte(0); + } + + switch (state->tformat) + { + case TEX_RGB332: + addbyte(0x8b); /*MOV EAX, rgb332[EAX*4]*/ + addbyte(0x04); + addbyte(0x85); + addlong(rgb332); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_Y4I2Q2: + addbyte(0x8b); /*MOV EBP, state->palette[EDI]*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, palette)); + addbyte(0x8b); /*MOV EAX, [EBP+EAX*4]*/ + addbyte(0x44); + addbyte(0x85); + addbyte(0); +// addbyte(0x0f); /*BSWAP EAX*/ +// addbyte(0xc8); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_A8: + addbyte(0x88); /*MOV AH, AL*/ + addbyte(0xc4); + addbyte(0x66); /*MOV BX, AX*/ + addbyte(0x89); + addbyte(0xc3); + addbyte(0x0f); /*BSWAP EAX*/ + addbyte(0xc8); + addbyte(0x66); /*MOV AX, BX*/ + addbyte(0x89); + addbyte(0xd8); + break; + + case TEX_I8: + addbyte(0x88); /*MOV AH, AL*/ + addbyte(0xc4); + addbyte(0xc1); /*SHL EAX, 8*/ + addbyte(0xe0); + addbyte(8); + addbyte(0x88); /*MOV AL, AH*/ + addbyte(0xe0); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); +// addbyte(0x25); /*AND EAX, 0x00ffffff*/ +// addlong(0x00000000); + break; + + case TEX_AI8: + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + addbyte(0x83); /*AND EAX, 0x0f*/ + addbyte(0xe0); + addbyte(0x0f); + addbyte(0x81); /*AND EBX, 0xf0*/ + addbyte(0xe3); + addlong(0xf0); + addbyte(0x89); /*MOV ECX, EAX*/ + addbyte(0xc1); + addbyte(0x89); /*MOV EDX, EBX*/ + addbyte(0xda); + addbyte(0xc1); /*SHL ECX, 4*/ + addbyte(0xe1); + addbyte(4); + addbyte(0xc1); /*SHR EDX, 4*/ + addbyte(0xe2); + addbyte(4); + addbyte(0x09); /*OR EAX, ECX*/ + addbyte(0xc8); + addbyte(0x09); /*OR EBX, EDX*/ + addbyte(0xd3); + addbyte(0x88); /*MOV AH, AL*/ + addbyte(0xc4); + addbyte(0xc1); /*SHL EBX, 24*/ + addbyte(0xe3); + addbyte(24); + addbyte(0xc1); /*SHL EAX, 8*/ + addbyte(0xe0); + addbyte(8); + addbyte(0x88); /*MOV AL, AH*/ + addbyte(0xe0); + addbyte(0x09); /*OR EAX, EBX*/ + addbyte(0xd8); + break; + + case TEX_PAL8: + addbyte(0x8b); /*MOV EBP, state->palette[EDI]*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, palette)); + addbyte(0x8b); /*MOV EAX, [EBP+EAX*4]*/ + addbyte(0x44); + addbyte(0x85); + addbyte(0); +// addbyte(0x0f); /*BSWAP EAX*/ +// addbyte(0xc8); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_R5G6B5: + addbyte(0x8b); /*MOV EAX, rgb565[EAX*4]*/ + addbyte(0x04); + addbyte(0x85); + addlong(rgb565); + addbyte(0x0d); /*OR EAX, 0xff000000*/ + addlong(0xff000000); + break; + + case TEX_ARGB1555: + addbyte(0x8b); /*MOV EAX, argb1555[EAX*4]*/ + addbyte(0x04); + addbyte(0x85); + addlong(argb1555); + break; + + case TEX_ARGB4444: + addbyte(0x8b); /*MOV EAX, argb4444[EAX*4]*/ + addbyte(0x04); + addbyte(0x85); + addlong(argb4444); + break; + + case TEX_A8I8: + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + addbyte(0xc1); /*SHL EAX, 16*/ + addbyte(0xe0); + addbyte(16); + addbyte(0x88); /*MOV AL, BL*/ + addbyte(0xd8); + addbyte(0x88); /*MOV AH, BL*/ + addbyte(0xdc); + break; + + case TEX_APAL88: + addbyte(0x8b); /*MOV EBP, state->palette[EDI]*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, palette)); + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + addbyte(0x25); /*AND EAX, 0x000000ff*/ + addlong(0x000000ff); + addbyte(0x8b); /*MOV EAX, [EBP+EAX*4]*/ + addbyte(0x44); + addbyte(0x85); + addbyte(0); + addbyte(0xc1); /*SHL EBX, 16*/ + addbyte(0xe3); + addbyte(16); +// addbyte(0x0f); /*BSWAP EAX*/ +// addbyte(0xc8); + addbyte(0x81); /*AND EBX, 0xff000000*/ + addbyte(0xe3); + addlong(0xff000000); + addbyte(0x25); /*AND EAX, 0x00ffffff*/ + addlong(0x00ffffff); + addbyte(0x09); /*OR EAX, EBX*/ + addbyte(0xd8); + +// addbyte(0x25); /*AND EAX, 0x00ffffff*/ +// addlong(0x00000000); + break; + + default: + fatal("Unknown texture format %i\n", state->tformat); + } + } + if ((params->fbzMode & FBZ_CHROMAKEY)) + { + addbyte(0x8b); /*MOV EBX, params->chromaKey[ESI]*/ + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, chromaKey)); + addbyte(0x31); /*XOR EBX, EAX*/ + addbyte(0xc3); + addbyte(0x81); /*AND EBX, 0xffffff*/ + addbyte(0xe3); + addlong(0xffffff); + addbyte(0x0f); /*JE skip*/ + addbyte(0x84); + chroma_skip_pos = block_pos; + addlong(0); + } +#if 0 + addbyte(0x0f); /*MOVZX EBX, AL*/ + addbyte(0xb6); + addbyte(0xd8); + addbyte(0x89); /*MOV state->tex_b[EDI], EBX*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_b)); + addbyte(0x0f); /*MOVZX EBX, AH*/ + addbyte(0xb6); + addbyte(0xdc); + addbyte(0xc1); /*SHR EAX, 16*/ + addbyte(0xe8); + addbyte(16); + addbyte(0x89); /*MOV state->tex_g[EDI], EBX*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_g)); + addbyte(0x0f); /*MOVZX EBX, AL*/ + addbyte(0xb6); + addbyte(0xd8); + addbyte(0x89); /*MOV state->tex_r[EDI], EBX*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_r)); + addbyte(0x0f); /*MOVZX EBX, AH*/ + addbyte(0xb6); + addbyte(0xdc); + addbyte(0x89); /*MOV state->tex_a[EDI], EBX*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); +#endif +//#if 0 +// addbyte(0x89); /*MOV state->tex_out[EDI], EAX*/ +// addbyte(0x87); +// addlong(offsetof(voodoo_state_t, tex_out)); + addbyte(0x66); /*MOVD XMM0, EAX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xc0); + addbyte(0xc1); /*SHR EAX, 24*/ + addbyte(0xe8); + addbyte(24); + addbyte(0x89); /*MOV state->tex_a[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_a)); +//#endif + } + + + if (params->alphaMode & ((1 << 0) | (1 << 4))) + { + /*EBX = a_other*/ + switch (a_sel) + { + case A_SEL_ITER_A: + addbyte(0x8b); /*MOV EBX, state->ia*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, ia)); + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + addbyte(0xba); /*MOV EDX, 0xff*/ + addlong(0xff); + addbyte(0xc1); /*SAR EBX, 12*/ + addbyte(0xfb); + addbyte(12); + addbyte(0x0f); /*CMOVS EBX, EAX*/ + addbyte(0x48); + addbyte(0xd8); + addbyte(0x39); /*CMP EBX, EDX*/ + addbyte(0xd3); + addbyte(0x0f); /*CMOVA EBX, EDX*/ + addbyte(0x47); + addbyte(0xda); + break; + case A_SEL_TEX: + addbyte(0x8b); /*MOV EBX, state->tex_a*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); + break; + case A_SEL_COLOR1: + addbyte(0x0f); /*MOVZX EBX, params->color1+3*/ + addbyte(0xb6); + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, color1)+3); + break; + default: + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + break; + } + /*ECX = a_local*/ + switch (cca_localselect) + { + case CCA_LOCALSELECT_ITER_A: + if (a_sel == A_SEL_ITER_A) + { + addbyte(0x89); /*MOV ECX, EBX*/ + addbyte(0xd9); + } + else + { + addbyte(0x8b); /*MOV ECX, state->ia*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ia)); + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + addbyte(0xba); /*MOV EDX, 0xff*/ + addlong(0xff); + addbyte(0xc1);/*SAR ECX, 12*/ + addbyte(0xf9); + addbyte(12); + addbyte(0x0f); /*CMOVS ECX, EAX*/ + addbyte(0x48); + addbyte(0xc8); + addbyte(0x39); /*CMP ECX, EDX*/ + addbyte(0xd1); + addbyte(0x0f); /*CMOVA ECX, EDX*/ + addbyte(0x47); + addbyte(0xca); + } + break; + case CCA_LOCALSELECT_COLOR0: + addbyte(0x0f); /*MOVZX ECX, params->color0+3*/ + addbyte(0xb6); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, color0)+3); + break; + case CCA_LOCALSELECT_ITER_Z: + addbyte(0x8b); /*MOV ECX, state->z*/ + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, z)); + if (a_sel != A_SEL_ITER_A) + { + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + addbyte(0xba); /*MOV EDX, 0xff*/ + addlong(0xff); + } + addbyte(0xc1);/*SAR ECX, 20*/ + addbyte(0xf9); + addbyte(20); + addbyte(0x0f); /*CMOVS ECX, EAX*/ + addbyte(0x48); + addbyte(0xc8); + addbyte(0x39); /*CMP ECX, EDX*/ + addbyte(0xd1); + addbyte(0x0f); /*CMOVA ECX, EDX*/ + addbyte(0x47); + addbyte(0xca); + break; + + default: + addbyte(0xb9); /*MOV ECX, 0xff*/ + addlong(0xff); + break; + } + + if (cca_zero_other) + { + addbyte(0x31); /*XOR EDX, EDX*/ + addbyte(0xd2); + } + else + { + addbyte(0x89); /*MOV EDX, EBX*/ + addbyte(0xda); + } + + if (cca_sub_clocal) + { + addbyte(0x29); /*SUB EDX, ECX*/ + addbyte(0xca); + } + } + + if (cc_sub_clocal || cc_mselect == 1 || cc_add == 1) + { + /*XMM1 = local*/ + if (!cc_localselect_override) + { + if (cc_localselect) + { + addbyte(0x66); /*MOVD XMM1, params->color0*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, color0)); + } + else + { + addbyte(0xf3); /*MOVDQU XMM1, ib*/ /* ir, ig and ib must be in same dqword!*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0x66); /*PSRAD XMM1, 12*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe1); + addbyte(12); + addbyte(0x66); /*PACKSSDW XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc9); + addbyte(0x66); /*PACKUSWB XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc9); + } + } + else + { + addbyte(0xf6); /*TEST state->tex_a, 0x80*/ + addbyte(0x87); + addbyte(0x23); + addlong(offsetof(voodoo_state_t, tex_a)); + addbyte(0x80); + addbyte(0x74);/*JZ !cc_localselect*/ + addbyte(8+2); + addbyte(0x66); /*MOVD XMM1, params->color0*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, color0)); + /*JMP +*/ + /*!cc_localselect:*/ + addbyte(0xf3); /*MOVDQU XMM1, ib*/ /* ir, ig and ib must be in same dqword!*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0x66); /*PSRAD XMM1, 12*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe1); + addbyte(12); + addbyte(0x66); /*PACKSSDW XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc9); + addbyte(0x66); /*PACKUSWB XMM1, XMM1*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc9); + } + addbyte(0x66); /*PUNPCKLBW XMM1, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xca); + } + if (!cc_zero_other) + { + if (_rgb_sel == CC_LOCALSELECT_ITER_RGB) + { + addbyte(0xf3); /*MOVDQU XMM0, ib*/ /* ir, ig and ib must be in same dqword!*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0x66); /*PSRAD XMM0, 12*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe0); + addbyte(12); + addbyte(0x66); /*PACKSSDW XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + } + else if (_rgb_sel == CC_LOCALSELECT_TEX) + { +#if 0 + addbyte(0xf3); /*MOVDQU XMM0, state->tex_b*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_b)); + addbyte(0x66); /*PACKSSDW XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0); + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); +#endif + } + else if (_rgb_sel == CC_LOCALSELECT_COLOR1) + { + addbyte(0x66); /*MOVD XMM0, params->color1*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x86); + addlong(offsetof(voodoo_params_t, color1)); + } + else + { + /*MOVD XMM0, src_r*/ + } + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + if (cc_sub_clocal) + { + addbyte(0x66); /*PSUBW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xc1); + } + } + else + { + addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc0); + if (cc_sub_clocal) + { + addbyte(0x66); /*PSUBW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xc1); + } + } + + if (params->alphaMode & ((1 << 0) | (1 << 4))) + { + if (!(cca_mselect == 0 && cca_reverse_blend == 0)) + { + switch (cca_mselect) + { + case CCA_MSELECT_ALOCAL: + addbyte(0x89); /*MOV EAX, ECX*/ + addbyte(0xc8); + break; + case CCA_MSELECT_AOTHER: + addbyte(0x89); /*MOV EAX, EBX*/ + addbyte(0xd8); + break; + case CCA_MSELECT_ALOCAL2: + addbyte(0x89); /*MOV EAX, ECX*/ + addbyte(0xc8); + break; + case CCA_MSELECT_TEX: + addbyte(0x0f); /*MOVZX EAX, state->tex_a*/ + addbyte(0xb6); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, tex_a)); + break; + + case CCA_MSELECT_ZERO: + default: + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + break; + } + if (!cca_reverse_blend) + { + addbyte(0x35); /*XOR EAX, 0xff*/ + addlong(0xff); + } + addbyte(0x83); /*ADD EAX, 1*/ + addbyte(0xc0); + addbyte(1); + addbyte(0x0f); /*IMUL EDX, EAX*/ + addbyte(0xaf); + addbyte(0xd0); + addbyte(0xc1); /*SHR EDX, 8*/ + addbyte(0xea); + addbyte(8); + } + } + + if ((params->alphaMode & ((1 << 0) | (1 << 4)))) + { + addbyte(0x31); /*XOR EAX, EAX*/ + addbyte(0xc0); + } + + if (!(cc_mselect == 0 && cc_reverse_blend == 0) && cc_mselect == CC_MSELECT_AOTHER) + { + /*Copy a_other to XMM3 before it gets modified*/ + addbyte(0x66); /*MOVD XMM3, EDX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xda); + addbyte(0xf2); /*PSHUFLW XMM3, XMM3, 0*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xdb); + addbyte(0x00); + } + + if (cca_add && (params->alphaMode & ((1 << 0) | (1 << 4)))) + { + addbyte(0x01); /*ADD EDX, ECX*/ + addbyte(0xca); + } + + if ((params->alphaMode & ((1 << 0) | (1 << 4)))) + { + addbyte(0x85); /*TEST EDX, EDX*/ + addbyte(0xd2); + addbyte(0x0f); /*CMOVS EDX, EAX*/ + addbyte(0x48); + addbyte(0xd0); + addbyte(0xb8); /*MOV EAX, 0xff*/ + addlong(0xff); + addbyte(0x81); /*CMP EDX, 0xff*/ + addbyte(0xfa); + addlong(0xff); + addbyte(0x0f); /*CMOVA EDX, EAX*/ + addbyte(0x47); + addbyte(0xd0); + + if (cca_invert_output) + { + addbyte(0x81); /*XOR EDX, 0xff*/ + addbyte(0xf2); + addlong(0xff); + } + } + + if (!(cc_mselect == 0 && cc_reverse_blend == 0)) + { + switch (cc_mselect) + { + case CC_MSELECT_ZERO: + addbyte(0x66); /*PXOR XMM3, XMM3*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xdb); + break; + case CC_MSELECT_CLOCAL: + addbyte(0xf3); /*MOV XMM3, XMM1*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xd9); + break; + case CC_MSELECT_ALOCAL: + addbyte(0x66); /*MOVD XMM3, ECX*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0xd9); + addbyte(0xf2); /*PSHUFLW XMM3, XMM3, 0*/ + addbyte(0x0f); + addbyte(0x70); + addbyte(0xdb); + addbyte(0x00); + break; + case CC_MSELECT_AOTHER: + /*Handled above*/ + break; + case CC_MSELECT_TEX: + addbyte(0x66); /*PINSRW XMM3, state->tex_a, 0*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); + addbyte(0); + addbyte(0x66); /*PINSRW XMM3, state->tex_a, 1*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); + addbyte(1); + addbyte(0x66); /*PINSRW XMM3, state->tex_a, 2*/ + addbyte(0x0f); + addbyte(0xc4); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tex_a)); + addbyte(2); + break; + default: + addbyte(0x66); /*PXOR XMM3, XMM3*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xdb); + break; + } + addbyte(0xf3); /*MOV XMM4, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe0); + if (!cc_reverse_blend) + { + addbyte(0x66); /*PXOR XMM3, 0xff*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x1d); + addlong(&xmm_ff_w); + } + addbyte(0x66); /*PADDW XMM3, 1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x1d); + addlong(&xmm_01_w); + addbyte(0x66); /*PMULLW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xc3); + addbyte(0x66); /*PMULHW XMM4, XMM3*/ + addbyte(0x0f); + addbyte(0xe5); + addbyte(0xe3); + addbyte(0x66); /*PUNPCKLWD XMM0, XMM4*/ + addbyte(0x0f); + addbyte(0x61); + addbyte(0xc4); + addbyte(0x66); /*PSRLD XMM0, 8*/ + addbyte(0x0f); + addbyte(0x72); + addbyte(0xe0); + addbyte(8); + addbyte(0x66); /*PACKSSDW XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x6b); + addbyte(0xc0); + } + + if (cc_add == 1) + { + addbyte(0x66); /*PADDW XMM0, XMM1*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc1); + } + + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + + if (cc_invert_output) + { + addbyte(0x66); /*PXOR XMM0, 0xff*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0x05); + addlong(&xmm_ff_b); + } +//#if 0 +// addbyte(0x66); /*MOVD state->out[EDI], XMM0*/ +// addbyte(0x0f); +// addbyte(0x7e); +// addbyte(0x87); +// addlong(offsetof(voodoo_state_t, out)); + if (params->fogMode & FOG_ENABLE) + { + if (params->fogMode & FOG_CONSTANT) + { + addbyte(0x66); /*MOVD XMM3, params->fogColor[ESI]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, fogColor)); + addbyte(0x66); /*PADDUSB XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xdc); + addbyte(0xc3); +/* src_r += params->fogColor.r; + src_g += params->fogColor.g; + src_b += params->fogColor.b; */ + } + else + { + /*int fog_r, fog_g, fog_b, fog_a; */ + + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + + if (!(params->fogMode & FOG_ADD)) + { + addbyte(0x66); /*MOVD XMM3, params->fogColor[ESI]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x9e); + addlong(offsetof(voodoo_params_t, fogColor)); + addbyte(0x66); /*PUNPCKLBW XMM3, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xda); + } + else + { + addbyte(0x66); /*PXOR XMM3, XMM3*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xdb); + } + + if (!(params->fogMode & FOG_MULT)) + { + addbyte(0x66); /*PSUBW XMM3, XMM0*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xd8); + } + + /*Divide by 2 to prevent overflow on multiply*/ + addbyte(0x66); /*PSRAW XMM3, 1*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xe3); + addbyte(1); + + if (params->fogMode & FOG_Z) + { + addbyte(0x8b); /*MOV EAX, state->z[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, z)); + addbyte(0xc1); /*SHR EAX, 12*/ + addbyte(0xe8); + addbyte(12); + addbyte(0x25); /*AND EAX, 0xff*/ + addlong(0xff); +// fog_a = (z >> 20) & 0xff; + } + else if (params->fogMode & FOG_ALPHA) + { + addbyte(0x8b); /*MOV EAX, state->ia[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, ia)); + addbyte(0x31); /*XOR EBX, EBX*/ + addbyte(0xdb); + addbyte(0xc1); /*SAR EAX, 12*/ + addbyte(0xf8); + addbyte(12); + addbyte(0x0f); /*CMOVS EAX, EBX*/ + addbyte(0x48); + addbyte(0xc3); + addbyte(0xbb); /*MOV EBX, 0xff*/ + addlong(0xff); + addbyte(0x3d); /*CMP EAX, 0xff*/ + addlong(0xff); + addbyte(0x0f); /*CMOVAE EAX, EBX*/ + addbyte(0x43); + addbyte(0xc3); +// fog_a = CLAMP(ia >> 12); + } + else + { + addbyte(0x8b); /*MOV EBX, state->w_depth[EDI]*/ + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, w_depth)); + addbyte(0x89); /*MOV EAX, EBX*/ + addbyte(0xd8); + addbyte(0xc1); /*SHR EBX, 10*/ + addbyte(0xeb); + addbyte(10); + addbyte(0xc1); /*SHR EAX, 2*/ + addbyte(0xe8); + addbyte(2); + addbyte(0x83); /*AND EBX, 0x3f*/ + addbyte(0xe3); + addbyte(0x3f); + addbyte(0x25); /*AND EAX, 0xff*/ + addlong(0xff); + addbyte(0xf6); /*MUL params->fogTable+1[ESI+EBX*2]*/ + addbyte(0xa4); + addbyte(0x5e); + addlong(offsetof(voodoo_params_t, fogTable)+1); + addbyte(0x0f); /*MOVZX EBX, params->fogTable[ESI+EBX*2]*/ + addbyte(0xb6); + addbyte(0x9c); + addbyte(0x5e); + addlong(offsetof(voodoo_params_t, fogTable)); + addbyte(0xc1); /*SHR EAX, 10*/ + addbyte(0xe8); + addbyte(10); + addbyte(0x01); /*ADD EAX, EBX*/ + addbyte(0xd8); + +/* int fog_idx = (w_depth >> 10) & 0x3f; + + fog_a = params->fogTable[fog_idx].fog; + fog_a += (params->fogTable[fog_idx].dfog * ((w_depth >> 2) & 0xff)) >> 10;*/ + } + addbyte(0x01); /*ADD EAX, EAX*/ + addbyte(0xc0); +// fog_a++; + + addbyte(0x66); /*PMULLW XMM3, alookup+4[EAX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x1c); + addbyte(0xc5); + addlong(((uintptr_t)alookup) + 16); + addbyte(0x66); /*PSRAW XMM3, 7*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xe3); + addbyte(7); +/* fog_r = (fog_r * fog_a) >> 8; + fog_g = (fog_g * fog_a) >> 8; + fog_b = (fog_b * fog_a) >> 8;*/ + + if (params->fogMode & FOG_MULT) + { + addbyte(0xf3); /*MOV XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc3); + } + else + { + addbyte(0x66); /*PADDW XMM0, XMM3*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc3); +/* src_r += fog_r; + src_g += fog_g; + src_b += fog_b;*/ + } + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + } + +/* src_r = CLAMP(src_r); + src_g = CLAMP(src_g); + src_b = CLAMP(src_b);*/ + } + + if ((params->alphaMode & 1) && (alpha_func != AFUNC_NEVER) && (alpha_func != AFUNC_ALWAYS)) + { + addbyte(0x0f); /*MOVZX ECX, params->alphaMode+3*/ + addbyte(0xb6); + addbyte(0x8e); + addlong(offsetof(voodoo_params_t, alphaMode) + 3); + addbyte(0x39); /*CMP EDX, ECX*/ + addbyte(0xca); + + switch (alpha_func) + { + case AFUNC_LESSTHAN: + addbyte(0x0f); /*JAE skip*/ + addbyte(0x83); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_EQUAL: + addbyte(0x0f); /*JNE skip*/ + addbyte(0x85); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_LESSTHANEQUAL: + addbyte(0x0f); /*JA skip*/ + addbyte(0x87); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_GREATERTHAN: + addbyte(0x0f); /*JBE skip*/ + addbyte(0x86); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_NOTEQUAL: + addbyte(0x0f); /*JE skip*/ + addbyte(0x84); + a_skip_pos = block_pos; + addlong(0); + break; + case AFUNC_GREATERTHANEQUAL: + addbyte(0x0f); /*JB skip*/ + addbyte(0x82); + a_skip_pos = block_pos; + addlong(0); + break; + } + } + else if ((params->alphaMode & 1) && (alpha_func == AFUNC_NEVER)) + { + addbyte(0xC3); /*RET*/ + } + + if (params->alphaMode & (1 << 4)) + { + addbyte(0x8b); /*MOV EAX, state->x[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x)); + addbyte(0x8b); /*MOV EBP, fb_mem*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, fb_mem)); + addbyte(0x01); /*ADD EDX, EDX*/ + addbyte(0xd2); + addbyte(0x0f); /*MOVZX EAX, [EBP+EAX*2]*/ + addbyte(0xb7); + addbyte(0x44); + addbyte(0x45); + addbyte(0); + addbyte(0x66); /*PUNPCKLBW XMM0, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xc2); + addbyte(0x66); /*MOVD XMM4, rgb565[EAX*4]*/ + addbyte(0x0f); + addbyte(0x6e); + addbyte(0x24); + addbyte(0x85); + addlong(rgb565); + addbyte(0x66); /*PUNPCKLBW XMM4, XMM2*/ + addbyte(0x0f); + addbyte(0x60); + addbyte(0xe2); + addbyte(0xf3); /*MOV XMM6, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xf4); + + switch (dest_afunc) + { + case AFUNC_AZERO: + addbyte(0x66); /*PXOR XMM4, XMM4*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xe4); + break; + case AFUNC_ASRC_ALPHA: + addbyte(0x66); /*PMULLW XMM4, alookup[EDX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x24); + addbyte(0xd5); + addlong(alookup); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + break; + case AFUNC_A_COLOR: + addbyte(0x66); /*PMULLW XMM4, XMM0*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xe0); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + break; + case AFUNC_ADST_ALPHA: + break; + case AFUNC_AONE: + break; + case AFUNC_AOMSRC_ALPHA: + addbyte(0x66); /*PMULLW XMM4, aminuslookup[EDX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x24); + addbyte(0xd5); + addlong(aminuslookup); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + break; + case AFUNC_AOM_COLOR: + addbyte(0xf3); /*MOVQ XMM5, xmm_ff_w*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x2d); + addlong(&xmm_ff_w); + addbyte(0x66); /*PSUBW XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xe8); + addbyte(0x66); /*PMULLW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xe5); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + break; + case AFUNC_AOMDST_ALPHA: + addbyte(0x66); /*PXOR XMM4, XMM4*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xe4); + break; + case AFUNC_ASATURATE: + addbyte(0x66); /*PMULLW XMM4, minus_254*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x25); + addlong(&minus_254); + addbyte(0xf3); /*MOVQ XMM5, XMM4*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xec); + addbyte(0x66); /*PADDW XMM4, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x25); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM4, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xe5); + addbyte(0x66); /*PSRLW XMM4, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd4); + addbyte(8); + } + + switch (src_afunc) + { + case AFUNC_AZERO: + addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc0); + break; + case AFUNC_ASRC_ALPHA: + addbyte(0x66); /*PMULLW XMM0, alookup[EDX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x04); + addbyte(0xd5); + addlong(alookup); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x05); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + break; + case AFUNC_A_COLOR: + addbyte(0x66); /*PMULLW XMM0, XMM6*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xc6); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x05); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + break; + case AFUNC_ADST_ALPHA: + break; + case AFUNC_AONE: + break; + case AFUNC_AOMSRC_ALPHA: + addbyte(0x66); /*PMULLW XMM0, aminuslookup[EDX*8]*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0x04); + addbyte(0xd5); + addlong(aminuslookup); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x05); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + break; + case AFUNC_AOM_COLOR: + addbyte(0xf3); /*MOVQ XMM5, xmm_ff_w*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x2d); + addlong(&xmm_ff_w); + addbyte(0x66); /*PSUBW XMM5, XMM6*/ + addbyte(0x0f); + addbyte(0xf9); + addbyte(0xee); + addbyte(0x66); /*PMULLW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xd5); + addbyte(0xc5); + addbyte(0xf3); /*MOVQ XMM5, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xe8); + addbyte(0x66); /*PADDW XMM0, alookup[1*8]*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0x05); + addlong((uint32_t)alookup + 16); + addbyte(0x66); /*PSRLW XMM5, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd5); + addbyte(8); + addbyte(0x66); /*PADDW XMM0, XMM5*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc5); + addbyte(0x66); /*PSRLW XMM0, 8*/ + addbyte(0x0f); + addbyte(0x71); + addbyte(0xd0); + addbyte(8); + break; + case AFUNC_AOMDST_ALPHA: + addbyte(0x66); /*PXOR XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0xef); + addbyte(0xc0); + break; + case AFUNC_ACOLORBEFOREFOG: + break; + } + + addbyte(0x66); /*PADDW XMM0, XMM4*/ + addbyte(0x0f); + addbyte(0xfd); + addbyte(0xc4); + + addbyte(0x66); /*PACKUSWB XMM0, XMM0*/ + addbyte(0x0f); + addbyte(0x67); + addbyte(0xc0); + } +//#endif + +// addbyte(0x8b); /*MOV EDX, x (ESP+12)*/ +// addbyte(0x54); +// addbyte(0x24); +// addbyte(12); + + + addbyte(0x8b); /*MOV EDX, state->x[EDI]*/ + addbyte(0x97); + addlong(offsetof(voodoo_state_t, x)); + + addbyte(0x66); /*MOV EAX, XMM0*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xc0); + + if (params->fbzMode & FBZ_RGB_WMASK) + { +// addbyte(0x89); /*MOV state->rgb_out[EDI], EAX*/ +// addbyte(0x87); +// addlong(offsetof(voodoo_state_t, rgb_out)); + + if (dither) + { + addbyte(0x8b); /*MOV ESI, real_y (ESP+16)*/ + addbyte(0x74); + addbyte(0x24); + addbyte(16+16); + addbyte(0x0f); /*MOVZX EBX, AH*/ /*G*/ + addbyte(0xb6); + addbyte(0xdc); + if (dither2x2) + { + addbyte(0x83); /*AND EDX, 1*/ + addbyte(0xe2); + addbyte(1); + addbyte(0x83); /*AND ESI, 1*/ + addbyte(0xe6); + addbyte(1); + addbyte(0xc1); /*SHL EBX, 2*/ + addbyte(0xe3); + addbyte(2); + } + else + { + addbyte(0x83); /*AND EDX, 3*/ + addbyte(0xe2); + addbyte(3); + addbyte(0x83); /*AND ESI, 3*/ + addbyte(0xe6); + addbyte(3); + addbyte(0xc1); /*SHL EBX, 4*/ + addbyte(0xe3); + addbyte(4); + } + addbyte(0x0f); /*MOVZX ECX, AL*/ /*R*/ + addbyte(0xb6); + addbyte(0xc8); + if (dither2x2) + { + addbyte(0xc1); /*SHR EAX, 14*/ + addbyte(0xe8); + addbyte(14); + addbyte(0x8d); /*LEA ESI, EDX+ESI*2*/ + addbyte(0x34); + addbyte(0x72); + } + else + { + addbyte(0xc1); /*SHR EAX, 12*/ + addbyte(0xe8); + addbyte(12); + addbyte(0x8d); /*LEA ESI, EDX+ESI*4*/ + addbyte(0x34); + addbyte(0xb2); + } + addbyte(0x8b); /*MOV EDX, state->x[EDI]*/ + addbyte(0x97); + addlong(offsetof(voodoo_state_t, x)); + if (dither2x2) + { + addbyte(0xc1); /*SHL ECX, 2*/ + addbyte(0xe1); + addbyte(2); + addbyte(0x25); /*AND EAX, 0x3fc*/ /*B*/ + addlong(0x3fc); + } + else + { + addbyte(0xc1); /*SHL ECX, 4*/ + addbyte(0xe1); + addbyte(4); + addbyte(0x25); /*AND EAX, 0xff0*/ /*B*/ + addlong(0xff0); + } + addbyte(0x0f); /*MOVZX EBX, dither_g[EBX+ESI]*/ + addbyte(0xb6); + addbyte(0x9c); + addbyte(0x33); + addlong(dither2x2 ? dither_g2x2 : dither_g); + addbyte(0x0f); /*MOVZX ECX, dither_rb[ECX+ESI]*/ + addbyte(0xb6); + addbyte(0x8c); + addbyte(0x31); + addlong(dither2x2 ? dither_rb2x2 : dither_rb); + addbyte(0x0f); /*MOVZX EAX, dither_rb[EAX+ESI]*/ + addbyte(0xb6); + addbyte(0x84); + addbyte(0x30); + addlong(dither2x2 ? dither_rb2x2 : dither_rb); + addbyte(0xc1); /*SHL EBX, 5*/ + addbyte(0xe3); + addbyte(5); + addbyte(0xc1); /*SHL EAX, 11*/ + addbyte(0xe0); + addbyte(11); + addbyte(0x09); /*OR EAX, EBX*/ + addbyte(0xd8); + addbyte(0x09); /*OR EAX, ECX*/ + addbyte(0xc8); + } + else + { + addbyte(0x89); /*MOV EBX, EAX*/ + addbyte(0xc3); + addbyte(0x0f); /*MOVZX ECX, AH*/ + addbyte(0xb6); + addbyte(0xcc); + addbyte(0xc1); /*SHR EAX, 3*/ + addbyte(0xe8); + addbyte(3); + addbyte(0xc1); /*SHR EBX, 8*/ + addbyte(0xeb); + addbyte(8); + addbyte(0xc1); /*SHL ECX, 3*/ + addbyte(0xe1); + addbyte(3); + addbyte(0x81); /*AND EAX, 0x001f*/ + addbyte(0xe0); + addlong(0x001f); + addbyte(0x81); /*AND EBX, 0xf800*/ + addbyte(0xe3); + addlong(0xf800); + addbyte(0x81); /*AND ECX, 0x07e0*/ + addbyte(0xe1); + addlong(0x07e0); + addbyte(0x09); /*OR EAX, EBX*/ + addbyte(0xd8); + addbyte(0x09); /*OR EAX, ECX*/ + addbyte(0xc8); + } + addbyte(0x8b); /*MOV ESI, fb_mem*/ + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, fb_mem)); + addbyte(0x66); /*MOV [ESI+EDX*2], AX*/ + addbyte(0x89); + addbyte(0x04); + addbyte(0x56); + } + + if (params->fbzMode & FBZ_DEPTH_WMASK) + { + addbyte(0x66); /*MOV AX, new_depth*/ + addbyte(0x8b); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, new_depth)); + addbyte(0x8b); /*MOV ESI, aux_mem*/ + addbyte(0xb7); + addlong(offsetof(voodoo_state_t, aux_mem)); + addbyte(0x66); /*MOV [ESI+EDX*2], AX*/ + addbyte(0x89); + addbyte(0x04); + addbyte(0x56); + } + + if (z_skip_pos) + *(uint32_t *)&code_block[z_skip_pos] = (block_pos - z_skip_pos) - 4; + if (a_skip_pos) + *(uint32_t *)&code_block[a_skip_pos] = (block_pos - a_skip_pos) - 4; + if (chroma_skip_pos) + *(uint32_t *)&code_block[chroma_skip_pos] = (block_pos - chroma_skip_pos) - 4; + + + addbyte(0x8b); /*MOV ESI, [ESP+8]*/ + addbyte(0x74); + addbyte(0x24); + addbyte(8+16); + + addbyte(0xf3); /*MOVDQU XMM1, state->ib[EDI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0xf3); /*MOVDQU XMM3, state->tmu0_s[EDI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tmu0_s)); + addbyte(0xf3); /*MOVQ XMM4, state->tmu0_w[EDI]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, tmu0_w)); + addbyte(0xf3); /*MOVDQU XMM0, params->dBdX[ESI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0x86); + addlong(offsetof(voodoo_params_t, dBdX)); + addbyte(0x8b); /*MOV EAX, params->dZdX[ESI]*/ + addbyte(0x86); + addlong(offsetof(voodoo_params_t, dZdX)); + addbyte(0xf3); /*MOVDQU XMM5, params->tmu[0].dSdX[ESI]*/ + addbyte(0x0f); + addbyte(0x6f); + addbyte(0xae); + addlong(offsetof(voodoo_params_t, tmu[0].dSdX)); + addbyte(0xf3); /*MOVQ XMM6, params->tmu[0].dWdX[ESI]*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xb6); + addlong(offsetof(voodoo_params_t, tmu[0].dWdX)); + + if (state->xdir > 0) + { + addbyte(0x66); /*PADDD XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0xfe); + addbyte(0xc8); + } + else + { + addbyte(0x66); /*PSUBD XMM1, XMM0*/ + addbyte(0x0f); + addbyte(0xfa); + addbyte(0xc8); + } + + addbyte(0xf3); /*MOVQ XMM0, state->w*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w)); + addbyte(0xf3); /*MOVDQU state->ib, XMM1*/ + addbyte(0x0f); + addbyte(0x7f); + addbyte(0x8f); + addlong(offsetof(voodoo_state_t, ib)); + addbyte(0xf3); /*MOVQ XMM7, params->dWdX*/ + addbyte(0x0f); + addbyte(0x7e); + addbyte(0xbe); + addlong(offsetof(voodoo_params_t, dWdX)); + + if (state->xdir > 0) + { + addbyte(0x66); /*PADDQ XMM3, XMM5*/ + addbyte(0x0f); + addbyte(0xd4); + addbyte(0xdd); + addbyte(0x66); /*PADDQ XMM4, XMM6*/ + addbyte(0x0f); + addbyte(0xd4); + addbyte(0xe6); + addbyte(0x66); /*PADDQ XMM0, XMM7*/ + addbyte(0x0f); + addbyte(0xd4); + addbyte(0xc7); + addbyte(0x01); /*ADD state->z[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, z)); + } + else + { + addbyte(0x66); /*PSUBQ XMM3, XMM5*/ + addbyte(0x0f); + addbyte(0xfb); + addbyte(0xdd); + addbyte(0x66); /*PSUBQ XMM4, XMM6*/ + addbyte(0x0f); + addbyte(0xfb); + addbyte(0xe6); + addbyte(0x66); /*PSUBQ XMM0, XMM7*/ + addbyte(0x0f); + addbyte(0xfb); + addbyte(0xc7); + addbyte(0x29); /*SUB state->z[EDI], EAX*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, z)); + } + + addbyte(0xf3); /*MOVDQU state->tmu0_s, XMM3*/ + addbyte(0x0f); + addbyte(0x7f); + addbyte(0x9f); + addlong(offsetof(voodoo_state_t, tmu0_s)); + addbyte(0x66); /*MOVQ state->tmu0_w, XMM4*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0xa7); + addlong(offsetof(voodoo_state_t, tmu0_w)); + addbyte(0x66); /*MOVQ state->w, XMM0*/ + addbyte(0x0f); + addbyte(0xd6); + addbyte(0x87); + addlong(offsetof(voodoo_state_t, w)); + + addbyte(0x83); /*ADD state->pixel_count[EDI], 1*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, pixel_count)); + addbyte(1); + + addbyte(0x8b); /*MOV EAX, state->x[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x)); + + if (state->xdir > 0) + { + addbyte(0x83); /*ADD state->x[EDI], 1*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x)); + addbyte(1); + } + else + { + addbyte(0x83); /*SUB state->x[EDI], 1*/ + addbyte(0xaf); + addlong(offsetof(voodoo_state_t, x)); + addbyte(1); + } + + addbyte(0x3b); /*CMP EAX, state->x2[EDI]*/ + addbyte(0x87); + addlong(offsetof(voodoo_state_t, x2)); + addbyte(0x0f); /*JNZ loop_jump_pos*/ + addbyte(0x85); + addlong(loop_jump_pos - (block_pos + 4)); + + addbyte(0x5b); /*POP EBX*/ + addbyte(0x5e); /*POP ESI*/ + addbyte(0x5f); /*POP EDI*/ + addbyte(0x5d); /*POP EBP*/ + + addbyte(0xC3); /*RET*/ +} +static int voodoo_recomp = 0; +static inline void *voodoo_get_block(voodoo_t *voodoo, voodoo_params_t *params, voodoo_state_t *state, int odd_even) +{ + int c; + int b = last_block[odd_even]; + voodoo_x86_data_t *data; + voodoo_x86_data_t *codegen_data = voodoo->codegen_data; + + for (c = 0; c < 8; c++) + { + data = &codegen_data[odd_even + b*2]; + + if (state->xdir == data->xdir && + params->alphaMode == data->alphaMode && + params->fbzMode == data->fbzMode && + params->fogMode == data->fogMode && + params->fbzColorPath == data->fbzColorPath && + (voodoo->trexInit1 & (1 << 18)) == data->trexInit1 && + params->textureMode == data->textureMode) + { + last_block[odd_even] = b; + return data->code_block; + } + + b = (b + 1) & 7; + } +voodoo_recomp++; + data = &codegen_data[odd_even + next_block_to_write[odd_even]*2]; +// code_block = data->code_block; + + voodoo_generate(data->code_block, voodoo, params, state, depth_op); + + data->xdir = state->xdir; + data->alphaMode = params->alphaMode; + data->fbzMode = params->fbzMode; + data->fogMode = params->fogMode; + data->fbzColorPath = params->fbzColorPath; + data->trexInit1 = voodoo->trexInit1 & (1 << 18); + data->textureMode = params->textureMode; + + next_block_to_write[odd_even] = (next_block_to_write[odd_even] + 1) & 7; + + return data->code_block; +} + +static void voodoo_codegen_init(voodoo_t *voodoo) +{ + int c; +#ifdef __linux__ + void *start; + size_t len; + long pagesize = sysconf(_SC_PAGESIZE); + long pagemask = ~(pagesize - 1); +#endif + +#if defined WIN32 || defined _WIN32 || defined _WIN32 + voodoo->codegen_data = VirtualAlloc(NULL, sizeof(voodoo_x86_data_t) * BLOCK_NUM*2, MEM_COMMIT, PAGE_EXECUTE_READWRITE); +#else + voodoo->codegen_data = malloc(sizeof(voodoo_x86_data_t) * BLOCK_NUM*2); +#endif + +#ifdef __linux__ + start = (void *)((long)voodoo->codegen_data & pagemask); + len = ((sizeof(voodoo_x86_data_t) * BLOCK_NUM) + pagesize) & pagemask; + if (mprotect(start, len, PROT_READ | PROT_WRITE | PROT_EXEC) != 0) + { + perror("mprotect"); + exit(-1); + } +#endif + + for (c = 0; c < 256; c++) + { + int d[4]; + int _ds = c & 0xf; + int dt = c >> 4; + + alookup[c] = _mm_set_epi32(0, 0, c | (c << 16), c | (c << 16)); + aminuslookup[c] = _mm_set_epi32(0, 0, (255-c) | ((255-c) << 16), (255-c) | ((255-c) << 16)); + + d[0] = (16 - _ds) * (16 - dt); + d[1] = _ds * (16 - dt); + d[2] = (16 - _ds) * dt; + d[3] = _ds * dt; + + bilinear_lookup[c*4] = _mm_set_epi32(0, 0, d[0] | (d[0] << 16), d[0] | (d[0] << 16)); + bilinear_lookup[c*4 + 1] = _mm_set_epi32(0, 0, d[1] | (d[1] << 16), d[1] | (d[1] << 16)); + bilinear_lookup[c*4 + 2] = _mm_set_epi32(0, 0, d[2] | (d[2] << 16), d[2] | (d[2] << 16)); + bilinear_lookup[c*4 + 3] = _mm_set_epi32(0, 0, d[3] | (d[3] << 16), d[3] | (d[3] << 16)); + } + alookup[256] = _mm_set_epi32(0, 0, 256 | (256 << 16), 256 | (256 << 16)); +} + +static void voodoo_codegen_close(voodoo_t *voodoo) +{ +#if defined WIN32 || defined _WIN32 || defined _WIN32 + VirtualFree(voodoo->codegen_data, 0, MEM_RELEASE); +#else + free(voodoo->codegen_data); +#endif +} diff --git a/src/vid_voodoo_dither.h b/src/vid_voodoo_dither.h new file mode 100644 index 000000000..21baf772b --- /dev/null +++ b/src/vid_voodoo_dither.h @@ -0,0 +1,5136 @@ +uint8_t dither_rb[256][4][4] = +{ + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + }, + { + {0, 0, 0, 0}, + {0, 0, 1, 0}, + {0, 0, 0, 0}, + {1, 0, 0, 0}, + }, + { + {0, 0, 0, 0}, + {1, 0, 1, 0}, + {0, 0, 0, 0}, + {1, 0, 1, 0}, + }, + { + {0, 0, 0, 1}, + {1, 0, 1, 0}, + {0, 1, 0, 0}, + {1, 0, 1, 0}, + }, + { + {0, 1, 0, 1}, + {1, 0, 1, 0}, + {0, 1, 0, 1}, + {1, 0, 1, 0}, + }, + { + {0, 1, 0, 1}, + {1, 0, 1, 1}, + {0, 1, 0, 1}, + {1, 1, 1, 0}, + }, + { + {0, 1, 0, 1}, + {1, 1, 1, 1}, + {0, 1, 0, 1}, + {1, 1, 1, 1}, + }, + { + {0, 1, 1, 1}, + {1, 1, 1, 1}, + {1, 1, 0, 1}, + {1, 1, 1, 1}, + }, + { + {1, 1, 1, 1}, + {1, 1, 1, 1}, + {1, 1, 1, 1}, + {1, 1, 1, 1}, + }, + { + {1, 1, 1, 1}, + {1, 1, 2, 1}, + {1, 1, 1, 1}, + {2, 1, 1, 1}, + }, + { + {1, 1, 1, 1}, + {2, 1, 2, 1}, + {1, 1, 1, 1}, + {2, 1, 2, 1}, + }, + { + {1, 1, 1, 2}, + {2, 1, 2, 1}, + {1, 2, 1, 1}, + {2, 1, 2, 1}, + }, + { + {1, 2, 1, 2}, + {2, 1, 2, 1}, + {1, 2, 1, 2}, + {2, 1, 2, 1}, + }, + { + {1, 2, 1, 2}, + {2, 1, 2, 2}, + {1, 2, 1, 2}, + {2, 2, 2, 1}, + }, + { + {1, 2, 1, 2}, + {2, 2, 2, 2}, + {1, 2, 1, 2}, + {2, 2, 2, 2}, + }, + { + {1, 2, 2, 2}, + {2, 2, 2, 2}, + {2, 2, 1, 2}, + {2, 2, 2, 2}, + }, + { + {1, 2, 2, 2}, + {2, 2, 2, 2}, + {2, 2, 2, 2}, + {2, 2, 2, 2}, + }, + { + {2, 2, 2, 2}, + {2, 2, 2, 2}, + {2, 2, 2, 2}, + {3, 2, 2, 2}, + }, + { + {2, 2, 2, 2}, + {2, 2, 3, 2}, + {2, 2, 2, 2}, + {3, 2, 3, 2}, + }, + { + {2, 2, 2, 2}, + {3, 2, 3, 2}, + {2, 3, 2, 2}, + {3, 2, 3, 2}, + }, + { + {2, 2, 2, 3}, + {3, 2, 3, 2}, + {2, 3, 2, 3}, + {3, 2, 3, 2}, + }, + { + {2, 3, 2, 3}, + {3, 2, 3, 2}, + {2, 3, 2, 3}, + {3, 3, 3, 2}, + }, + { + {2, 3, 2, 3}, + {3, 2, 3, 3}, + {2, 3, 2, 3}, + {3, 3, 3, 3}, + }, + { + {2, 3, 2, 3}, + {3, 3, 3, 3}, + {3, 3, 2, 3}, + {3, 3, 3, 3}, + }, + { + {2, 3, 3, 3}, + {3, 3, 3, 3}, + {3, 3, 3, 3}, + {3, 3, 3, 3}, + }, + { + {3, 3, 3, 3}, + {3, 3, 3, 3}, + {3, 3, 3, 3}, + {4, 3, 3, 3}, + }, + { + {3, 3, 3, 3}, + {3, 3, 4, 3}, + {3, 3, 3, 3}, + {4, 3, 4, 3}, + }, + { + {3, 3, 3, 3}, + {4, 3, 4, 3}, + {3, 4, 3, 3}, + {4, 3, 4, 3}, + }, + { + {3, 3, 3, 4}, + {4, 3, 4, 3}, + {3, 4, 3, 4}, + {4, 3, 4, 3}, + }, + { + {3, 4, 3, 4}, + {4, 3, 4, 3}, + {3, 4, 3, 4}, + {4, 4, 4, 3}, + }, + { + {3, 4, 3, 4}, + {4, 3, 4, 4}, + {3, 4, 3, 4}, + {4, 4, 4, 4}, + }, + { + {3, 4, 3, 4}, + {4, 4, 4, 4}, + {4, 4, 3, 4}, + {4, 4, 4, 4}, + }, + { + {3, 4, 4, 4}, + {4, 4, 4, 4}, + {4, 4, 3, 4}, + {4, 4, 4, 4}, + }, + { + {4, 4, 4, 4}, + {4, 4, 4, 4}, + {4, 4, 4, 4}, + {4, 4, 4, 4}, + }, + { + {4, 4, 4, 4}, + {4, 4, 5, 4}, + {4, 4, 4, 4}, + {5, 4, 4, 4}, + }, + { + {4, 4, 4, 4}, + {5, 4, 5, 4}, + {4, 4, 4, 4}, + {5, 4, 5, 4}, + }, + { + {4, 4, 4, 5}, + {5, 4, 5, 4}, + {4, 5, 4, 4}, + {5, 4, 5, 4}, + }, + { + {4, 5, 4, 5}, + {5, 4, 5, 4}, + {4, 5, 4, 5}, + {5, 4, 5, 4}, + }, + { + {4, 5, 4, 5}, + {5, 4, 5, 5}, + {4, 5, 4, 5}, + {5, 5, 5, 4}, + }, + { + {4, 5, 4, 5}, + {5, 5, 5, 5}, + {4, 5, 4, 5}, + {5, 5, 5, 5}, + }, + { + {4, 5, 5, 5}, + {5, 5, 5, 5}, + {5, 5, 4, 5}, + {5, 5, 5, 5}, + }, + { + {5, 5, 5, 5}, + {5, 5, 5, 5}, + {5, 5, 5, 5}, + {5, 5, 5, 5}, + }, + { + {5, 5, 5, 5}, + {5, 5, 6, 5}, + {5, 5, 5, 5}, + {6, 5, 5, 5}, + }, + { + {5, 5, 5, 5}, + {6, 5, 6, 5}, + {5, 5, 5, 5}, + {6, 5, 6, 5}, + }, + { + {5, 5, 5, 6}, + {6, 5, 6, 5}, + {5, 6, 5, 5}, + {6, 5, 6, 5}, + }, + { + {5, 6, 5, 6}, + {6, 5, 6, 5}, + {5, 6, 5, 6}, + {6, 5, 6, 5}, + }, + { + {5, 6, 5, 6}, + {6, 5, 6, 6}, + {5, 6, 5, 6}, + {6, 6, 6, 5}, + }, + { + {5, 6, 5, 6}, + {6, 6, 6, 6}, + {5, 6, 5, 6}, + {6, 6, 6, 6}, + }, + { + {5, 6, 5, 6}, + {6, 6, 6, 6}, + {6, 6, 5, 6}, + {6, 6, 6, 6}, + }, + { + {5, 6, 6, 6}, + {6, 6, 6, 6}, + {6, 6, 6, 6}, + {6, 6, 6, 6}, + }, + { + {6, 6, 6, 6}, + {6, 6, 6, 6}, + {6, 6, 6, 6}, + {7, 6, 6, 6}, + }, + { + {6, 6, 6, 6}, + {6, 6, 7, 6}, + {6, 6, 6, 6}, + {7, 6, 7, 6}, + }, + { + {6, 6, 6, 6}, + {7, 6, 7, 6}, + {6, 7, 6, 6}, + {7, 6, 7, 6}, + }, + { + {6, 6, 6, 7}, + {7, 6, 7, 6}, + {6, 7, 6, 7}, + {7, 6, 7, 6}, + }, + { + {6, 7, 6, 7}, + {7, 6, 7, 6}, + {6, 7, 6, 7}, + {7, 7, 7, 6}, + }, + { + {6, 7, 6, 7}, + {7, 6, 7, 7}, + {6, 7, 6, 7}, + {7, 7, 7, 7}, + }, + { + {6, 7, 6, 7}, + {7, 7, 7, 7}, + {7, 7, 6, 7}, + {7, 7, 7, 7}, + }, + { + {6, 7, 7, 7}, + {7, 7, 7, 7}, + {7, 7, 7, 7}, + {7, 7, 7, 7}, + }, + { + {7, 7, 7, 7}, + {7, 7, 7, 7}, + {7, 7, 7, 7}, + {8, 7, 7, 7}, + }, + { + {7, 7, 7, 7}, + {7, 7, 8, 7}, + {7, 7, 7, 7}, + {8, 7, 8, 7}, + }, + { + {7, 7, 7, 7}, + {8, 7, 8, 7}, + {7, 8, 7, 7}, + {8, 7, 8, 7}, + }, + { + {7, 7, 7, 8}, + {8, 7, 8, 7}, + {7, 8, 7, 8}, + {8, 7, 8, 7}, + }, + { + {7, 8, 7, 8}, + {8, 7, 8, 7}, + {7, 8, 7, 8}, + {8, 8, 8, 7}, + }, + { + {7, 8, 7, 8}, + {8, 7, 8, 8}, + {7, 8, 7, 8}, + {8, 8, 8, 8}, + }, + { + {7, 8, 7, 8}, + {8, 8, 8, 8}, + {7, 8, 7, 8}, + {8, 8, 8, 8}, + }, + { + {7, 8, 8, 8}, + {8, 8, 8, 8}, + {8, 8, 7, 8}, + {8, 8, 8, 8}, + }, + { + {8, 8, 8, 8}, + {8, 8, 8, 8}, + {8, 8, 8, 8}, + {8, 8, 8, 8}, + }, + { + {8, 8, 8, 8}, + {8, 8, 9, 8}, + {8, 8, 8, 8}, + {9, 8, 8, 8}, + }, + { + {8, 8, 8, 8}, + {9, 8, 9, 8}, + {8, 8, 8, 8}, + {9, 8, 9, 8}, + }, + { + {8, 8, 8, 9}, + {9, 8, 9, 8}, + {8, 9, 8, 8}, + {9, 8, 9, 8}, + }, + { + {8, 9, 8, 9}, + {9, 8, 9, 8}, + {8, 9, 8, 9}, + {9, 8, 9, 8}, + }, + { + {8, 9, 8, 9}, + {9, 8, 9, 9}, + {8, 9, 8, 9}, + {9, 9, 9, 8}, + }, + { + {8, 9, 8, 9}, + {9, 9, 9, 9}, + {8, 9, 8, 9}, + {9, 9, 9, 9}, + }, + { + {8, 9, 9, 9}, + {9, 9, 9, 9}, + {9, 9, 8, 9}, + {9, 9, 9, 9}, + }, + { + {9, 9, 9, 9}, + {9, 9, 9, 9}, + {9, 9, 9, 9}, + {9, 9, 9, 9}, + }, + { + {9, 9, 9, 9}, + {9, 9, 10, 9}, + {9, 9, 9, 9}, + {10, 9, 9, 9}, + }, + { + {9, 9, 9, 9}, + {10, 9, 10, 9}, + {9, 9, 9, 9}, + {10, 9, 10, 9}, + }, + { + {9, 9, 9, 10}, + {10, 9, 10, 9}, + {9, 10, 9, 9}, + {10, 9, 10, 9}, + }, + { + {9, 10, 9, 10}, + {10, 9, 10, 9}, + {9, 10, 9, 10}, + {10, 9, 10, 9}, + }, + { + {9, 10, 9, 10}, + {10, 9, 10, 10}, + {9, 10, 9, 10}, + {10, 10, 10, 9}, + }, + { + {9, 10, 9, 10}, + {10, 9, 10, 10}, + {9, 10, 9, 10}, + {10, 10, 10, 10}, + }, + { + {9, 10, 9, 10}, + {10, 10, 10, 10}, + {10, 10, 9, 10}, + {10, 10, 10, 10}, + }, + { + {9, 10, 10, 10}, + {10, 10, 10, 10}, + {10, 10, 10, 10}, + {10, 10, 10, 10}, + }, + { + {10, 10, 10, 10}, + {10, 10, 10, 10}, + {10, 10, 10, 10}, + {11, 10, 10, 10}, + }, + { + {10, 10, 10, 10}, + {10, 10, 11, 10}, + {10, 10, 10, 10}, + {11, 10, 11, 10}, + }, + { + {10, 10, 10, 10}, + {11, 10, 11, 10}, + {10, 11, 10, 10}, + {11, 10, 11, 10}, + }, + { + {10, 10, 10, 11}, + {11, 10, 11, 10}, + {10, 11, 10, 11}, + {11, 10, 11, 10}, + }, + { + {10, 11, 10, 11}, + {11, 10, 11, 10}, + {10, 11, 10, 11}, + {11, 11, 11, 10}, + }, + { + {10, 11, 10, 11}, + {11, 10, 11, 11}, + {10, 11, 10, 11}, + {11, 11, 11, 11}, + }, + { + {10, 11, 10, 11}, + {11, 11, 11, 11}, + {11, 11, 10, 11}, + {11, 11, 11, 11}, + }, + { + {10, 11, 11, 11}, + {11, 11, 11, 11}, + {11, 11, 11, 11}, + {11, 11, 11, 11}, + }, + { + {11, 11, 11, 11}, + {11, 11, 11, 11}, + {11, 11, 11, 11}, + {12, 11, 11, 11}, + }, + { + {11, 11, 11, 11}, + {11, 11, 12, 11}, + {11, 11, 11, 11}, + {12, 11, 12, 11}, + }, + { + {11, 11, 11, 11}, + {12, 11, 12, 11}, + {11, 12, 11, 11}, + {12, 11, 12, 11}, + }, + { + {11, 11, 11, 12}, + {12, 11, 12, 11}, + {11, 12, 11, 12}, + {12, 11, 12, 11}, + }, + { + {11, 12, 11, 12}, + {12, 11, 12, 11}, + {11, 12, 11, 12}, + {12, 12, 12, 11}, + }, + { + {11, 12, 11, 12}, + {12, 11, 12, 12}, + {11, 12, 11, 12}, + {12, 12, 12, 11}, + }, + { + {11, 12, 11, 12}, + {12, 12, 12, 12}, + {11, 12, 11, 12}, + {12, 12, 12, 12}, + }, + { + {11, 12, 12, 12}, + {12, 12, 12, 12}, + {12, 12, 11, 12}, + {12, 12, 12, 12}, + }, + { + {12, 12, 12, 12}, + {12, 12, 12, 12}, + {12, 12, 12, 12}, + {12, 12, 12, 12}, + }, + { + {12, 12, 12, 12}, + {12, 12, 13, 12}, + {12, 12, 12, 12}, + {13, 12, 12, 12}, + }, + { + {12, 12, 12, 12}, + {13, 12, 13, 12}, + {12, 12, 12, 12}, + {13, 12, 13, 12}, + }, + { + {12, 12, 12, 13}, + {13, 12, 13, 12}, + {12, 13, 12, 12}, + {13, 12, 13, 12}, + }, + { + {12, 13, 12, 13}, + {13, 12, 13, 12}, + {12, 13, 12, 13}, + {13, 12, 13, 12}, + }, + { + {12, 13, 12, 13}, + {13, 12, 13, 13}, + {12, 13, 12, 13}, + {13, 13, 13, 12}, + }, + { + {12, 13, 12, 13}, + {13, 13, 13, 13}, + {12, 13, 12, 13}, + {13, 13, 13, 13}, + }, + { + {12, 13, 13, 13}, + {13, 13, 13, 13}, + {13, 13, 12, 13}, + {13, 13, 13, 13}, + }, + { + {13, 13, 13, 13}, + {13, 13, 13, 13}, + {13, 13, 13, 13}, + {13, 13, 13, 13}, + }, + { + {13, 13, 13, 13}, + {13, 13, 14, 13}, + {13, 13, 13, 13}, + {14, 13, 13, 13}, + }, + { + {13, 13, 13, 13}, + {14, 13, 14, 13}, + {13, 13, 13, 13}, + {14, 13, 14, 13}, + }, + { + {13, 13, 13, 14}, + {14, 13, 14, 13}, + {13, 14, 13, 13}, + {14, 13, 14, 13}, + }, + { + {13, 14, 13, 14}, + {14, 13, 14, 13}, + {13, 14, 13, 14}, + {14, 13, 14, 13}, + }, + { + {13, 14, 13, 14}, + {14, 13, 14, 13}, + {13, 14, 13, 14}, + {14, 14, 14, 13}, + }, + { + {13, 14, 13, 14}, + {14, 13, 14, 14}, + {13, 14, 13, 14}, + {14, 14, 14, 14}, + }, + { + {13, 14, 13, 14}, + {14, 14, 14, 14}, + {14, 14, 13, 14}, + {14, 14, 14, 14}, + }, + { + {13, 14, 14, 14}, + {14, 14, 14, 14}, + {14, 14, 14, 14}, + {14, 14, 14, 14}, + }, + { + {14, 14, 14, 14}, + {14, 14, 14, 14}, + {14, 14, 14, 14}, + {15, 14, 14, 14}, + }, + { + {14, 14, 14, 14}, + {14, 14, 15, 14}, + {14, 14, 14, 14}, + {15, 14, 15, 14}, + }, + { + {14, 14, 14, 14}, + {15, 14, 15, 14}, + {14, 15, 14, 14}, + {15, 14, 15, 14}, + }, + { + {14, 14, 14, 15}, + {15, 14, 15, 14}, + {14, 15, 14, 15}, + {15, 14, 15, 14}, + }, + { + {14, 15, 14, 15}, + {15, 14, 15, 14}, + {14, 15, 14, 15}, + {15, 15, 15, 14}, + }, + { + {14, 15, 14, 15}, + {15, 14, 15, 15}, + {14, 15, 14, 15}, + {15, 15, 15, 15}, + }, + { + {14, 15, 14, 15}, + {15, 15, 15, 15}, + {15, 15, 14, 15}, + {15, 15, 15, 15}, + }, + { + {14, 15, 15, 15}, + {15, 15, 15, 15}, + {15, 15, 15, 15}, + {15, 15, 15, 15}, + }, + { + {15, 15, 15, 15}, + {15, 15, 15, 15}, + {15, 15, 15, 15}, + {16, 15, 15, 15}, + }, + { + {15, 15, 15, 15}, + {15, 15, 16, 15}, + {15, 15, 15, 15}, + {16, 15, 16, 15}, + }, + { + {15, 15, 15, 15}, + {16, 15, 16, 15}, + {15, 16, 15, 15}, + {16, 15, 16, 15}, + }, + { + {15, 15, 15, 16}, + {16, 15, 16, 15}, + {15, 16, 15, 16}, + {16, 15, 16, 15}, + }, + { + {15, 16, 15, 16}, + {16, 15, 16, 15}, + {15, 16, 15, 16}, + {16, 16, 16, 15}, + }, + { + {15, 16, 15, 16}, + {16, 15, 16, 16}, + {15, 16, 15, 16}, + {16, 16, 16, 16}, + }, + { + {15, 16, 15, 16}, + {16, 16, 16, 16}, + {16, 16, 15, 16}, + {16, 16, 16, 16}, + }, + { + {15, 16, 16, 16}, + {16, 16, 16, 16}, + {16, 16, 16, 16}, + {16, 16, 16, 16}, + }, + { + {16, 16, 16, 16}, + {16, 16, 16, 16}, + {16, 16, 16, 16}, + {17, 16, 16, 16}, + }, + { + {16, 16, 16, 16}, + {16, 16, 17, 16}, + {16, 16, 16, 16}, + {17, 16, 17, 16}, + }, + { + {16, 16, 16, 16}, + {17, 16, 17, 16}, + {16, 17, 16, 16}, + {17, 16, 17, 16}, + }, + { + {16, 16, 16, 17}, + {17, 16, 17, 16}, + {16, 17, 16, 17}, + {17, 16, 17, 16}, + }, + { + {16, 17, 16, 17}, + {17, 16, 17, 16}, + {16, 17, 16, 17}, + {17, 17, 17, 16}, + }, + { + {16, 17, 16, 17}, + {17, 16, 17, 17}, + {16, 17, 16, 17}, + {17, 17, 17, 17}, + }, + { + {16, 17, 16, 17}, + {17, 17, 17, 17}, + {17, 17, 16, 17}, + {17, 17, 17, 17}, + }, + { + {16, 17, 17, 17}, + {17, 17, 17, 17}, + {17, 17, 17, 17}, + {17, 17, 17, 17}, + }, + { + {17, 17, 17, 17}, + {17, 17, 17, 17}, + {17, 17, 17, 17}, + {18, 17, 17, 17}, + }, + { + {17, 17, 17, 17}, + {17, 17, 18, 17}, + {17, 17, 17, 17}, + {18, 17, 18, 17}, + }, + { + {17, 17, 17, 17}, + {18, 17, 18, 17}, + {17, 18, 17, 17}, + {18, 17, 18, 17}, + }, + { + {17, 17, 17, 18}, + {18, 17, 18, 17}, + {17, 18, 17, 18}, + {18, 17, 18, 17}, + }, + { + {17, 18, 17, 18}, + {18, 17, 18, 17}, + {17, 18, 17, 18}, + {18, 17, 18, 17}, + }, + { + {17, 18, 17, 18}, + {18, 17, 18, 18}, + {17, 18, 17, 18}, + {18, 18, 18, 17}, + }, + { + {17, 18, 17, 18}, + {18, 18, 18, 18}, + {17, 18, 17, 18}, + {18, 18, 18, 18}, + }, + { + {17, 18, 18, 18}, + {18, 18, 18, 18}, + {18, 18, 17, 18}, + {18, 18, 18, 18}, + }, + { + {18, 18, 18, 18}, + {18, 18, 18, 18}, + {18, 18, 18, 18}, + {18, 18, 18, 18}, + }, + { + {18, 18, 18, 18}, + {18, 18, 19, 18}, + {18, 18, 18, 18}, + {19, 18, 18, 18}, + }, + { + {18, 18, 18, 18}, + {19, 18, 19, 18}, + {18, 18, 18, 18}, + {19, 18, 19, 18}, + }, + { + {18, 18, 18, 19}, + {19, 18, 19, 18}, + {18, 19, 18, 18}, + {19, 18, 19, 18}, + }, + { + {18, 19, 18, 19}, + {19, 18, 19, 18}, + {18, 19, 18, 19}, + {19, 18, 19, 18}, + }, + { + {18, 19, 18, 19}, + {19, 18, 19, 19}, + {18, 19, 18, 19}, + {19, 19, 19, 18}, + }, + { + {18, 19, 18, 19}, + {19, 19, 19, 19}, + {18, 19, 18, 19}, + {19, 19, 19, 19}, + }, + { + {18, 19, 19, 19}, + {19, 19, 19, 19}, + {19, 19, 18, 19}, + {19, 19, 19, 19}, + }, + { + {19, 19, 19, 19}, + {19, 19, 19, 19}, + {19, 19, 19, 19}, + {19, 19, 19, 19}, + }, + { + {19, 19, 19, 19}, + {19, 19, 20, 19}, + {19, 19, 19, 19}, + {20, 19, 19, 19}, + }, + { + {19, 19, 19, 19}, + {20, 19, 20, 19}, + {19, 19, 19, 19}, + {20, 19, 20, 19}, + }, + { + {19, 19, 19, 20}, + {20, 19, 20, 19}, + {19, 20, 19, 19}, + {20, 19, 20, 19}, + }, + { + {19, 19, 19, 20}, + {20, 19, 20, 19}, + {19, 20, 19, 20}, + {20, 19, 20, 19}, + }, + { + {19, 20, 19, 20}, + {20, 19, 20, 19}, + {19, 20, 19, 20}, + {20, 20, 20, 19}, + }, + { + {19, 20, 19, 20}, + {20, 19, 20, 20}, + {19, 20, 19, 20}, + {20, 20, 20, 20}, + }, + { + {19, 20, 19, 20}, + {20, 20, 20, 20}, + {20, 20, 19, 20}, + {20, 20, 20, 20}, + }, + { + {19, 20, 20, 20}, + {20, 20, 20, 20}, + {20, 20, 20, 20}, + {20, 20, 20, 20}, + }, + { + {20, 20, 20, 20}, + {20, 20, 20, 20}, + {20, 20, 20, 20}, + {21, 20, 20, 20}, + }, + { + {20, 20, 20, 20}, + {20, 20, 21, 20}, + {20, 20, 20, 20}, + {21, 20, 21, 20}, + }, + { + {20, 20, 20, 20}, + {21, 20, 21, 20}, + {20, 21, 20, 20}, + {21, 20, 21, 20}, + }, + { + {20, 20, 20, 21}, + {21, 20, 21, 20}, + {20, 21, 20, 21}, + {21, 20, 21, 20}, + }, + { + {20, 21, 20, 21}, + {21, 20, 21, 20}, + {20, 21, 20, 21}, + {21, 21, 21, 20}, + }, + { + {20, 21, 20, 21}, + {21, 20, 21, 21}, + {20, 21, 20, 21}, + {21, 21, 21, 21}, + }, + { + {20, 21, 20, 21}, + {21, 21, 21, 21}, + {21, 21, 20, 21}, + {21, 21, 21, 21}, + }, + { + {20, 21, 21, 21}, + {21, 21, 21, 21}, + {21, 21, 21, 21}, + {21, 21, 21, 21}, + }, + { + {21, 21, 21, 21}, + {21, 21, 21, 21}, + {21, 21, 21, 21}, + {22, 21, 21, 21}, + }, + { + {21, 21, 21, 21}, + {21, 21, 22, 21}, + {21, 21, 21, 21}, + {22, 21, 22, 21}, + }, + { + {21, 21, 21, 21}, + {22, 21, 22, 21}, + {21, 22, 21, 21}, + {22, 21, 22, 21}, + }, + { + {21, 21, 21, 22}, + {22, 21, 22, 21}, + {21, 22, 21, 21}, + {22, 21, 22, 21}, + }, + { + {21, 22, 21, 22}, + {22, 21, 22, 21}, + {21, 22, 21, 22}, + {22, 21, 22, 21}, + }, + { + {21, 22, 21, 22}, + {22, 21, 22, 22}, + {21, 22, 21, 22}, + {22, 22, 22, 21}, + }, + { + {21, 22, 21, 22}, + {22, 22, 22, 22}, + {21, 22, 21, 22}, + {22, 22, 22, 22}, + }, + { + {21, 22, 22, 22}, + {22, 22, 22, 22}, + {22, 22, 21, 22}, + {22, 22, 22, 22}, + }, + { + {22, 22, 22, 22}, + {22, 22, 22, 22}, + {22, 22, 22, 22}, + {22, 22, 22, 22}, + }, + { + {22, 22, 22, 22}, + {22, 22, 23, 22}, + {22, 22, 22, 22}, + {23, 22, 22, 22}, + }, + { + {22, 22, 22, 22}, + {23, 22, 23, 22}, + {22, 22, 22, 22}, + {23, 22, 23, 22}, + }, + { + {22, 22, 22, 23}, + {23, 22, 23, 22}, + {22, 23, 22, 22}, + {23, 22, 23, 22}, + }, + { + {22, 23, 22, 23}, + {23, 22, 23, 22}, + {22, 23, 22, 23}, + {23, 22, 23, 22}, + }, + { + {22, 23, 22, 23}, + {23, 22, 23, 23}, + {22, 23, 22, 23}, + {23, 23, 23, 22}, + }, + { + {22, 23, 22, 23}, + {23, 23, 23, 23}, + {22, 23, 22, 23}, + {23, 23, 23, 23}, + }, + { + {22, 23, 23, 23}, + {23, 23, 23, 23}, + {23, 23, 22, 23}, + {23, 23, 23, 23}, + }, + { + {23, 23, 23, 23}, + {23, 23, 23, 23}, + {23, 23, 23, 23}, + {23, 23, 23, 23}, + }, + { + {23, 23, 23, 23}, + {23, 23, 24, 23}, + {23, 23, 23, 23}, + {24, 23, 23, 23}, + }, + { + {23, 23, 23, 23}, + {24, 23, 24, 23}, + {23, 23, 23, 23}, + {24, 23, 24, 23}, + }, + { + {23, 23, 23, 23}, + {24, 23, 24, 23}, + {23, 24, 23, 23}, + {24, 23, 24, 23}, + }, + { + {23, 23, 23, 24}, + {24, 23, 24, 23}, + {23, 24, 23, 24}, + {24, 23, 24, 23}, + }, + { + {23, 24, 23, 24}, + {24, 23, 24, 23}, + {23, 24, 23, 24}, + {24, 24, 24, 23}, + }, + { + {23, 24, 23, 24}, + {24, 23, 24, 24}, + {23, 24, 23, 24}, + {24, 24, 24, 24}, + }, + { + {23, 24, 23, 24}, + {24, 24, 24, 24}, + {24, 24, 23, 24}, + {24, 24, 24, 24}, + }, + { + {23, 24, 24, 24}, + {24, 24, 24, 24}, + {24, 24, 24, 24}, + {24, 24, 24, 24}, + }, + { + {24, 24, 24, 24}, + {24, 24, 24, 24}, + {24, 24, 24, 24}, + {25, 24, 24, 24}, + }, + { + {24, 24, 24, 24}, + {24, 24, 25, 24}, + {24, 24, 24, 24}, + {25, 24, 25, 24}, + }, + { + {24, 24, 24, 24}, + {25, 24, 25, 24}, + {24, 25, 24, 24}, + {25, 24, 25, 24}, + }, + { + {24, 24, 24, 25}, + {25, 24, 25, 24}, + {24, 25, 24, 25}, + {25, 24, 25, 24}, + }, + { + {24, 25, 24, 25}, + {25, 24, 25, 24}, + {24, 25, 24, 25}, + {25, 25, 25, 24}, + }, + { + {24, 25, 24, 25}, + {25, 24, 25, 25}, + {24, 25, 24, 25}, + {25, 25, 25, 25}, + }, + { + {24, 25, 24, 25}, + {25, 25, 25, 25}, + {25, 25, 24, 25}, + {25, 25, 25, 25}, + }, + { + {24, 25, 25, 25}, + {25, 25, 25, 25}, + {25, 25, 25, 25}, + {25, 25, 25, 25}, + }, + { + {25, 25, 25, 25}, + {25, 25, 25, 25}, + {25, 25, 25, 25}, + {26, 25, 25, 25}, + }, + { + {25, 25, 25, 25}, + {25, 25, 26, 25}, + {25, 25, 25, 25}, + {26, 25, 26, 25}, + }, + { + {25, 25, 25, 25}, + {26, 25, 26, 25}, + {25, 25, 25, 25}, + {26, 25, 26, 25}, + }, + { + {25, 25, 25, 26}, + {26, 25, 26, 25}, + {25, 26, 25, 25}, + {26, 25, 26, 25}, + }, + { + {25, 26, 25, 26}, + {26, 25, 26, 25}, + {25, 26, 25, 26}, + {26, 25, 26, 25}, + }, + { + {25, 26, 25, 26}, + {26, 25, 26, 26}, + {25, 26, 25, 26}, + {26, 26, 26, 25}, + }, + { + {25, 26, 25, 26}, + {26, 26, 26, 26}, + {25, 26, 25, 26}, + {26, 26, 26, 26}, + }, + { + {25, 26, 26, 26}, + {26, 26, 26, 26}, + {26, 26, 25, 26}, + {26, 26, 26, 26}, + }, + { + {26, 26, 26, 26}, + {26, 26, 26, 26}, + {26, 26, 26, 26}, + {26, 26, 26, 26}, + }, + { + {26, 26, 26, 26}, + {26, 26, 27, 26}, + {26, 26, 26, 26}, + {27, 26, 26, 26}, + }, + { + {26, 26, 26, 26}, + {27, 26, 27, 26}, + {26, 26, 26, 26}, + {27, 26, 27, 26}, + }, + { + {26, 26, 26, 27}, + {27, 26, 27, 26}, + {26, 27, 26, 26}, + {27, 26, 27, 26}, + }, + { + {26, 27, 26, 27}, + {27, 26, 27, 26}, + {26, 27, 26, 27}, + {27, 26, 27, 26}, + }, + { + {26, 27, 26, 27}, + {27, 26, 27, 27}, + {26, 27, 26, 27}, + {27, 27, 27, 26}, + }, + { + {26, 27, 26, 27}, + {27, 27, 27, 27}, + {26, 27, 26, 27}, + {27, 27, 27, 27}, + }, + { + {26, 27, 27, 27}, + {27, 27, 27, 27}, + {27, 27, 26, 27}, + {27, 27, 27, 27}, + }, + { + {27, 27, 27, 27}, + {27, 27, 27, 27}, + {27, 27, 27, 27}, + {27, 27, 27, 27}, + }, + { + {27, 27, 27, 27}, + {27, 27, 28, 27}, + {27, 27, 27, 27}, + {28, 27, 27, 27}, + }, + { + {27, 27, 27, 27}, + {27, 27, 28, 27}, + {27, 27, 27, 27}, + {28, 27, 28, 27}, + }, + { + {27, 27, 27, 27}, + {28, 27, 28, 27}, + {27, 28, 27, 27}, + {28, 27, 28, 27}, + }, + { + {27, 27, 27, 28}, + {28, 27, 28, 27}, + {27, 28, 27, 28}, + {28, 27, 28, 27}, + }, + { + {27, 28, 27, 28}, + {28, 27, 28, 27}, + {27, 28, 27, 28}, + {28, 28, 28, 27}, + }, + { + {27, 28, 27, 28}, + {28, 27, 28, 28}, + {27, 28, 27, 28}, + {28, 28, 28, 28}, + }, + { + {27, 28, 27, 28}, + {28, 28, 28, 28}, + {28, 28, 27, 28}, + {28, 28, 28, 28}, + }, + { + {27, 28, 28, 28}, + {28, 28, 28, 28}, + {28, 28, 28, 28}, + {28, 28, 28, 28}, + }, + { + {28, 28, 28, 28}, + {28, 28, 28, 28}, + {28, 28, 28, 28}, + {29, 28, 28, 28}, + }, + { + {28, 28, 28, 28}, + {28, 28, 29, 28}, + {28, 28, 28, 28}, + {29, 28, 29, 28}, + }, + { + {28, 28, 28, 28}, + {29, 28, 29, 28}, + {28, 29, 28, 28}, + {29, 28, 29, 28}, + }, + { + {28, 28, 28, 29}, + {29, 28, 29, 28}, + {28, 29, 28, 29}, + {29, 28, 29, 28}, + }, + { + {28, 29, 28, 29}, + {29, 28, 29, 28}, + {28, 29, 28, 29}, + {29, 29, 29, 28}, + }, + { + {28, 29, 28, 29}, + {29, 28, 29, 29}, + {28, 29, 28, 29}, + {29, 29, 29, 29}, + }, + { + {28, 29, 28, 29}, + {29, 29, 29, 29}, + {29, 29, 28, 29}, + {29, 29, 29, 29}, + }, + { + {28, 29, 29, 29}, + {29, 29, 29, 29}, + {29, 29, 29, 29}, + {29, 29, 29, 29}, + }, + { + {29, 29, 29, 29}, + {29, 29, 29, 29}, + {29, 29, 29, 29}, + {30, 29, 29, 29}, + }, + { + {29, 29, 29, 29}, + {29, 29, 30, 29}, + {29, 29, 29, 29}, + {30, 29, 29, 29}, + }, + { + {29, 29, 29, 29}, + {30, 29, 30, 29}, + {29, 29, 29, 29}, + {30, 29, 30, 29}, + }, + { + {29, 29, 29, 30}, + {30, 29, 30, 29}, + {29, 30, 29, 29}, + {30, 29, 30, 29}, + }, + { + {29, 30, 29, 30}, + {30, 29, 30, 29}, + {29, 30, 29, 30}, + {30, 29, 30, 29}, + }, + { + {29, 30, 29, 30}, + {30, 29, 30, 30}, + {29, 30, 29, 30}, + {30, 30, 30, 29}, + }, + { + {29, 30, 29, 30}, + {30, 30, 30, 30}, + {29, 30, 29, 30}, + {30, 30, 30, 30}, + }, + { + {29, 30, 30, 30}, + {30, 30, 30, 30}, + {30, 30, 29, 30}, + {30, 30, 30, 30}, + }, + { + {30, 30, 30, 30}, + {30, 30, 30, 30}, + {30, 30, 30, 30}, + {30, 30, 30, 30}, + }, + { + {30, 30, 30, 30}, + {30, 30, 31, 30}, + {30, 30, 30, 30}, + {31, 30, 30, 30}, + }, + { + {30, 30, 30, 30}, + {31, 30, 31, 30}, + {30, 30, 30, 30}, + {31, 30, 31, 30}, + }, + { + {30, 30, 30, 31}, + {31, 30, 31, 30}, + {30, 31, 30, 30}, + {31, 30, 31, 30}, + }, + { + {30, 31, 30, 31}, + {31, 30, 31, 30}, + {30, 31, 30, 31}, + {31, 30, 31, 30}, + }, + { + {30, 31, 30, 31}, + {31, 30, 31, 31}, + {30, 31, 30, 31}, + {31, 31, 31, 30}, + }, + { + {30, 31, 30, 31}, + {31, 31, 31, 31}, + {30, 31, 30, 31}, + {31, 31, 31, 31}, + }, + { + {30, 31, 31, 31}, + {31, 31, 31, 31}, + {31, 31, 30, 31}, + {31, 31, 31, 31}, + }, + { + {31, 31, 31, 31}, + {31, 31, 31, 31}, + {31, 31, 31, 31}, + {31, 31, 31, 31}, + }, +}; + +uint8_t dither_g[256][4][4] = +{ + { + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + {0, 0, 0, 0}, + }, + { + {0, 0, 0, 0}, + {1, 0, 1, 0}, + {0, 0, 0, 0}, + {1, 0, 1, 0}, + }, + { + {0, 1, 0, 1}, + {1, 0, 1, 0}, + {0, 1, 0, 1}, + {1, 0, 1, 0}, + }, + { + {0, 1, 0, 1}, + {1, 1, 1, 1}, + {0, 1, 0, 1}, + {1, 1, 1, 1}, + }, + { + {1, 1, 1, 1}, + {1, 1, 1, 1}, + {1, 1, 1, 1}, + {1, 1, 1, 1}, + }, + { + {1, 1, 1, 1}, + {2, 1, 2, 1}, + {1, 1, 1, 1}, + {2, 1, 2, 1}, + }, + { + {1, 2, 1, 2}, + {2, 1, 2, 1}, + {1, 2, 1, 2}, + {2, 1, 2, 1}, + }, + { + {1, 2, 1, 2}, + {2, 2, 2, 2}, + {1, 2, 1, 2}, + {2, 2, 2, 2}, + }, + { + {2, 2, 2, 2}, + {2, 2, 2, 2}, + {2, 2, 2, 2}, + {2, 2, 2, 2}, + }, + { + {2, 2, 2, 2}, + {3, 2, 3, 2}, + {2, 2, 2, 2}, + {3, 2, 3, 2}, + }, + { + {2, 3, 2, 3}, + {3, 2, 3, 2}, + {2, 3, 2, 3}, + {3, 2, 3, 2}, + }, + { + {2, 3, 2, 3}, + {3, 3, 3, 3}, + {2, 3, 2, 3}, + {3, 3, 3, 3}, + }, + { + {3, 3, 3, 3}, + {3, 3, 3, 3}, + {3, 3, 3, 3}, + {3, 3, 3, 3}, + }, + { + {3, 3, 3, 3}, + {4, 3, 4, 3}, + {3, 3, 3, 3}, + {4, 3, 4, 3}, + }, + { + {3, 4, 3, 4}, + {4, 3, 4, 3}, + {3, 4, 3, 4}, + {4, 3, 4, 3}, + }, + { + {3, 4, 3, 4}, + {4, 4, 4, 4}, + {3, 4, 3, 4}, + {4, 4, 4, 4}, + }, + { + {3, 4, 4, 4}, + {4, 4, 4, 4}, + {4, 4, 4, 4}, + {4, 4, 4, 4}, + }, + { + {4, 4, 4, 4}, + {4, 4, 5, 4}, + {4, 4, 4, 4}, + {5, 4, 5, 4}, + }, + { + {4, 4, 4, 5}, + {5, 4, 5, 4}, + {4, 5, 4, 5}, + {5, 4, 5, 4}, + }, + { + {4, 5, 4, 5}, + {5, 4, 5, 5}, + {4, 5, 4, 5}, + {5, 5, 5, 5}, + }, + { + {4, 5, 5, 5}, + {5, 5, 5, 5}, + {5, 5, 5, 5}, + {5, 5, 5, 5}, + }, + { + {5, 5, 5, 5}, + {5, 5, 6, 5}, + {5, 5, 5, 5}, + {6, 5, 6, 5}, + }, + { + {5, 5, 5, 6}, + {6, 5, 6, 5}, + {5, 6, 5, 6}, + {6, 5, 6, 5}, + }, + { + {5, 6, 5, 6}, + {6, 5, 6, 6}, + {5, 6, 5, 6}, + {6, 6, 6, 6}, + }, + { + {5, 6, 6, 6}, + {6, 6, 6, 6}, + {6, 6, 6, 6}, + {6, 6, 6, 6}, + }, + { + {6, 6, 6, 6}, + {6, 6, 7, 6}, + {6, 6, 6, 6}, + {7, 6, 7, 6}, + }, + { + {6, 6, 6, 7}, + {7, 6, 7, 6}, + {6, 7, 6, 7}, + {7, 6, 7, 6}, + }, + { + {6, 7, 6, 7}, + {7, 6, 7, 7}, + {6, 7, 6, 7}, + {7, 7, 7, 7}, + }, + { + {6, 7, 7, 7}, + {7, 7, 7, 7}, + {7, 7, 7, 7}, + {7, 7, 7, 7}, + }, + { + {7, 7, 7, 7}, + {7, 7, 8, 7}, + {7, 7, 7, 7}, + {8, 7, 8, 7}, + }, + { + {7, 7, 7, 8}, + {8, 7, 8, 7}, + {7, 8, 7, 8}, + {8, 7, 8, 7}, + }, + { + {7, 8, 7, 8}, + {8, 7, 8, 8}, + {7, 8, 7, 8}, + {8, 8, 8, 8}, + }, + { + {7, 8, 8, 8}, + {8, 8, 8, 8}, + {8, 8, 7, 8}, + {8, 8, 8, 8}, + }, + { + {8, 8, 8, 8}, + {8, 8, 9, 8}, + {8, 8, 8, 8}, + {9, 8, 8, 8}, + }, + { + {8, 8, 8, 9}, + {9, 8, 9, 8}, + {8, 9, 8, 8}, + {9, 8, 9, 8}, + }, + { + {8, 9, 8, 9}, + {9, 8, 9, 9}, + {8, 9, 8, 9}, + {9, 9, 9, 8}, + }, + { + {8, 9, 9, 9}, + {9, 9, 9, 9}, + {9, 9, 8, 9}, + {9, 9, 9, 9}, + }, + { + {9, 9, 9, 9}, + {9, 9, 10, 9}, + {9, 9, 9, 9}, + {10, 9, 9, 9}, + }, + { + {9, 9, 9, 10}, + {10, 9, 10, 9}, + {9, 10, 9, 9}, + {10, 9, 10, 9}, + }, + { + {9, 10, 9, 10}, + {10, 9, 10, 10}, + {9, 10, 9, 10}, + {10, 10, 10, 9}, + }, + { + {9, 10, 10, 10}, + {10, 10, 10, 10}, + {10, 10, 9, 10}, + {10, 10, 10, 10}, + }, + { + {10, 10, 10, 10}, + {10, 10, 11, 10}, + {10, 10, 10, 10}, + {11, 10, 10, 10}, + }, + { + {10, 10, 10, 11}, + {11, 10, 11, 10}, + {10, 11, 10, 10}, + {11, 10, 11, 10}, + }, + { + {10, 11, 10, 11}, + {11, 10, 11, 11}, + {10, 11, 10, 11}, + {11, 11, 11, 10}, + }, + { + {10, 11, 11, 11}, + {11, 11, 11, 11}, + {11, 11, 10, 11}, + {11, 11, 11, 11}, + }, + { + {11, 11, 11, 11}, + {11, 11, 12, 11}, + {11, 11, 11, 11}, + {12, 11, 11, 11}, + }, + { + {11, 11, 11, 12}, + {12, 11, 12, 11}, + {11, 12, 11, 11}, + {12, 11, 12, 11}, + }, + { + {11, 12, 11, 12}, + {12, 11, 12, 12}, + {11, 12, 11, 12}, + {12, 12, 12, 11}, + }, + { + {11, 12, 11, 12}, + {12, 12, 12, 12}, + {12, 12, 11, 12}, + {12, 12, 12, 12}, + }, + { + {12, 12, 12, 12}, + {12, 12, 12, 12}, + {12, 12, 12, 12}, + {13, 12, 12, 12}, + }, + { + {12, 12, 12, 12}, + {13, 12, 13, 12}, + {12, 13, 12, 12}, + {13, 12, 13, 12}, + }, + { + {12, 13, 12, 13}, + {13, 12, 13, 12}, + {12, 13, 12, 13}, + {13, 13, 13, 12}, + }, + { + {12, 13, 12, 13}, + {13, 13, 13, 13}, + {13, 13, 12, 13}, + {13, 13, 13, 13}, + }, + { + {13, 13, 13, 13}, + {13, 13, 13, 13}, + {13, 13, 13, 13}, + {14, 13, 13, 13}, + }, + { + {13, 13, 13, 13}, + {14, 13, 14, 13}, + {13, 14, 13, 13}, + {14, 13, 14, 13}, + }, + { + {13, 14, 13, 14}, + {14, 13, 14, 13}, + {13, 14, 13, 14}, + {14, 14, 14, 13}, + }, + { + {13, 14, 13, 14}, + {14, 14, 14, 14}, + {14, 14, 13, 14}, + {14, 14, 14, 14}, + }, + { + {14, 14, 14, 14}, + {14, 14, 14, 14}, + {14, 14, 14, 14}, + {15, 14, 14, 14}, + }, + { + {14, 14, 14, 14}, + {15, 14, 15, 14}, + {14, 15, 14, 14}, + {15, 14, 15, 14}, + }, + { + {14, 15, 14, 15}, + {15, 14, 15, 14}, + {14, 15, 14, 15}, + {15, 15, 15, 14}, + }, + { + {14, 15, 14, 15}, + {15, 15, 15, 15}, + {15, 15, 14, 15}, + {15, 15, 15, 15}, + }, + { + {15, 15, 15, 15}, + {15, 15, 15, 15}, + {15, 15, 15, 15}, + {16, 15, 15, 15}, + }, + { + {15, 15, 15, 15}, + {16, 15, 16, 15}, + {15, 16, 15, 15}, + {16, 15, 16, 15}, + }, + { + {15, 16, 15, 16}, + {16, 15, 16, 15}, + {15, 16, 15, 16}, + {16, 16, 16, 15}, + }, + { + {15, 16, 15, 16}, + {16, 16, 16, 16}, + {16, 16, 15, 16}, + {16, 16, 16, 16}, + }, + { + {16, 16, 16, 16}, + {16, 16, 16, 16}, + {16, 16, 16, 16}, + {17, 16, 16, 16}, + }, + { + {16, 16, 16, 16}, + {17, 16, 17, 16}, + {16, 17, 16, 16}, + {17, 16, 17, 16}, + }, + { + {16, 17, 16, 17}, + {17, 16, 17, 16}, + {16, 17, 16, 17}, + {17, 17, 17, 16}, + }, + { + {16, 17, 16, 17}, + {17, 17, 17, 17}, + {17, 17, 16, 17}, + {17, 17, 17, 17}, + }, + { + {17, 17, 17, 17}, + {17, 17, 17, 17}, + {17, 17, 17, 17}, + {18, 17, 17, 17}, + }, + { + {17, 17, 17, 17}, + {18, 17, 18, 17}, + {17, 18, 17, 17}, + {18, 17, 18, 17}, + }, + { + {17, 18, 17, 18}, + {18, 17, 18, 17}, + {17, 18, 17, 18}, + {18, 18, 18, 17}, + }, + { + {17, 18, 17, 18}, + {18, 18, 18, 18}, + {18, 18, 17, 18}, + {18, 18, 18, 18}, + }, + { + {18, 18, 18, 18}, + {18, 18, 18, 18}, + {18, 18, 18, 18}, + {19, 18, 18, 18}, + }, + { + {18, 18, 18, 18}, + {19, 18, 19, 18}, + {18, 19, 18, 18}, + {19, 18, 19, 18}, + }, + { + {18, 19, 18, 19}, + {19, 18, 19, 18}, + {18, 19, 18, 19}, + {19, 19, 19, 18}, + }, + { + {18, 19, 18, 19}, + {19, 19, 19, 19}, + {19, 19, 18, 19}, + {19, 19, 19, 19}, + }, + { + {19, 19, 19, 19}, + {19, 19, 19, 19}, + {19, 19, 19, 19}, + {20, 19, 19, 19}, + }, + { + {19, 19, 19, 19}, + {20, 19, 20, 19}, + {19, 20, 19, 19}, + {20, 19, 20, 19}, + }, + { + {19, 20, 19, 20}, + {20, 19, 20, 19}, + {19, 20, 19, 20}, + {20, 20, 20, 19}, + }, + { + {19, 20, 19, 20}, + {20, 20, 20, 20}, + {19, 20, 19, 20}, + {20, 20, 20, 20}, + }, + { + {20, 20, 20, 20}, + {20, 20, 20, 20}, + {20, 20, 20, 20}, + {20, 20, 20, 20}, + }, + { + {20, 20, 20, 20}, + {21, 20, 21, 20}, + {20, 20, 20, 20}, + {21, 20, 21, 20}, + }, + { + {20, 21, 20, 21}, + {21, 20, 21, 20}, + {20, 21, 20, 21}, + {21, 20, 21, 20}, + }, + { + {20, 21, 20, 21}, + {21, 21, 21, 21}, + {20, 21, 20, 21}, + {21, 21, 21, 21}, + }, + { + {21, 21, 21, 21}, + {21, 21, 21, 21}, + {21, 21, 21, 21}, + {21, 21, 21, 21}, + }, + { + {21, 21, 21, 21}, + {22, 21, 22, 21}, + {21, 21, 21, 21}, + {22, 21, 22, 21}, + }, + { + {21, 22, 21, 22}, + {22, 21, 22, 21}, + {21, 22, 21, 22}, + {22, 21, 22, 21}, + }, + { + {21, 22, 21, 22}, + {22, 22, 22, 22}, + {21, 22, 21, 22}, + {22, 22, 22, 22}, + }, + { + {22, 22, 22, 22}, + {22, 22, 22, 22}, + {22, 22, 22, 22}, + {22, 22, 22, 22}, + }, + { + {22, 22, 22, 22}, + {23, 22, 23, 22}, + {22, 22, 22, 22}, + {23, 22, 23, 22}, + }, + { + {22, 23, 22, 23}, + {23, 22, 23, 22}, + {22, 23, 22, 23}, + {23, 22, 23, 22}, + }, + { + {22, 23, 22, 23}, + {23, 23, 23, 23}, + {22, 23, 22, 23}, + {23, 23, 23, 23}, + }, + { + {23, 23, 23, 23}, + {23, 23, 23, 23}, + {23, 23, 23, 23}, + {23, 23, 23, 23}, + }, + { + {23, 23, 23, 23}, + {24, 23, 24, 23}, + {23, 23, 23, 23}, + {24, 23, 24, 23}, + }, + { + {23, 24, 23, 24}, + {24, 23, 24, 23}, + {23, 24, 23, 24}, + {24, 23, 24, 23}, + }, + { + {23, 24, 23, 24}, + {24, 23, 24, 24}, + {23, 24, 23, 24}, + {24, 24, 24, 24}, + }, + { + {23, 24, 24, 24}, + {24, 24, 24, 24}, + {24, 24, 24, 24}, + {24, 24, 24, 24}, + }, + { + {24, 24, 24, 24}, + {24, 24, 25, 24}, + {24, 24, 24, 24}, + {25, 24, 25, 24}, + }, + { + {24, 24, 24, 25}, + {25, 24, 25, 24}, + {24, 25, 24, 25}, + {25, 24, 25, 24}, + }, + { + {24, 25, 24, 25}, + {25, 24, 25, 25}, + {24, 25, 24, 25}, + {25, 25, 25, 25}, + }, + { + {24, 25, 25, 25}, + {25, 25, 25, 25}, + {25, 25, 25, 25}, + {25, 25, 25, 25}, + }, + { + {25, 25, 25, 25}, + {25, 25, 26, 25}, + {25, 25, 25, 25}, + {26, 25, 26, 25}, + }, + { + {25, 25, 25, 26}, + {26, 25, 26, 25}, + {25, 26, 25, 26}, + {26, 25, 26, 25}, + }, + { + {25, 26, 25, 26}, + {26, 25, 26, 26}, + {25, 26, 25, 26}, + {26, 26, 26, 26}, + }, + { + {25, 26, 26, 26}, + {26, 26, 26, 26}, + {26, 26, 26, 26}, + {26, 26, 26, 26}, + }, + { + {26, 26, 26, 26}, + {26, 26, 27, 26}, + {26, 26, 26, 26}, + {27, 26, 27, 26}, + }, + { + {26, 26, 26, 27}, + {27, 26, 27, 26}, + {26, 27, 26, 27}, + {27, 26, 27, 26}, + }, + { + {26, 27, 26, 27}, + {27, 26, 27, 27}, + {26, 27, 26, 27}, + {27, 27, 27, 27}, + }, + { + {26, 27, 27, 27}, + {27, 27, 27, 27}, + {27, 27, 27, 27}, + {27, 27, 27, 27}, + }, + { + {27, 27, 27, 27}, + {27, 27, 28, 27}, + {27, 27, 27, 27}, + {28, 27, 28, 27}, + }, + { + {27, 27, 27, 28}, + {28, 27, 28, 27}, + {27, 28, 27, 28}, + {28, 27, 28, 27}, + }, + { + {27, 28, 27, 28}, + {28, 27, 28, 28}, + {27, 28, 27, 28}, + {28, 28, 28, 27}, + }, + { + {27, 28, 28, 28}, + {28, 28, 28, 28}, + {28, 28, 27, 28}, + {28, 28, 28, 28}, + }, + { + {28, 28, 28, 28}, + {28, 28, 29, 28}, + {28, 28, 28, 28}, + {29, 28, 28, 28}, + }, + { + {28, 28, 28, 29}, + {29, 28, 29, 28}, + {28, 29, 28, 28}, + {29, 28, 29, 28}, + }, + { + {28, 29, 28, 29}, + {29, 28, 29, 29}, + {28, 29, 28, 29}, + {29, 29, 29, 28}, + }, + { + {28, 29, 29, 29}, + {29, 29, 29, 29}, + {29, 29, 28, 29}, + {29, 29, 29, 29}, + }, + { + {29, 29, 29, 29}, + {29, 29, 30, 29}, + {29, 29, 29, 29}, + {30, 29, 29, 29}, + }, + { + {29, 29, 29, 30}, + {30, 29, 30, 29}, + {29, 30, 29, 29}, + {30, 29, 30, 29}, + }, + { + {29, 30, 29, 30}, + {30, 29, 30, 30}, + {29, 30, 29, 30}, + {30, 30, 30, 29}, + }, + { + {29, 30, 30, 30}, + {30, 30, 30, 30}, + {30, 30, 29, 30}, + {30, 30, 30, 30}, + }, + { + {30, 30, 30, 30}, + {30, 30, 31, 30}, + {30, 30, 30, 30}, + {31, 30, 30, 30}, + }, + { + {30, 30, 30, 31}, + {31, 30, 31, 30}, + {30, 31, 30, 30}, + {31, 30, 31, 30}, + }, + { + {30, 31, 30, 31}, + {31, 30, 31, 31}, + {30, 31, 30, 31}, + {31, 31, 31, 30}, + }, + { + {30, 31, 31, 31}, + {31, 31, 31, 31}, + {31, 31, 30, 31}, + {31, 31, 31, 31}, + }, + { + {31, 31, 31, 31}, + {31, 31, 32, 31}, + {31, 31, 31, 31}, + {32, 31, 31, 31}, + }, + { + {31, 31, 31, 32}, + {32, 31, 32, 31}, + {31, 32, 31, 31}, + {32, 31, 32, 31}, + }, + { + {31, 32, 31, 32}, + {32, 31, 32, 32}, + {31, 32, 31, 32}, + {32, 32, 32, 31}, + }, + { + {31, 32, 32, 32}, + {32, 32, 32, 32}, + {32, 32, 31, 32}, + {32, 32, 32, 32}, + }, + { + {32, 32, 32, 32}, + {32, 32, 33, 32}, + {32, 32, 32, 32}, + {33, 32, 32, 32}, + }, + { + {32, 32, 32, 33}, + {33, 32, 33, 32}, + {32, 33, 32, 32}, + {33, 32, 33, 32}, + }, + { + {32, 33, 32, 33}, + {33, 32, 33, 33}, + {32, 33, 32, 33}, + {33, 33, 33, 32}, + }, + { + {32, 33, 33, 33}, + {33, 33, 33, 33}, + {33, 33, 32, 33}, + {33, 33, 33, 33}, + }, + { + {33, 33, 33, 33}, + {33, 33, 34, 33}, + {33, 33, 33, 33}, + {34, 33, 33, 33}, + }, + { + {33, 33, 33, 34}, + {34, 33, 34, 33}, + {33, 34, 33, 33}, + {34, 33, 34, 33}, + }, + { + {33, 34, 33, 34}, + {34, 33, 34, 34}, + {33, 34, 33, 34}, + {34, 34, 34, 33}, + }, + { + {33, 34, 34, 34}, + {34, 34, 34, 34}, + {34, 34, 33, 34}, + {34, 34, 34, 34}, + }, + { + {34, 34, 34, 34}, + {34, 34, 35, 34}, + {34, 34, 34, 34}, + {35, 34, 34, 34}, + }, + { + {34, 34, 34, 35}, + {35, 34, 35, 34}, + {34, 35, 34, 34}, + {35, 34, 35, 34}, + }, + { + {34, 35, 34, 35}, + {35, 34, 35, 35}, + {34, 35, 34, 35}, + {35, 35, 35, 34}, + }, + { + {34, 35, 35, 35}, + {35, 35, 35, 35}, + {35, 35, 34, 35}, + {35, 35, 35, 35}, + }, + { + {35, 35, 35, 35}, + {35, 35, 36, 35}, + {35, 35, 35, 35}, + {36, 35, 35, 35}, + }, + { + {35, 35, 35, 36}, + {36, 35, 36, 35}, + {35, 36, 35, 35}, + {36, 35, 36, 35}, + }, + { + {35, 36, 35, 36}, + {36, 35, 36, 35}, + {35, 36, 35, 36}, + {36, 36, 36, 35}, + }, + { + {35, 36, 35, 36}, + {36, 36, 36, 36}, + {36, 36, 35, 36}, + {36, 36, 36, 36}, + }, + { + {36, 36, 36, 36}, + {36, 36, 36, 36}, + {36, 36, 36, 36}, + {37, 36, 36, 36}, + }, + { + {36, 36, 36, 36}, + {37, 36, 37, 36}, + {36, 37, 36, 36}, + {37, 36, 37, 36}, + }, + { + {36, 37, 36, 37}, + {37, 36, 37, 36}, + {36, 37, 36, 37}, + {37, 37, 37, 36}, + }, + { + {36, 37, 36, 37}, + {37, 37, 37, 37}, + {37, 37, 36, 37}, + {37, 37, 37, 37}, + }, + { + {37, 37, 37, 37}, + {37, 37, 37, 37}, + {37, 37, 37, 37}, + {38, 37, 37, 37}, + }, + { + {37, 37, 37, 37}, + {38, 37, 38, 37}, + {37, 38, 37, 37}, + {38, 37, 38, 37}, + }, + { + {37, 38, 37, 38}, + {38, 37, 38, 37}, + {37, 38, 37, 38}, + {38, 38, 38, 37}, + }, + { + {37, 38, 37, 38}, + {38, 38, 38, 38}, + {38, 38, 37, 38}, + {38, 38, 38, 38}, + }, + { + {38, 38, 38, 38}, + {38, 38, 38, 38}, + {38, 38, 38, 38}, + {39, 38, 38, 38}, + }, + { + {38, 38, 38, 38}, + {39, 38, 39, 38}, + {38, 39, 38, 38}, + {39, 38, 39, 38}, + }, + { + {38, 39, 38, 39}, + {39, 38, 39, 38}, + {38, 39, 38, 39}, + {39, 39, 39, 38}, + }, + { + {38, 39, 38, 39}, + {39, 39, 39, 39}, + {39, 39, 38, 39}, + {39, 39, 39, 39}, + }, + { + {39, 39, 39, 39}, + {39, 39, 39, 39}, + {39, 39, 39, 39}, + {40, 39, 39, 39}, + }, + { + {39, 39, 39, 39}, + {40, 39, 40, 39}, + {39, 40, 39, 39}, + {40, 39, 40, 39}, + }, + { + {39, 40, 39, 40}, + {40, 39, 40, 39}, + {39, 40, 39, 40}, + {40, 39, 40, 39}, + }, + { + {39, 40, 39, 40}, + {40, 40, 40, 40}, + {39, 40, 39, 40}, + {40, 40, 40, 40}, + }, + { + {40, 40, 40, 40}, + {40, 40, 40, 40}, + {40, 40, 40, 40}, + {40, 40, 40, 40}, + }, + { + {40, 40, 40, 40}, + {41, 40, 41, 40}, + {40, 40, 40, 40}, + {41, 40, 41, 40}, + }, + { + {40, 41, 40, 41}, + {41, 40, 41, 40}, + {40, 41, 40, 41}, + {41, 40, 41, 40}, + }, + { + {40, 41, 40, 41}, + {41, 41, 41, 41}, + {40, 41, 40, 41}, + {41, 41, 41, 41}, + }, + { + {41, 41, 41, 41}, + {41, 41, 41, 41}, + {41, 41, 41, 41}, + {41, 41, 41, 41}, + }, + { + {41, 41, 41, 41}, + {42, 41, 42, 41}, + {41, 41, 41, 41}, + {42, 41, 42, 41}, + }, + { + {41, 42, 41, 42}, + {42, 41, 42, 41}, + {41, 42, 41, 42}, + {42, 41, 42, 41}, + }, + { + {41, 42, 41, 42}, + {42, 42, 42, 42}, + {41, 42, 41, 42}, + {42, 42, 42, 42}, + }, + { + {42, 42, 42, 42}, + {42, 42, 42, 42}, + {42, 42, 42, 42}, + {42, 42, 42, 42}, + }, + { + {42, 42, 42, 42}, + {43, 42, 43, 42}, + {42, 42, 42, 42}, + {43, 42, 43, 42}, + }, + { + {42, 43, 42, 43}, + {43, 42, 43, 42}, + {42, 43, 42, 43}, + {43, 42, 43, 42}, + }, + { + {42, 43, 42, 43}, + {43, 43, 43, 43}, + {42, 43, 42, 43}, + {43, 43, 43, 43}, + }, + { + {43, 43, 43, 43}, + {43, 43, 43, 43}, + {43, 43, 43, 43}, + {43, 43, 43, 43}, + }, + { + {43, 43, 43, 43}, + {44, 43, 44, 43}, + {43, 43, 43, 43}, + {44, 43, 44, 43}, + }, + { + {43, 43, 43, 44}, + {44, 43, 44, 43}, + {43, 44, 43, 44}, + {44, 43, 44, 43}, + }, + { + {43, 44, 43, 44}, + {44, 43, 44, 44}, + {43, 44, 43, 44}, + {44, 44, 44, 44}, + }, + { + {43, 44, 44, 44}, + {44, 44, 44, 44}, + {44, 44, 44, 44}, + {44, 44, 44, 44}, + }, + { + {44, 44, 44, 44}, + {44, 44, 45, 44}, + {44, 44, 44, 44}, + {45, 44, 45, 44}, + }, + { + {44, 44, 44, 45}, + {45, 44, 45, 44}, + {44, 45, 44, 45}, + {45, 44, 45, 44}, + }, + { + {44, 45, 44, 45}, + {45, 44, 45, 45}, + {44, 45, 44, 45}, + {45, 45, 45, 45}, + }, + { + {44, 45, 45, 45}, + {45, 45, 45, 45}, + {45, 45, 45, 45}, + {45, 45, 45, 45}, + }, + { + {45, 45, 45, 45}, + {45, 45, 46, 45}, + {45, 45, 45, 45}, + {46, 45, 46, 45}, + }, + { + {45, 45, 45, 46}, + {46, 45, 46, 45}, + {45, 46, 45, 46}, + {46, 45, 46, 45}, + }, + { + {45, 46, 45, 46}, + {46, 45, 46, 46}, + {45, 46, 45, 46}, + {46, 46, 46, 46}, + }, + { + {45, 46, 46, 46}, + {46, 46, 46, 46}, + {46, 46, 46, 46}, + {46, 46, 46, 46}, + }, + { + {46, 46, 46, 46}, + {46, 46, 47, 46}, + {46, 46, 46, 46}, + {47, 46, 47, 46}, + }, + { + {46, 46, 46, 47}, + {47, 46, 47, 46}, + {46, 47, 46, 47}, + {47, 46, 47, 46}, + }, + { + {46, 47, 46, 47}, + {47, 46, 47, 47}, + {46, 47, 46, 47}, + {47, 47, 47, 47}, + }, + { + {46, 47, 47, 47}, + {47, 47, 47, 47}, + {47, 47, 47, 47}, + {47, 47, 47, 47}, + }, + { + {47, 47, 47, 47}, + {47, 47, 48, 47}, + {47, 47, 47, 47}, + {48, 47, 48, 47}, + }, + { + {47, 47, 47, 48}, + {48, 47, 48, 47}, + {47, 48, 47, 48}, + {48, 47, 48, 47}, + }, + { + {47, 48, 47, 48}, + {48, 47, 48, 48}, + {47, 48, 47, 48}, + {48, 48, 48, 48}, + }, + { + {47, 48, 48, 48}, + {48, 48, 48, 48}, + {48, 48, 48, 48}, + {48, 48, 48, 48}, + }, + { + {48, 48, 48, 48}, + {48, 48, 49, 48}, + {48, 48, 48, 48}, + {49, 48, 49, 48}, + }, + { + {48, 48, 48, 49}, + {49, 48, 49, 48}, + {48, 49, 48, 49}, + {49, 48, 49, 48}, + }, + { + {48, 49, 48, 49}, + {49, 48, 49, 49}, + {48, 49, 48, 49}, + {49, 49, 49, 49}, + }, + { + {48, 49, 49, 49}, + {49, 49, 49, 49}, + {49, 49, 49, 49}, + {49, 49, 49, 49}, + }, + { + {49, 49, 49, 49}, + {49, 49, 50, 49}, + {49, 49, 49, 49}, + {50, 49, 50, 49}, + }, + { + {49, 49, 49, 50}, + {50, 49, 50, 49}, + {49, 50, 49, 50}, + {50, 49, 50, 49}, + }, + { + {49, 50, 49, 50}, + {50, 49, 50, 50}, + {49, 50, 49, 50}, + {50, 50, 50, 50}, + }, + { + {49, 50, 50, 50}, + {50, 50, 50, 50}, + {50, 50, 50, 50}, + {50, 50, 50, 50}, + }, + { + {50, 50, 50, 50}, + {50, 50, 51, 50}, + {50, 50, 50, 50}, + {51, 50, 51, 50}, + }, + { + {50, 50, 50, 51}, + {51, 50, 51, 50}, + {50, 51, 50, 51}, + {51, 50, 51, 50}, + }, + { + {50, 51, 50, 51}, + {51, 50, 51, 51}, + {50, 51, 50, 51}, + {51, 51, 51, 51}, + }, + { + {50, 51, 51, 51}, + {51, 51, 51, 51}, + {51, 51, 51, 51}, + {51, 51, 51, 51}, + }, + { + {51, 51, 51, 51}, + {51, 51, 52, 51}, + {51, 51, 51, 51}, + {52, 51, 52, 51}, + }, + { + {51, 51, 51, 52}, + {52, 51, 52, 51}, + {51, 52, 51, 51}, + {52, 51, 52, 51}, + }, + { + {51, 52, 51, 52}, + {52, 51, 52, 52}, + {51, 52, 51, 52}, + {52, 52, 52, 51}, + }, + { + {51, 52, 52, 52}, + {52, 52, 52, 52}, + {52, 52, 51, 52}, + {52, 52, 52, 52}, + }, + { + {52, 52, 52, 52}, + {52, 52, 53, 52}, + {52, 52, 52, 52}, + {53, 52, 52, 52}, + }, + { + {52, 52, 52, 53}, + {53, 52, 53, 52}, + {52, 53, 52, 52}, + {53, 52, 53, 52}, + }, + { + {52, 53, 52, 53}, + {53, 52, 53, 53}, + {52, 53, 52, 53}, + {53, 53, 53, 52}, + }, + { + {52, 53, 53, 53}, + {53, 53, 53, 53}, + {53, 53, 52, 53}, + {53, 53, 53, 53}, + }, + { + {53, 53, 53, 53}, + {53, 53, 54, 53}, + {53, 53, 53, 53}, + {54, 53, 53, 53}, + }, + { + {53, 53, 53, 54}, + {54, 53, 54, 53}, + {53, 54, 53, 53}, + {54, 53, 54, 53}, + }, + { + {53, 54, 53, 54}, + {54, 53, 54, 54}, + {53, 54, 53, 54}, + {54, 54, 54, 53}, + }, + { + {53, 54, 54, 54}, + {54, 54, 54, 54}, + {54, 54, 53, 54}, + {54, 54, 54, 54}, + }, + { + {54, 54, 54, 54}, + {54, 54, 55, 54}, + {54, 54, 54, 54}, + {55, 54, 54, 54}, + }, + { + {54, 54, 54, 55}, + {55, 54, 55, 54}, + {54, 55, 54, 54}, + {55, 54, 55, 54}, + }, + { + {54, 55, 54, 55}, + {55, 54, 55, 55}, + {54, 55, 54, 55}, + {55, 55, 55, 54}, + }, + { + {54, 55, 55, 55}, + {55, 55, 55, 55}, + {55, 55, 54, 55}, + {55, 55, 55, 55}, + }, + { + {55, 55, 55, 55}, + {55, 55, 56, 55}, + {55, 55, 55, 55}, + {56, 55, 55, 55}, + }, + { + {55, 55, 55, 55}, + {56, 55, 56, 55}, + {55, 56, 55, 55}, + {56, 55, 56, 55}, + }, + { + {55, 56, 55, 56}, + {56, 55, 56, 55}, + {55, 56, 55, 56}, + {56, 56, 56, 55}, + }, + { + {55, 56, 55, 56}, + {56, 56, 56, 56}, + {56, 56, 55, 56}, + {56, 56, 56, 56}, + }, + { + {56, 56, 56, 56}, + {56, 56, 56, 56}, + {56, 56, 56, 56}, + {57, 56, 56, 56}, + }, + { + {56, 56, 56, 56}, + {57, 56, 57, 56}, + {56, 57, 56, 56}, + {57, 56, 57, 56}, + }, + { + {56, 57, 56, 57}, + {57, 56, 57, 56}, + {56, 57, 56, 57}, + {57, 57, 57, 56}, + }, + { + {56, 57, 56, 57}, + {57, 57, 57, 57}, + {57, 57, 56, 57}, + {57, 57, 57, 57}, + }, + { + {57, 57, 57, 57}, + {57, 57, 57, 57}, + {57, 57, 57, 57}, + {58, 57, 57, 57}, + }, + { + {57, 57, 57, 57}, + {58, 57, 58, 57}, + {57, 58, 57, 57}, + {58, 57, 58, 57}, + }, + { + {57, 58, 57, 58}, + {58, 57, 58, 57}, + {57, 58, 57, 58}, + {58, 58, 58, 57}, + }, + { + {57, 58, 57, 58}, + {58, 58, 58, 58}, + {58, 58, 57, 58}, + {58, 58, 58, 58}, + }, + { + {58, 58, 58, 58}, + {58, 58, 58, 58}, + {58, 58, 58, 58}, + {59, 58, 58, 58}, + }, + { + {58, 58, 58, 58}, + {59, 58, 59, 58}, + {58, 59, 58, 58}, + {59, 58, 59, 58}, + }, + { + {58, 59, 58, 59}, + {59, 58, 59, 58}, + {58, 59, 58, 59}, + {59, 59, 59, 58}, + }, + { + {58, 59, 58, 59}, + {59, 59, 59, 59}, + {59, 59, 58, 59}, + {59, 59, 59, 59}, + }, + { + {59, 59, 59, 59}, + {59, 59, 59, 59}, + {59, 59, 59, 59}, + {60, 59, 59, 59}, + }, + { + {59, 59, 59, 59}, + {60, 59, 60, 59}, + {59, 59, 59, 59}, + {60, 59, 60, 59}, + }, + { + {59, 60, 59, 60}, + {60, 59, 60, 59}, + {59, 60, 59, 60}, + {60, 59, 60, 59}, + }, + { + {59, 60, 59, 60}, + {60, 60, 60, 60}, + {59, 60, 59, 60}, + {60, 60, 60, 60}, + }, + { + {60, 60, 60, 60}, + {60, 60, 60, 60}, + {60, 60, 60, 60}, + {60, 60, 60, 60}, + }, + { + {60, 60, 60, 60}, + {61, 60, 61, 60}, + {60, 60, 60, 60}, + {61, 60, 61, 60}, + }, + { + {60, 61, 60, 61}, + {61, 60, 61, 60}, + {60, 61, 60, 61}, + {61, 60, 61, 60}, + }, + { + {60, 61, 60, 61}, + {61, 61, 61, 61}, + {60, 61, 60, 61}, + {61, 61, 61, 61}, + }, + { + {61, 61, 61, 61}, + {61, 61, 61, 61}, + {61, 61, 61, 61}, + {61, 61, 61, 61}, + }, + { + {61, 61, 61, 61}, + {62, 61, 62, 61}, + {61, 61, 61, 61}, + {62, 61, 62, 61}, + }, + { + {61, 62, 61, 62}, + {62, 61, 62, 61}, + {61, 62, 61, 62}, + {62, 61, 62, 61}, + }, + { + {61, 62, 61, 62}, + {62, 62, 62, 62}, + {61, 62, 61, 62}, + {62, 62, 62, 62}, + }, + { + {62, 62, 62, 62}, + {62, 62, 62, 62}, + {62, 62, 62, 62}, + {62, 62, 62, 62}, + }, + { + {62, 62, 62, 62}, + {63, 62, 63, 62}, + {62, 62, 62, 62}, + {63, 62, 63, 62}, + }, + { + {62, 63, 62, 63}, + {63, 62, 63, 62}, + {62, 63, 62, 63}, + {63, 62, 63, 62}, + }, + { + {62, 63, 62, 63}, + {63, 63, 63, 63}, + {62, 63, 62, 63}, + {63, 63, 63, 63}, + }, + { + {63, 63, 63, 63}, + {63, 63, 63, 63}, + {63, 63, 63, 63}, + {63, 63, 63, 63}, + }, +}; + +uint8_t dither_rb2x2[256][2][2] = +{ + { + {0, 0}, + {0, 0}, + }, + { + {0, 0}, + {1, 0}, + }, + { + {0, 0}, + {1, 0}, + }, + { + {0, 1}, + {1, 0}, + }, + { + {0, 1}, + {1, 0}, + }, + { + {0, 1}, + {1, 1}, + }, + { + {0, 1}, + {1, 1}, + }, + { + {1, 1}, + {1, 1}, + }, + { + {1, 1}, + {1, 1}, + }, + { + {1, 1}, + {2, 1}, + }, + { + {1, 1}, + {2, 1}, + }, + { + {1, 2}, + {2, 1}, + }, + { + {1, 2}, + {2, 1}, + }, + { + {1, 2}, + {2, 2}, + }, + { + {1, 2}, + {2, 2}, + }, + { + {2, 2}, + {2, 2}, + }, + { + {2, 2}, + {2, 2}, + }, + { + {2, 2}, + {2, 2}, + }, + { + {2, 2}, + {3, 2}, + }, + { + {2, 2}, + {3, 2}, + }, + { + {2, 3}, + {3, 2}, + }, + { + {2, 3}, + {3, 2}, + }, + { + {2, 3}, + {3, 3}, + }, + { + {2, 3}, + {3, 3}, + }, + { + {3, 3}, + {3, 3}, + }, + { + {3, 3}, + {3, 3}, + }, + { + {3, 3}, + {4, 3}, + }, + { + {3, 3}, + {4, 3}, + }, + { + {3, 4}, + {4, 3}, + }, + { + {3, 4}, + {4, 3}, + }, + { + {3, 4}, + {4, 4}, + }, + { + {3, 4}, + {4, 4}, + }, + { + {4, 4}, + {4, 4}, + }, + { + {4, 4}, + {4, 4}, + }, + { + {4, 4}, + {5, 4}, + }, + { + {4, 4}, + {5, 4}, + }, + { + {4, 5}, + {5, 4}, + }, + { + {4, 5}, + {5, 4}, + }, + { + {4, 5}, + {5, 5}, + }, + { + {4, 5}, + {5, 5}, + }, + { + {5, 5}, + {5, 5}, + }, + { + {5, 5}, + {5, 5}, + }, + { + {5, 5}, + {6, 5}, + }, + { + {5, 5}, + {6, 5}, + }, + { + {5, 6}, + {6, 5}, + }, + { + {5, 6}, + {6, 5}, + }, + { + {5, 6}, + {6, 6}, + }, + { + {5, 6}, + {6, 6}, + }, + { + {5, 6}, + {6, 6}, + }, + { + {6, 6}, + {6, 6}, + }, + { + {6, 6}, + {6, 6}, + }, + { + {6, 6}, + {7, 6}, + }, + { + {6, 6}, + {7, 6}, + }, + { + {6, 7}, + {7, 6}, + }, + { + {6, 7}, + {7, 6}, + }, + { + {6, 7}, + {7, 7}, + }, + { + {6, 7}, + {7, 7}, + }, + { + {7, 7}, + {7, 7}, + }, + { + {7, 7}, + {7, 7}, + }, + { + {7, 7}, + {8, 7}, + }, + { + {7, 7}, + {8, 7}, + }, + { + {7, 8}, + {8, 7}, + }, + { + {7, 8}, + {8, 7}, + }, + { + {7, 8}, + {8, 8}, + }, + { + {7, 8}, + {8, 8}, + }, + { + {8, 8}, + {8, 8}, + }, + { + {8, 8}, + {8, 8}, + }, + { + {8, 8}, + {9, 8}, + }, + { + {8, 8}, + {9, 8}, + }, + { + {8, 9}, + {9, 8}, + }, + { + {8, 9}, + {9, 8}, + }, + { + {8, 9}, + {9, 9}, + }, + { + {8, 9}, + {9, 9}, + }, + { + {9, 9}, + {9, 9}, + }, + { + {9, 9}, + {9, 9}, + }, + { + {9, 9}, + {10, 9}, + }, + { + {9, 9}, + {10, 9}, + }, + { + {9, 10}, + {10, 9}, + }, + { + {9, 10}, + {10, 9}, + }, + { + {9, 10}, + {10, 10}, + }, + { + {9, 10}, + {10, 10}, + }, + { + {9, 10}, + {10, 10}, + }, + { + {10, 10}, + {10, 10}, + }, + { + {10, 10}, + {10, 10}, + }, + { + {10, 10}, + {11, 10}, + }, + { + {10, 10}, + {11, 10}, + }, + { + {10, 11}, + {11, 10}, + }, + { + {10, 11}, + {11, 10}, + }, + { + {10, 11}, + {11, 11}, + }, + { + {10, 11}, + {11, 11}, + }, + { + {11, 11}, + {11, 11}, + }, + { + {11, 11}, + {11, 11}, + }, + { + {11, 11}, + {12, 11}, + }, + { + {11, 11}, + {12, 11}, + }, + { + {11, 12}, + {12, 11}, + }, + { + {11, 12}, + {12, 11}, + }, + { + {11, 12}, + {12, 12}, + }, + { + {11, 12}, + {12, 12}, + }, + { + {12, 12}, + {12, 12}, + }, + { + {12, 12}, + {12, 12}, + }, + { + {12, 12}, + {13, 12}, + }, + { + {12, 12}, + {13, 12}, + }, + { + {12, 13}, + {13, 12}, + }, + { + {12, 13}, + {13, 12}, + }, + { + {12, 13}, + {13, 13}, + }, + { + {12, 13}, + {13, 13}, + }, + { + {13, 13}, + {13, 13}, + }, + { + {13, 13}, + {13, 13}, + }, + { + {13, 13}, + {14, 13}, + }, + { + {13, 13}, + {14, 13}, + }, + { + {13, 14}, + {14, 13}, + }, + { + {13, 14}, + {14, 13}, + }, + { + {13, 14}, + {14, 13}, + }, + { + {13, 14}, + {14, 14}, + }, + { + {13, 14}, + {14, 14}, + }, + { + {14, 14}, + {14, 14}, + }, + { + {14, 14}, + {14, 14}, + }, + { + {14, 14}, + {15, 14}, + }, + { + {14, 14}, + {15, 14}, + }, + { + {14, 15}, + {15, 14}, + }, + { + {14, 15}, + {15, 14}, + }, + { + {14, 15}, + {15, 15}, + }, + { + {14, 15}, + {15, 15}, + }, + { + {15, 15}, + {15, 15}, + }, + { + {15, 15}, + {15, 15}, + }, + { + {15, 15}, + {16, 15}, + }, + { + {15, 15}, + {16, 15}, + }, + { + {15, 16}, + {16, 15}, + }, + { + {15, 16}, + {16, 15}, + }, + { + {15, 16}, + {16, 16}, + }, + { + {15, 16}, + {16, 16}, + }, + { + {16, 16}, + {16, 16}, + }, + { + {16, 16}, + {16, 16}, + }, + { + {16, 16}, + {17, 16}, + }, + { + {16, 16}, + {17, 16}, + }, + { + {16, 17}, + {17, 16}, + }, + { + {16, 17}, + {17, 16}, + }, + { + {16, 17}, + {17, 17}, + }, + { + {16, 17}, + {17, 17}, + }, + { + {17, 17}, + {17, 17}, + }, + { + {17, 17}, + {17, 17}, + }, + { + {17, 17}, + {18, 17}, + }, + { + {17, 17}, + {18, 17}, + }, + { + {17, 18}, + {18, 17}, + }, + { + {17, 18}, + {18, 17}, + }, + { + {17, 18}, + {18, 18}, + }, + { + {17, 18}, + {18, 18}, + }, + { + {18, 18}, + {18, 18}, + }, + { + {18, 18}, + {18, 18}, + }, + { + {18, 18}, + {19, 18}, + }, + { + {18, 18}, + {19, 18}, + }, + { + {18, 19}, + {19, 18}, + }, + { + {18, 19}, + {19, 18}, + }, + { + {18, 19}, + {19, 19}, + }, + { + {18, 19}, + {19, 19}, + }, + { + {19, 19}, + {19, 19}, + }, + { + {19, 19}, + {19, 19}, + }, + { + {19, 19}, + {20, 19}, + }, + { + {19, 19}, + {20, 19}, + }, + { + {19, 20}, + {20, 19}, + }, + { + {19, 20}, + {20, 19}, + }, + { + {19, 20}, + {20, 19}, + }, + { + {19, 20}, + {20, 20}, + }, + { + {19, 20}, + {20, 20}, + }, + { + {20, 20}, + {20, 20}, + }, + { + {20, 20}, + {20, 20}, + }, + { + {20, 20}, + {21, 20}, + }, + { + {20, 20}, + {21, 20}, + }, + { + {20, 21}, + {21, 20}, + }, + { + {20, 21}, + {21, 20}, + }, + { + {20, 21}, + {21, 21}, + }, + { + {20, 21}, + {21, 21}, + }, + { + {21, 21}, + {21, 21}, + }, + { + {21, 21}, + {21, 21}, + }, + { + {21, 21}, + {22, 21}, + }, + { + {21, 21}, + {22, 21}, + }, + { + {21, 22}, + {22, 21}, + }, + { + {21, 22}, + {22, 21}, + }, + { + {21, 22}, + {22, 22}, + }, + { + {21, 22}, + {22, 22}, + }, + { + {22, 22}, + {22, 22}, + }, + { + {22, 22}, + {22, 22}, + }, + { + {22, 22}, + {23, 22}, + }, + { + {22, 22}, + {23, 22}, + }, + { + {22, 23}, + {23, 22}, + }, + { + {22, 23}, + {23, 22}, + }, + { + {22, 23}, + {23, 23}, + }, + { + {22, 23}, + {23, 23}, + }, + { + {23, 23}, + {23, 23}, + }, + { + {23, 23}, + {23, 23}, + }, + { + {23, 23}, + {24, 23}, + }, + { + {23, 23}, + {24, 23}, + }, + { + {23, 23}, + {24, 23}, + }, + { + {23, 24}, + {24, 23}, + }, + { + {23, 24}, + {24, 23}, + }, + { + {23, 24}, + {24, 24}, + }, + { + {23, 24}, + {24, 24}, + }, + { + {24, 24}, + {24, 24}, + }, + { + {24, 24}, + {24, 24}, + }, + { + {24, 24}, + {25, 24}, + }, + { + {24, 24}, + {25, 24}, + }, + { + {24, 25}, + {25, 24}, + }, + { + {24, 25}, + {25, 24}, + }, + { + {24, 25}, + {25, 25}, + }, + { + {24, 25}, + {25, 25}, + }, + { + {25, 25}, + {25, 25}, + }, + { + {25, 25}, + {25, 25}, + }, + { + {25, 25}, + {26, 25}, + }, + { + {25, 25}, + {26, 25}, + }, + { + {25, 26}, + {26, 25}, + }, + { + {25, 26}, + {26, 25}, + }, + { + {25, 26}, + {26, 26}, + }, + { + {25, 26}, + {26, 26}, + }, + { + {26, 26}, + {26, 26}, + }, + { + {26, 26}, + {26, 26}, + }, + { + {26, 26}, + {27, 26}, + }, + { + {26, 26}, + {27, 26}, + }, + { + {26, 27}, + {27, 26}, + }, + { + {26, 27}, + {27, 26}, + }, + { + {26, 27}, + {27, 27}, + }, + { + {26, 27}, + {27, 27}, + }, + { + {27, 27}, + {27, 27}, + }, + { + {27, 27}, + {27, 27}, + }, + { + {27, 27}, + {28, 27}, + }, + { + {27, 27}, + {28, 27}, + }, + { + {27, 27}, + {28, 27}, + }, + { + {27, 28}, + {28, 27}, + }, + { + {27, 28}, + {28, 27}, + }, + { + {27, 28}, + {28, 28}, + }, + { + {27, 28}, + {28, 28}, + }, + { + {28, 28}, + {28, 28}, + }, + { + {28, 28}, + {28, 28}, + }, + { + {28, 28}, + {29, 28}, + }, + { + {28, 28}, + {29, 28}, + }, + { + {28, 29}, + {29, 28}, + }, + { + {28, 29}, + {29, 28}, + }, + { + {28, 29}, + {29, 29}, + }, + { + {28, 29}, + {29, 29}, + }, + { + {29, 29}, + {29, 29}, + }, + { + {29, 29}, + {29, 29}, + }, + { + {29, 29}, + {30, 29}, + }, + { + {29, 29}, + {30, 29}, + }, + { + {29, 30}, + {30, 29}, + }, + { + {29, 30}, + {30, 29}, + }, + { + {29, 30}, + {30, 30}, + }, + { + {29, 30}, + {30, 30}, + }, + { + {30, 30}, + {30, 30}, + }, + { + {30, 30}, + {30, 30}, + }, + { + {30, 30}, + {31, 30}, + }, + { + {30, 30}, + {31, 30}, + }, + { + {30, 31}, + {31, 30}, + }, + { + {30, 31}, + {31, 30}, + }, + { + {30, 31}, + {31, 31}, + }, + { + {30, 31}, + {31, 31}, + }, + { + {31, 31}, + {31, 31}, + }, + { + {31, 31}, + {31, 31}, + }, +}; + +uint8_t dither_g2x2[256][2][2] = +{ + { + {0, 0}, + {0, 0}, + }, + { + {0, 0}, + {1, 0}, + }, + { + {0, 1}, + {1, 0}, + }, + { + {0, 1}, + {1, 1}, + }, + { + {1, 1}, + {1, 1}, + }, + { + {1, 1}, + {2, 1}, + }, + { + {1, 2}, + {2, 1}, + }, + { + {1, 2}, + {2, 2}, + }, + { + {2, 2}, + {2, 2}, + }, + { + {2, 2}, + {3, 2}, + }, + { + {2, 3}, + {3, 2}, + }, + { + {2, 3}, + {3, 3}, + }, + { + {3, 3}, + {3, 3}, + }, + { + {3, 3}, + {4, 3}, + }, + { + {3, 4}, + {4, 3}, + }, + { + {3, 4}, + {4, 4}, + }, + { + {4, 4}, + {4, 4}, + }, + { + {4, 4}, + {5, 4}, + }, + { + {4, 5}, + {5, 4}, + }, + { + {4, 5}, + {5, 5}, + }, + { + {5, 5}, + {5, 5}, + }, + { + {5, 5}, + {6, 5}, + }, + { + {5, 6}, + {6, 5}, + }, + { + {5, 6}, + {6, 6}, + }, + { + {6, 6}, + {6, 6}, + }, + { + {6, 6}, + {7, 6}, + }, + { + {6, 7}, + {7, 6}, + }, + { + {6, 7}, + {7, 7}, + }, + { + {7, 7}, + {7, 7}, + }, + { + {7, 7}, + {8, 7}, + }, + { + {7, 8}, + {8, 7}, + }, + { + {7, 8}, + {8, 8}, + }, + { + {8, 8}, + {8, 8}, + }, + { + {8, 8}, + {9, 8}, + }, + { + {8, 9}, + {9, 8}, + }, + { + {8, 9}, + {9, 9}, + }, + { + {9, 9}, + {9, 9}, + }, + { + {9, 9}, + {10, 9}, + }, + { + {9, 10}, + {10, 9}, + }, + { + {9, 10}, + {10, 10}, + }, + { + {10, 10}, + {10, 10}, + }, + { + {10, 10}, + {11, 10}, + }, + { + {10, 11}, + {11, 10}, + }, + { + {10, 11}, + {11, 11}, + }, + { + {11, 11}, + {11, 11}, + }, + { + {11, 11}, + {12, 11}, + }, + { + {11, 12}, + {12, 11}, + }, + { + {11, 12}, + {12, 12}, + }, + { + {11, 12}, + {12, 12}, + }, + { + {12, 12}, + {12, 12}, + }, + { + {12, 12}, + {13, 12}, + }, + { + {12, 13}, + {13, 12}, + }, + { + {12, 13}, + {13, 13}, + }, + { + {13, 13}, + {13, 13}, + }, + { + {13, 13}, + {14, 13}, + }, + { + {13, 14}, + {14, 13}, + }, + { + {13, 14}, + {14, 14}, + }, + { + {14, 14}, + {14, 14}, + }, + { + {14, 14}, + {15, 14}, + }, + { + {14, 15}, + {15, 14}, + }, + { + {14, 15}, + {15, 15}, + }, + { + {15, 15}, + {15, 15}, + }, + { + {15, 15}, + {16, 15}, + }, + { + {15, 16}, + {16, 15}, + }, + { + {15, 16}, + {16, 16}, + }, + { + {16, 16}, + {16, 16}, + }, + { + {16, 16}, + {17, 16}, + }, + { + {16, 17}, + {17, 16}, + }, + { + {16, 17}, + {17, 17}, + }, + { + {17, 17}, + {17, 17}, + }, + { + {17, 17}, + {18, 17}, + }, + { + {17, 18}, + {18, 17}, + }, + { + {17, 18}, + {18, 18}, + }, + { + {18, 18}, + {18, 18}, + }, + { + {18, 18}, + {19, 18}, + }, + { + {18, 19}, + {19, 18}, + }, + { + {18, 19}, + {19, 19}, + }, + { + {19, 19}, + {19, 19}, + }, + { + {19, 19}, + {20, 19}, + }, + { + {19, 20}, + {20, 19}, + }, + { + {19, 20}, + {20, 20}, + }, + { + {20, 20}, + {20, 20}, + }, + { + {20, 20}, + {21, 20}, + }, + { + {20, 21}, + {21, 20}, + }, + { + {20, 21}, + {21, 21}, + }, + { + {21, 21}, + {21, 21}, + }, + { + {21, 21}, + {22, 21}, + }, + { + {21, 22}, + {22, 21}, + }, + { + {21, 22}, + {22, 22}, + }, + { + {22, 22}, + {22, 22}, + }, + { + {22, 22}, + {23, 22}, + }, + { + {22, 23}, + {23, 22}, + }, + { + {22, 23}, + {23, 23}, + }, + { + {23, 23}, + {23, 23}, + }, + { + {23, 23}, + {24, 23}, + }, + { + {23, 24}, + {24, 23}, + }, + { + {23, 24}, + {24, 24}, + }, + { + {24, 24}, + {24, 24}, + }, + { + {24, 24}, + {25, 24}, + }, + { + {24, 25}, + {25, 24}, + }, + { + {24, 25}, + {25, 25}, + }, + { + {25, 25}, + {25, 25}, + }, + { + {25, 25}, + {26, 25}, + }, + { + {25, 26}, + {26, 25}, + }, + { + {25, 26}, + {26, 26}, + }, + { + {26, 26}, + {26, 26}, + }, + { + {26, 26}, + {27, 26}, + }, + { + {26, 27}, + {27, 26}, + }, + { + {26, 27}, + {27, 27}, + }, + { + {27, 27}, + {27, 27}, + }, + { + {27, 27}, + {28, 27}, + }, + { + {27, 28}, + {28, 27}, + }, + { + {27, 28}, + {28, 28}, + }, + { + {28, 28}, + {28, 28}, + }, + { + {28, 28}, + {29, 28}, + }, + { + {28, 29}, + {29, 28}, + }, + { + {28, 29}, + {29, 29}, + }, + { + {29, 29}, + {29, 29}, + }, + { + {29, 29}, + {30, 29}, + }, + { + {29, 30}, + {30, 29}, + }, + { + {29, 30}, + {30, 30}, + }, + { + {30, 30}, + {30, 30}, + }, + { + {30, 30}, + {31, 30}, + }, + { + {30, 31}, + {31, 30}, + }, + { + {30, 31}, + {31, 31}, + }, + { + {31, 31}, + {31, 31}, + }, + { + {31, 31}, + {32, 31}, + }, + { + {31, 32}, + {32, 31}, + }, + { + {31, 32}, + {32, 32}, + }, + { + {32, 32}, + {32, 32}, + }, + { + {32, 32}, + {33, 32}, + }, + { + {32, 33}, + {33, 32}, + }, + { + {32, 33}, + {33, 33}, + }, + { + {33, 33}, + {33, 33}, + }, + { + {33, 33}, + {34, 33}, + }, + { + {33, 34}, + {34, 33}, + }, + { + {33, 34}, + {34, 34}, + }, + { + {34, 34}, + {34, 34}, + }, + { + {34, 34}, + {35, 34}, + }, + { + {34, 35}, + {35, 34}, + }, + { + {34, 35}, + {35, 35}, + }, + { + {35, 35}, + {35, 35}, + }, + { + {35, 35}, + {36, 35}, + }, + { + {35, 36}, + {36, 35}, + }, + { + {35, 36}, + {36, 35}, + }, + { + {35, 36}, + {36, 36}, + }, + { + {36, 36}, + {36, 36}, + }, + { + {36, 36}, + {37, 36}, + }, + { + {36, 37}, + {37, 36}, + }, + { + {36, 37}, + {37, 37}, + }, + { + {37, 37}, + {37, 37}, + }, + { + {37, 37}, + {38, 37}, + }, + { + {37, 38}, + {38, 37}, + }, + { + {37, 38}, + {38, 38}, + }, + { + {38, 38}, + {38, 38}, + }, + { + {38, 38}, + {39, 38}, + }, + { + {38, 39}, + {39, 38}, + }, + { + {38, 39}, + {39, 39}, + }, + { + {39, 39}, + {39, 39}, + }, + { + {39, 39}, + {40, 39}, + }, + { + {39, 40}, + {40, 39}, + }, + { + {39, 40}, + {40, 40}, + }, + { + {40, 40}, + {40, 40}, + }, + { + {40, 40}, + {41, 40}, + }, + { + {40, 41}, + {41, 40}, + }, + { + {40, 41}, + {41, 41}, + }, + { + {41, 41}, + {41, 41}, + }, + { + {41, 41}, + {42, 41}, + }, + { + {41, 42}, + {42, 41}, + }, + { + {41, 42}, + {42, 42}, + }, + { + {42, 42}, + {42, 42}, + }, + { + {42, 42}, + {43, 42}, + }, + { + {42, 43}, + {43, 42}, + }, + { + {42, 43}, + {43, 43}, + }, + { + {43, 43}, + {43, 43}, + }, + { + {43, 43}, + {44, 43}, + }, + { + {43, 44}, + {44, 43}, + }, + { + {43, 44}, + {44, 44}, + }, + { + {44, 44}, + {44, 44}, + }, + { + {44, 44}, + {45, 44}, + }, + { + {44, 45}, + {45, 44}, + }, + { + {44, 45}, + {45, 45}, + }, + { + {45, 45}, + {45, 45}, + }, + { + {45, 45}, + {46, 45}, + }, + { + {45, 46}, + {46, 45}, + }, + { + {45, 46}, + {46, 46}, + }, + { + {46, 46}, + {46, 46}, + }, + { + {46, 46}, + {47, 46}, + }, + { + {46, 47}, + {47, 46}, + }, + { + {46, 47}, + {47, 47}, + }, + { + {47, 47}, + {47, 47}, + }, + { + {47, 47}, + {48, 47}, + }, + { + {47, 48}, + {48, 47}, + }, + { + {47, 48}, + {48, 48}, + }, + { + {48, 48}, + {48, 48}, + }, + { + {48, 48}, + {49, 48}, + }, + { + {48, 49}, + {49, 48}, + }, + { + {48, 49}, + {49, 49}, + }, + { + {49, 49}, + {49, 49}, + }, + { + {49, 49}, + {50, 49}, + }, + { + {49, 50}, + {50, 49}, + }, + { + {49, 50}, + {50, 50}, + }, + { + {50, 50}, + {50, 50}, + }, + { + {50, 50}, + {51, 50}, + }, + { + {50, 51}, + {51, 50}, + }, + { + {50, 51}, + {51, 51}, + }, + { + {51, 51}, + {51, 51}, + }, + { + {51, 51}, + {52, 51}, + }, + { + {51, 52}, + {52, 51}, + }, + { + {51, 52}, + {52, 52}, + }, + { + {52, 52}, + {52, 52}, + }, + { + {52, 52}, + {53, 52}, + }, + { + {52, 53}, + {53, 52}, + }, + { + {52, 53}, + {53, 53}, + }, + { + {53, 53}, + {53, 53}, + }, + { + {53, 53}, + {54, 53}, + }, + { + {53, 54}, + {54, 53}, + }, + { + {53, 54}, + {54, 54}, + }, + { + {54, 54}, + {54, 54}, + }, + { + {54, 54}, + {55, 54}, + }, + { + {54, 55}, + {55, 54}, + }, + { + {54, 55}, + {55, 55}, + }, + { + {55, 55}, + {55, 55}, + }, + { + {55, 55}, + {56, 55}, + }, + { + {55, 55}, + {56, 55}, + }, + { + {55, 56}, + {56, 55}, + }, + { + {55, 56}, + {56, 56}, + }, + { + {56, 56}, + {56, 56}, + }, + { + {56, 56}, + {57, 56}, + }, + { + {56, 57}, + {57, 56}, + }, + { + {56, 57}, + {57, 57}, + }, + { + {57, 57}, + {57, 57}, + }, + { + {57, 57}, + {58, 57}, + }, + { + {57, 58}, + {58, 57}, + }, + { + {57, 58}, + {58, 58}, + }, + { + {58, 58}, + {58, 58}, + }, + { + {58, 58}, + {59, 58}, + }, + { + {58, 59}, + {59, 58}, + }, + { + {58, 59}, + {59, 59}, + }, + { + {59, 59}, + {59, 59}, + }, + { + {59, 59}, + {60, 59}, + }, + { + {59, 60}, + {60, 59}, + }, + { + {59, 60}, + {60, 60}, + }, + { + {60, 60}, + {60, 60}, + }, + { + {60, 60}, + {61, 60}, + }, + { + {60, 61}, + {61, 60}, + }, + { + {60, 61}, + {61, 61}, + }, + { + {61, 61}, + {61, 61}, + }, + { + {61, 61}, + {62, 61}, + }, + { + {61, 62}, + {62, 61}, + }, + { + {61, 62}, + {62, 62}, + }, + { + {62, 62}, + {62, 62}, + }, + { + {62, 62}, + {63, 62}, + }, + { + {62, 63}, + {63, 62}, + }, + { + {62, 63}, + {63, 63}, + }, + { + {63, 63}, + {63, 63}, + }, +}; + diff --git a/src/video.c b/src/video.c new file mode 100644 index 000000000..40d6540df --- /dev/null +++ b/src/video.c @@ -0,0 +1,495 @@ +#include +#include +#include +#include +#include "ibm.h" +#include "device.h" +#include "mem.h" +#include "video.h" +#include "vid_svga.h" +#include "io.h" +#include "cpu.h" +#include "rom.h" +#include "timer.h" + +#include "vid_ati18800.h" +#include "vid_ati28800.h" +#include "vid_ati_mach64.h" +#include "vid_cga.h" +#include "vid_cl5429.h" +#include "vid_ega.h" +#include "vid_et4000.h" +#include "vid_et4000w32.h" +#include "vid_hercules.h" +#include "vid_mda.h" +#include "vid_olivetti_m24.h" +#include "vid_oti067.h" +#include "vid_paradise.h" +#include "vid_pc1512.h" +#include "vid_pc1640.h" +#include "vid_pc200.h" +#include "vid_pcjr.h" +#include "vid_ps1_svga.h" +#include "vid_s3.h" +#include "vid_s3_virge.h" +#include "vid_tandy.h" +#include "vid_tandysl.h" +#include "vid_tgui9440.h" +#include "vid_tvga.h" +#include "vid_vga.h" + +typedef struct +{ + char name[64]; + device_t *device; + int legacy_id; +} VIDEO_CARD; + +static VIDEO_CARD video_cards[] = +{ + {"ATI Graphics Pro Turbo (Mach64 GX)", &mach64gx_device, GFX_MACH64GX}, + {"ATI VGA Charger (ATI-28800)", &ati28800_device, GFX_VGACHARGER}, + {"ATI VGA Edge-16 (ATI-18800)", &ati18800_device, GFX_VGAEDGE16}, + {"Cardex Tseng ET4000/w32p", &et4000w32pc_device, GFX_ET4000W32C}, + {"CGA (New)", &cga_new_device, GFX_NEW_CGA}, + {"CGA (Old)", &cga_device, GFX_CGA}, + {"Cirrus Logic CL-GD5429", &gd5429_device, GFX_CL_GD5429}, + {"Diamond Stealth 32 (Tseng ET4000/w32p)", &et4000w32p_device, GFX_ET4000W32}, + {"Diamond Stealth 3D 2000 (S3 ViRGE)", &s3_virge_device, GFX_VIRGE}, + {"EGA", &ega_device, GFX_EGA}, + {"Chips & Technologies SuperEGA", &sega_device, GFX_SUPER_EGA}, + {"Compaq ATI VGA Wonder XL (ATI-28800)", &compaq_ati28800_device, GFX_VGAWONDERXL}, + {"Compaq EGA", &cpqega_device, GFX_COMPAQ_EGA}, + {"Compaq/Paradise VGA", &cpqvga_device, GFX_COMPAQ_VGA}, + {"Hercules", &hercules_device, GFX_HERCULES}, + {"Hercules InColor", &hercules_device, GFX_INCOLOR}, + {"MDA", &mda_device, GFX_MDA}, + {"Miro Crystal S3 Vision964", &s3_miro_vision964_device, GFX_MIRO_VISION964}, + {"Number Nine 9FX (S3 Trio64)", &s3_9fx_device, GFX_N9_9FX}, + {"OAK OTI-067", &oti067_device, GFX_OTI067}, + {"OAK OTI-077", &oti077_device, GFX_OTI077}, + {"Paradise Bahamas 64 (S3 Vision864)", &s3_bahamas64_device, GFX_BAHAMAS64}, + {"Paradise WD90C11", ¶dise_wd90c11_device, GFX_WD90C11}, + {"Phoenix S3 Trio32", &s3_phoenix_trio32_device, GFX_PHOENIX_TRIO32}, + {"Phoenix S3 Trio64", &s3_phoenix_trio64_device, GFX_PHOENIX_TRIO64}, + {"S3 ViRGE/DX", &s3_virge_375_device, GFX_VIRGEDX}, + {"Trident TVGA8900D", &tvga8900d_device, GFX_TVGA}, + {"Tseng ET4000AX", &et4000_device, GFX_ET4000}, + {"Trident TGUI9440", &tgui9440_device, GFX_TGUI9440}, + {"VGA", &vga_device, GFX_VGA}, + {"", NULL, 0} +}; + +int video_card_available(int card) +{ + if (video_cards[card].device) + return device_available(video_cards[card].device); + + return 1; +} + +char *video_card_getname(int card) +{ + return video_cards[card].name; +} + +device_t *video_card_getdevice(int card) +{ + return video_cards[card].device; +} + +int video_card_has_config(int card) +{ + return video_cards[card].device->config ? 1 : 0; +} + +int video_card_getid(char *s) +{ + int c = 0; + + while (video_cards[c].device) + { + if (!strcmp(video_cards[c].name, s)) + return c; + c++; + } + + return 0; +} + +int video_old_to_new(int card) +{ + int c = 0; + + while (video_cards[c].device) + { + if (video_cards[c].legacy_id == card) + return c; + c++; + } + + return 0; +} + +int video_new_to_old(int card) +{ + return video_cards[card].legacy_id; +} + +int video_fullscreen = 0, video_fullscreen_scale, video_fullscreen_first; +uint32_t *video_15to32, *video_16to32; + +int egareads=0,egawrites=0; +int changeframecount=2; + +uint8_t rotatevga[8][256]; + +int frames = 0; + +int fullchange; + +uint8_t edatlookup[4][4]; + +int enable_overscan; +int overscan_x, overscan_y; +int force_43; +int enable_flash; + +/*Video timing settings - + +8-bit - 1mb/sec + B = 8 ISA clocks + W = 16 ISA clocks + L = 32 ISA clocks + +Slow 16-bit - 2mb/sec + B = 6 ISA clocks + W = 8 ISA clocks + L = 16 ISA clocks + +Fast 16-bit - 4mb/sec + B = 3 ISA clocks + W = 3 ISA clocks + L = 6 ISA clocks + +Slow VLB/PCI - 8mb/sec (ish) + B = 4 bus clocks + W = 8 bus clocks + L = 16 bus clocks + +Mid VLB/PCI - + B = 4 bus clocks + W = 5 bus clocks + L = 10 bus clocks + +Fast VLB/PCI - + B = 3 bus clocks + W = 3 bus clocks + L = 4 bus clocks +*/ + +enum +{ + VIDEO_ISA = 0, + VIDEO_BUS +}; + +int video_speed = 0; +int video_timing[6][4] = +{ + {VIDEO_ISA, 8, 16, 32}, + {VIDEO_ISA, 6, 8, 16}, + {VIDEO_ISA, 3, 3, 6}, + {VIDEO_BUS, 4, 8, 16}, + {VIDEO_BUS, 4, 5, 10}, + {VIDEO_BUS, 3, 3, 4} +}; + +void video_updatetiming() +{ + if (video_timing[video_speed][0] == VIDEO_ISA) + { + video_timing_b = (int)(isa_timing * video_timing[video_speed][1]); + video_timing_w = (int)(isa_timing * video_timing[video_speed][2]); + video_timing_l = (int)(isa_timing * video_timing[video_speed][3]); + } + else + { + video_timing_b = (int)(bus_timing * video_timing[video_speed][1]); + video_timing_w = (int)(bus_timing * video_timing[video_speed][2]); + video_timing_l = (int)(bus_timing * video_timing[video_speed][3]); + } + if (cpu_16bitbus) + video_timing_l = video_timing_w * 2; +} + +int video_timing_b, video_timing_w, video_timing_l; + +int video_res_x, video_res_y, video_bpp; + +void (*video_blit_memtoscreen)(int x, int y, int y1, int y2, int w, int h); +void (*video_blit_memtoscreen_8)(int x, int y, int w, int h); + +void video_init() +{ + pclog("Video_init %i %i\n",romset,gfxcard); + + switch (romset) + { + case ROM_IBMPCJR: + device_add(&pcjr_video_device); + return; + + case ROM_TANDY: + case ROM_TANDY1000HX: + device_add(&tandy_device); + return; + + case ROM_TANDY1000SL2: + device_add(&tandysl_device); + return; + + case ROM_PC1512: + device_add(&pc1512_device); + return; + + case ROM_PC1640: + device_add(&pc1640_device); + return; + + case ROM_PC200: + device_add(&pc200_device); + return; + + case ROM_OLIM24: + device_add(&m24_device); + return; + + case ROM_PC2086: + device_add(¶dise_pvga1a_pc2086_device); + return; + + case ROM_PC3086: + device_add(¶dise_pvga1a_pc3086_device); + return; + + case ROM_MEGAPC: + device_add(¶dise_wd90c11_megapc_device); + return; + + case ROM_ACER386: + device_add(&oti067_device); + return; + + case ROM_IBMPS1_2011: + device_add(&ps1vga_device); + return; + + case ROM_IBMPS1_2121: + device_add(&ps1_m2121_svga_device); + return; + } + device_add(video_cards[video_old_to_new(gfxcard)].device); +} + + +BITMAP *buffer, *buffer32; + +uint8_t fontdat[256][8]; +uint8_t fontdatm[256][16]; + +int xsize=1,ysize=1; + +PALETTE cgapal; + +void loadfont(char *s, int format) +{ + FILE *f=romfopen(s,"rb"); + int c,d; + if (!f) + return; + + if (!format) + { + for (c=0;c<256;c++) + { + for (d=0;d<8;d++) + { + fontdatm[c][d]=getc(f); + } + } + for (c=0;c<256;c++) + { + for (d=0;d<8;d++) + { + fontdatm[c][d+8]=getc(f); + } + } + fseek(f,4096+2048,SEEK_SET); + for (c=0;c<256;c++) + { + for (d=0;d<8;d++) + { + fontdat[c][d]=getc(f); + } + } + } + else if (format == 1) + { + for (c=0;c<256;c++) + { + for (d=0;d<8;d++) + { + fontdatm[c][d]=getc(f); + } + } + for (c=0;c<256;c++) + { + for (d=0;d<8;d++) + { + fontdatm[c][d+8]=getc(f); + } + } + fseek(f, 4096, SEEK_SET); + for (c=0;c<256;c++) + { + for (d=0;d<8;d++) + { + fontdat[c][d]=getc(f); + } + for (d=0;d<8;d++) getc(f); + } + } + else + { + for (c=0;c<256;c++) + { + for (d=0;d<8;d++) + { + fontdat[c][d]=getc(f); + } + } + } + fclose(f); +} + + +void initvideo() +{ + int c, d, e; + + /* Account for overscan. */ + buffer32 = create_bitmap(2064, 2056); + + buffer = create_bitmap(2064, 2056); + + for (c = 0; c < 64; c++) + { + cgapal[c + 64].r = (((c & 4) ? 2 : 0) | ((c & 0x10) ? 1 : 0)) * 21; + cgapal[c + 64].g = (((c & 2) ? 2 : 0) | ((c & 0x10) ? 1 : 0)) * 21; + cgapal[c + 64].b = (((c & 1) ? 2 : 0) | ((c & 0x10) ? 1 : 0)) * 21; + if ((c & 0x17) == 6) + cgapal[c + 64].g >>= 1; + } + for (c = 0; c < 64; c++) + { + cgapal[c + 128].r = (((c & 4) ? 2 : 0) | ((c & 0x20) ? 1 : 0)) * 21; + cgapal[c + 128].g = (((c & 2) ? 2 : 0) | ((c & 0x10) ? 1 : 0)) * 21; + cgapal[c + 128].b = (((c & 1) ? 2 : 0) | ((c & 0x08) ? 1 : 0)) * 21; + } + + for (c = 0; c < 256; c++) + { + e = c; + for (d = 0; d < 8; d++) + { + rotatevga[d][c] = e; + e = (e >> 1) | ((e & 1) ? 0x80 : 0); + } + } + for (c = 0; c < 4; c++) + { + for (d = 0; d < 4; d++) + { + edatlookup[c][d] = 0; + if (c & 1) edatlookup[c][d] |= 1; + if (d & 1) edatlookup[c][d] |= 2; + if (c & 2) edatlookup[c][d] |= 0x10; + if (d & 2) edatlookup[c][d] |= 0x20; +// printf("Edat %i,%i now %02X\n",c,d,edatlookup[c][d]); + } + } + + video_15to32 = malloc(4 * 65536); + for (c = 0; c < 65536; c++) + video_15to32[c] = ((c & 31) << 3) | (((c >> 5) & 31) << 11) | (((c >> 10) & 31) << 19); + + video_16to32 = malloc(4 * 65536); + for (c = 0; c < 65536; c++) + video_16to32[c] = ((c & 31) << 3) | (((c >> 5) & 63) << 10) | (((c >> 11) & 31) << 19); + +} + +void closevideo() +{ + free(video_15to32); + free(video_16to32); + destroy_bitmap(buffer); + destroy_bitmap(buffer32); +} + +#ifdef __unix +void d3d_fs_take_screenshot(char *fn) +{ +} + +void d3d_take_screenshot(char *fn) +{ +} + +void ddraw_fs_take_screenshot(char *fn) +{ +} + +void ddraw_take_screenshot(char *fn) +{ +} + +void take_screenshot() +{ +} +#else +void take_screenshot() +{ + char fn[1024]; + time_t now = time(0); + if ((vid_api < 0) || (vid_api > 1)) return; + memset(fn, 0, 1024); + pclog("Video API is: %i\n", vid_api); + if (vid_api == 1) + { + strftime(fn, 1024, "screenshots/%Y%m%d_%H%M%S.png", localtime(&now)); + if (video_fullscreen) + { + d3d_fs_take_screenshot(fn); + } + else + { + pclog("Direct 3D...\n"); + d3d_take_screenshot(fn); + } + } + else if (vid_api == 0) + { + strftime(fn, 1024, "screenshots/%Y%m%d_%H%M%S.bmp", localtime(&now)); + if (video_fullscreen) + { + ddraw_fs_take_screenshot(fn); + } + else + { + ddraw_take_screenshot(fn); + } + } +} +#endif diff --git a/src/video.h b/src/video.h new file mode 100644 index 000000000..6c411cf8e --- /dev/null +++ b/src/video.h @@ -0,0 +1,105 @@ +#ifdef __unix + +#include "allegro-main.h" + +#else + +typedef struct +{ + int w, h; + uint8_t *dat; + uint8_t *line[0]; +} BITMAP; + +extern BITMAP *screen; + +BITMAP *create_bitmap(int w, int h); + +typedef struct +{ + uint8_t r, g, b; +} RGB; + +typedef RGB PALETTE[256]; + +#define makecol(r, g, b) ((b) | ((g) << 8) | ((r) << 16)) +#define makecol32(r, g, b) ((b) | ((g) << 8) | ((r) << 16)) + +#endif + +extern BITMAP *buffer, *buffer32; + +int video_card_available(int card); +char *video_card_getname(int card); +struct device_t *video_card_getdevice(int card); +int video_card_has_config(int card); +int video_card_getid(char *s); +int video_old_to_new(int card); +int video_new_to_old(int card); + +extern int video_fullscreen, video_fullscreen_scale, video_fullscreen_first; + +enum +{ + FULLSCR_SCALE_FULL = 0, + FULLSCR_SCALE_43, + FULLSCR_SCALE_SQ, + FULLSCR_SCALE_INT +}; + +extern int egareads,egawrites; + +extern int fullchange; +extern int changeframecount; + +extern uint8_t fontdat[256][8]; +extern uint8_t fontdatm[256][16]; + +extern uint32_t *video_15to32, *video_16to32; + +extern int xsize,ysize; + +extern float cpuclock; + +extern int emu_fps, frames; + +extern int readflash; + +extern void (*video_recalctimings)(); + +extern void (*video_blit_memtoscreen)(int x, int y, int y1, int y2, int w, int h); +extern void (*video_blit_memtoscreen_8)(int x, int y, int w, int h); + +/* Enable EGA/(S)VGA overscan border. */ +extern int enable_overscan; +extern int overscan_x, overscan_y; +/* Forcibly stretch emulated video output to 4:3 or not. */ +extern int force_43; +/* Enable CGA brown circuitry. */ +extern int cga_brown; +/* Enable CGA color burst. */ +extern int cga_color_burst; +/* Enable disk activity flash. */ +extern int enable_flash; + +extern int video_timing_b, video_timing_w, video_timing_l; +extern int video_speed; + +extern int video_res_x, video_res_y, video_bpp; + +extern int vid_resize; + +extern int winsizex,winsizey; + +#ifdef __cplusplus +extern "C" { +#endif +void take_screenshot(); + +void d3d_take_screenshot(char *fn); +void d3d_fs_take_screenshot(char *fn); +void ddraw_take_screenshot(char *fn); +void ddraw_fs_take_screenshot(char *fn); +#ifdef __cplusplus +} +#endif diff --git a/src/w83877f.c b/src/w83877f.c new file mode 100644 index 000000000..d94fdfa3b --- /dev/null +++ b/src/w83877f.c @@ -0,0 +1,520 @@ +/* + Winbond W83877F Super I/O Chip + Used by the Award 430HX +*/ + +#include "ibm.h" + +#include "fdc.h" +#include "fdd.h" +#include "disc.h" +#include "io.h" +#include "lpt.h" +// #include "mouse_serial.h" +#include "serial.h" +#include "w83877f.h" + +static int w83877f_locked; +static int w83877f_rw_locked = 0; +static int w83877f_curreg = 0; +static uint8_t w83877f_regs[0x2A]; +static uint8_t tries; + +static int winbond_port = 0x3f0; +static int winbond_key = 0x89; +static int winbond_key_times = 1; + +void w83877f_write(uint16_t port, uint8_t val, void *priv); +uint8_t w83877f_read(uint16_t port, void *priv); + +#define OCSS0 (w83877f_regs[0] & 1) +#define OCSS1 ((w83877f_regs[0] >> 1) & 1) +#define PRTMODS0 ((w83877f_regs[0] >> 2) & 1) +#define PRTMODS1 ((w83877f_regs[0] >> 3) & 1) + +#define ABCHG (w83877f_regs[1] >> 7) + +#define CEA (w83877f_regs[2] & 1) +#define EA3 ((w83877f_regs[2] >> 1) & 1) +#define EA4 ((w83877f_regs[2] >> 2) & 1) +#define EA5 ((w83877f_regs[2] >> 3) & 1) +#define EA6 ((w83877f_regs[2] >> 4) & 1) +#define EA7 ((w83877f_regs[2] >> 5) & 1) +#define EA8 ((w83877f_regs[2] >> 6) & 1) +#define EA9 (w83877f_regs[2] >> 7) + +#define SUBMIDI (w83877f_regs[3] & 1) +#define SUAMIDI ((w83877f_regs[3] >> 1) & 1) +#define GMODS ((w83877f_regs[3] >> 4) & 1) +#define EPPVER ((w83877f_regs[3] >> 5) & 1) +#define GMENL ((w83877f_regs[3] >> 6) & 1) + +#define URBTRI (w83877f_regs[4] & 1) +#define URATRI ((w83877f_regs[4] >> 1) & 1) +#define GMTRI ((w83877f_regs[4] >> 2) & 1) +#define PRTTRI ((w83877f_regs[4] >> 3) & 1) +#define URBPWD ((w83877f_regs[4] >> 4) & 1) +#define URAPWD ((w83877f_regs[4] >> 5) & 1) +#define GMPWD ((w83877f_regs[4] >> 6) & 1) +#define PRTPWD (w83877f_regs[4] >> 7) + +#define ECPFTHR0 (w83877f_regs[5] & 1) +#define ECPFTHR1 ((w83877f_regs[5] >> 1) & 1) +#define ECPFTHR2 ((w83877f_regs[5] >> 2) & 1) +#define ECPFTHR3 ((w83877f_regs[5] >> 3) & 1) + +#define IDETRI (w83877f_regs[6] & 1) +#define FDCTRI ((w83877f_regs[6] >> 1) & 1) +#define IDEPWD ((w83877f_regs[6] >> 2) & 1) +#define FDCPWD ((w83877f_regs[6] >> 3) & 1) +#define FIPURDWM ((w83877f_regs[6] >> 4) & 1) +#define SEL4FDD ((w83877f_regs[6] >> 5) & 1) +#define OSCS2 ((w83877f_regs[6] >> 6) & 1) + +#define FDDA_TYPE (w83877f_regs[7] & 3) +#define FDDB_TYPE ((w83877f_regs[7] >> 2) & 3) +#define FDDC_TYPE ((w83877f_regs[7] >> 4) & 3) +#define FDDD_TYPE ((w83877f_regs[7] >> 6) & 3) + +#define FD_BOOT (w83877f_regs[8] & 3) +#define MEDIA_ID ((w83877f_regs[8] >> 2) & 3) +#define SWWP ((w83877f_regs[8] >> 4) & 1) +#define DISFDDWR ((w83877f_regs[8] >> 5) & 1) +#define APDTMS2 ((w83877f_regs[8] >> 6) & 1) +#define APDTMS1 (w83877f_regs[8] >> 7) + +#define CHIP_ID (w83877f_regs[9] & 0xF) +#define EN3MODE ((w83877f_regs[9] >> 5) & 1) +#define LOCKREG ((w83877f_regs[9] >> 6) & 1) +#define PRTMODS2 ((w83877f_regs[9] >> 7) & 1) + +#define PEXTECPP (w83877f_regs[0xA] & 1) +#define PEXT_ECP ((w83877f_regs[0xA] >> 1) & 1) +#define PEXT_EPP ((w83877f_regs[0xA] >> 2) & 1) +#define PEXT_ADP ((w83877f_regs[0xA] >> 3) & 1) +#define PDCACT ((w83877f_regs[0xA] >> 4) & 1) +#define PDIRHOP ((w83877f_regs[0xA] >> 5) & 1) +#define PEXT_ACT ((w83877f_regs[0xA] >> 6) & 1) +#define PFDCACT (w83877f_regs[0xA] >> 7) + +#define DRV2EN_NEG (w83877f_regs[0xB] & 1) /* 0 = drive 2 installed */ +#define INVERTZ ((w83877f_regs[0xB] >> 1) & 1) /* 0 = invert DENSEL polarity */ +#define MFM ((w83877f_regs[0xB] >> 2) & 1) +#define IDENT ((w83877f_regs[0xB] >> 3) & 1) +#define ENIFCHG ((w83877f_regs[0xB] >> 4) & 1) + +#define TX2INV (w83877f_regs[0xC] & 1) +#define RX2INV ((w83877f_regs[0xC] >> 1) & 1) +#define URIRSEL ((w83877f_regs[0xC] >> 3) & 1) +#define HEFERE ((w83877f_regs[0xC] >> 5) & 1) +#define TURB ((w83877f_regs[0xC] >> 6) & 1) +#define TURA (w83877f_regs[0xC] >> 7) + +#define IRMODE0 (w83877f_regs[0xD] & 1) +#define IRMODE1 ((w83877f_regs[0xD] >> 1) & 1) +#define IRMODE2 ((w83877f_regs[0xD] >> 2) & 1) +#define HDUPLX ((w83877f_regs[0xD] >> 3) & 1) +#define SIRRX0 ((w83877f_regs[0xD] >> 4) & 1) +#define SIRRX1 ((w83877f_regs[0xD] >> 5) & 1) +#define SIRTX0 ((w83877f_regs[0xD] >> 6) & 1) +#define SIRTX1 (w83877f_regs[0xD] >> 7) + +#define GIO0AD (w83877f_regs[0x10] | (((uint16_t) w83877f_regs[0x10] & 7) << 8)) +#define GIO0CADM (w83877f_regs[0x11] >> 6) +#define GIO1AD (w83877f_regs[0x12] | (((uint16_t) w83877f_regs[0x13] & 7) << 8)) +#define GIO1CADM (w83877f_regs[0x13] >> 6) + +#define GDA0IPI (w83877f_regs[0x14] & 1) +#define GDA0OPI ((w83877f_regs[0x14] >> 1) & 1) +#define GCS0IOW ((w83877f_regs[0x14] >> 2) & 1) +#define GCS0IOR ((w83877f_regs[0x14] >> 3) & 1) +#define GIO0CSH ((w83877f_regs[0x14] >> 4) & 1) +#define GIOP0MD ((w83877f_regs[0x14] >> 5) & 7) + +#define GDA1IPI (w83877f_regs[0x15] & 1) +#define GDA1OPI ((w83877f_regs[0x15] >> 1) & 1) +#define GCS1IOW ((w83877f_regs[0x15] >> 2) & 1) +#define GCS1IOR ((w83877f_regs[0x15] >> 3) & 1) +#define GIO1CSH ((w83877f_regs[0x15] >> 4) & 1) +#define GIOP1MD ((w83877f_regs[0x15] >> 5) & 7) + +#define HEFRAS (w83877f_regs[0x16] & 1) +#define IRIDE ((w83877f_regs[0x16] >> 1) & 1) +#define PNPCVS ((w83877f_regs[0x16] >> 2) & 1) +#define GMDRQ ((w83877f_regs[0x16] >> 3) & 1) +#define GOIQSEL ((w83877f_regs[0x16] >> 4) & 1) + +#define DSUBLGRQ (w83877f_regs[0x17] & 1) +#define DSUALGRQ ((w83877f_regs[0x17] >> 1) & 1) +#define DSPRLGRQ ((w83877f_regs[0x17] >> 2) & 1) +#define DSFDLGRQ ((w83877f_regs[0x17] >> 3) & 1) +#define PRIRQOD ((w83877f_regs[0x17] >> 4) & 1) + +#define GMAS (w83877f_regs[0x1E] & 3) +#define GMAD (w83877f_regs[0x1E] & 0xFC) + +#define FDCAD ((w83877f_regs[0x20] & 0xFC) << 2) + +/* Main IDE base address. */ +#define IDE0AD ((w83877f_regs[0x21] & 0xFC) << 2) +/* IDE Alternate status base address. */ +#define IDE1AD ((w83877f_regs[0x22] & 0xFC) << 2) + +#define PRTAD (((uint16_t) w83877f_regs[0x23]) << 2) + +#define URAAD (((uint16_t) w83877f_regs[0x24] & 0xFE) << 2) +#define URBAD (((uint16_t) w83877f_regs[0x25] & 0xFE) << 2) + +#define PRTDQS (w83877f[regs[0x26] & 0xF) +#define FDCDQS (w83877f[regs[0x26] >> 4) + +#define PRTIQS (w83877f[regs[0x27] & 0xF) +#define ECPIRQx (w83877f[regs[0x27] >> 5) + +#define URBIQS (w83877f[regs[0x28] & 0xF) +#define URAIQS (w83877f[regs[0x28] >> 4) + +#define IQNIQS (w83877f[regs[0x29] & 0xF) +#define FDCIQS (w83877f[regs[0x29] >> 4) + +#define W83757 (!PRTMODS2 && !PRTMODS1 && !PRTMODS0) +#define EXTFDC (!PRTMODS2 && !PRTMODS1 && PRTMODS0) +#define EXTADP (!PRTMODS2 && PRTMODS1 && !PRTMODS0) +#define EXT2FDD (!PRTMODS2 && PRTMODS1 && PRTMODS0) +#define JOYSTICK (PRTMODS2 && !PRTMODS1 && !PRTMODS0) +#define EPP_SPP (PRTMODS2 && !PRTMODS1 && PRTMODS0) +#define ECP (PRTMODS2 && PRTMODS1 && !PRTMODS0) +#define ECP_EPP (PRTMODS2 && PRTMODS1 && PRTMODS0) + +static uint16_t fdc_valid_ports[2] = {0x3F0, 0x370}; +static uint16_t ide_valid_ports[2] = {0x1F0, 0x170}; +static uint16_t ide_as_valid_ports[2] = {0x3F6, 0x376}; +static uint16_t lpt1_valid_ports[3] = {0x3BC, 0x378, 0x278}; +static uint16_t com1_valid_ports[9] = {0x3F8, 0x2F8, 0x3E8, 0x2E8}; +static uint16_t com2_valid_ports[9] = {0x3F8, 0x2F8, 0x3E8, 0x2E8}; + +static void w83877f_remap() +{ + io_removehandler(0x250, 0x0002, w83877f_read, NULL, NULL, w83877f_write, NULL, NULL, NULL); + io_removehandler(0x3f0, 0x0002, w83877f_read, NULL, NULL, w83877f_write, NULL, NULL, NULL); + io_sethandler(HEFRAS ? 0x3f0 : 0x250, 0x0002, w83877f_read, NULL, NULL, w83877f_write, NULL, NULL, NULL); + winbond_port = (HEFRAS ? 0x3f0 : 0x250); + winbond_key_times = HEFRAS + 1; + winbond_key = (HEFRAS ? 0x86 : 0x88) | HEFERE; + // pclog("W83877F mapped to %04X, with key %02X required %i times\n", winbond_port, winbond_key, winbond_key_times); +} + +static uint8_t is_in_array(uint16_t *port_array, uint8_t max, uint16_t port) +{ + uint8_t i = 0; + + for (i = 0; i < max; i++) + { + if (port_array[i] == port) return 1; + } + return 0; +} + +static uint16_t make_port(uint8_t reg) +{ + uint16_t p = 0; + + switch(reg) + { + case 0x20: + p = ((uint16_t) (w83877f_regs[reg] & 0xfc)) << 2; + p &= 0xFF0; + if ((p < 0x100) || (p > 0x3F0)) p = 0x3F0; + if (!(is_in_array(fdc_valid_ports, 2, p))) p = 0x3F0; + w83877f_regs[reg] = ((p >> 2) & 0xfc) | (w83877f_regs[reg] & 3); + break; + case 0x21: + p = ((uint16_t) (w83877f_regs[reg] & 0xfc)) << 2; + p &= 0xFF0; + if ((p < 0x100) || (p > 0x3F0)) p = 0x1F0; + if (!(is_in_array(ide_valid_ports, 2, p))) p = 0x1F0; + w83877f_regs[reg] = ((p >> 2) & 0xfc) | (w83877f_regs[reg] & 3); + break; + case 0x22: + p = ((uint16_t) (w83877f_regs[reg] & 0xfc)) << 2; + p &= 0xFF0; + if ((p < 0x106) || (p > 0x3F6)) p = 0x3F6; + if (!(is_in_array(ide_as_valid_ports, 2, p))) p = 0x3F6; + w83877f_regs[reg] = ((p >> 2) & 0xfc) | (w83877f_regs[reg] & 3); + break; + case 0x23: + p = ((uint16_t) (w83877f_regs[reg] & 0xff)) << 2; + p &= 0xFFC; + if ((p < 0x100) || (p > 0x3F8)) p = 0x378; + if (!(is_in_array(lpt1_valid_ports, 3, p))) p = 0x378; + w83877f_regs[reg] = (p >> 2); + break; + case 0x24: + p = ((uint16_t) (w83877f_regs[reg] & 0xfe)) << 2; + p &= 0xFF8; + if ((p < 0x100) || (p > 0x3F8)) p = 0x3F8; + if (!(is_in_array(com1_valid_ports, 9, p))) p = 0x3F8; + w83877f_regs[reg] = ((p >> 2) & 0xfe) | (w83877f_regs[reg] & 1); + break; + case 0x25: + p = ((uint16_t) (w83877f_regs[reg] & 0xfe)) << 2; + p &= 0xFF8; + if ((p < 0x100) || (p > 0x3F8)) p = 0x2F8; + if (!(is_in_array(com2_valid_ports, 9, p))) p = 0x2F8; + w83877f_regs[reg] = ((p >> 2) & 0xfe) | (w83877f_regs[reg] & 1); + break; + } + + // pclog("Made port %04X (reg %02X)\n", p, reg); + return p; +} + +void w83877f_write(uint16_t port, uint8_t val, void *priv) +{ + uint8_t index = (port & 1) ? 0 : 1; + uint8_t valxor = 0; + uint8_t max = 0x2A; + int temp; + + if (index) + { + // pclog("w83877f_write : port=%04x = %02X locked=%i\n", port, val, w83877f_locked); + + if ((val == winbond_key) && !w83877f_locked) + { + if (winbond_key_times == 2) + { + if (tries) + { + // pclog("W83877F Locked (2 tries)\n"); + w83877f_locked = 1; + // fdc_3f1_enable(0); + tries = 0; + } + else + { + tries++; + } + } + else + { + // pclog("W83877F Locked (1 try)\n"); + w83877f_locked = 1; + // fdc_3f1_enable(0); + tries = 0; + } + } + else + { + // pclog("w83877f_write : port=%04x reg %02X = %02X locked=%i\n", port, w83877f_curreg, val, w83877f_locked); + + if (w83877f_locked) + { + if (val < max) w83877f_curreg = val; + if (val == 0xaa) + { + w83877f_locked = 0; + // fdc_3f1_enable(1); + } + } + else + { + if (tries) + tries = 0; + } + } + } + else + { + // pclog("w83877f_write : port=%04x reg %02X = %02X locked=%i\n", port, w83877f_curreg, val, w83877f_locked); + + if (w83877f_locked) + { + if (w83877f_rw_locked) return; + if ((w83877f_curreg >= 0x26) && (w83877f_curreg <= 0x27)) return; + if (w83877f_curreg == 0x29) return; + if (w83877f_curreg == 6) val &= 0xF3; + valxor = val ^ w83877f_regs[w83877f_curreg]; + w83877f_regs[w83877f_curreg] = val; + goto process_value; + } + } + return; + +process_value: + switch(w83877f_curreg) + { + case 4: + if (valxor & 0x10) + { + serial2_remove(); + if (!(w83877f_regs[2] & 0x10)) serial2_set(make_port(0x25), w83877f_regs[0x28] & 0xF); + } + if (valxor & 0x20) + { + serial1_remove(); + if (!(w83877f_regs[4] & 0x20)) + { + serial1_set(make_port(0x24), (w83877f_regs[0x28] & 0xF0) >> 8); + // mouse_serial_init(); + } + } + if (valxor & 0x80) + { + lpt1_remove(); + if (!(w83877f_regs[4] & 0x80)) lpt1_init(make_port(0x23)); + } + break; + case 6: + if (valxor & 0x08) + { + fdc_remove(); + if (!(w83877f_regs[6] & 0x08)) fdc_add(); + } + break; + case 7: + // pclog("W83877F Write [Reg. %02X]: %02X\n", w83877f_curreg, val); + if (valxor & 3) fdc_update_rwc(0, FDDA_TYPE ? 1 : 0); + if (valxor & 0xC) fdc_update_rwc(1, FDDB_TYPE ? 1 : 0); + break; + case 8: + // pclog("W83877F Write [Reg. %02X]: %02X\n", w83877f_curreg, val); + if (valxor & 3) fdc_update_boot_drive(FD_BOOT); + if (valxor & 0x10) swwp = SWWP ? 1 : 0; + if (valxor & 0x20) disable_write = DISFDDWR ? 1 : 0; + break; + case 9: + // pclog("W83877F Write [Reg. %02X]: %02X\n", w83877f_curreg, val); + if (valxor & 0x20) + { + fdc_update_enh_mode(EN3MODE ? 1 : 0); + } + if (valxor & 0x40) + { + w83877f_rw_locked = (val & 0x40) ? 1 : 0; + } + break; + case 0xB: + // pclog("W83877F Write [Reg. %02X]: %02X\n", w83877f_curreg, val); + if (valxor & 1) fdc_update_drv2en(DRV2EN_NEG ? 0 : 1); + if (valxor & 2) fdc_update_densel_polarity(INVERTZ ? 1 : 0); + break; + case 0xC: + if (valxor & 0x20) w83877f_remap(); + break; + case 0x16: + if (valxor & 1) w83877f_remap(); + break; + case 0x23: + if (valxor) + { + lpt1_remove(); + if (!(w83877f_regs[4] & 0x80)) lpt1_init(make_port(0x23)); + } + break; + case 0x24: + if (valxor & 0xfe) + { + if (!(w83877f_regs[4] & 0x20)) + { + serial1_set(make_port(0x24), (w83877f_regs[0x28] & 0xF0) >> 8); + // mouse_serial_init(); + } + } + break; + case 0x25: + if (valxor & 0xfe) + { + if (!(w83877f_regs[2] & 0x10)) serial2_set(make_port(0x25), w83877f_regs[0x28] & 0xF); + } + break; + case 0x28: + if (valxor & 0xf) + { + if ((w83877f_regs[0x28] & 0xf) == 0) w83877f_regs[0x28] |= 0x3; + if (!(w83877f_regs[2] & 0x10)) serial2_set(make_port(0x25), w83877f_regs[0x28] & 0xF); + } + if (valxor & 0xf0) + { + if ((w83877f_regs[0x28] & 0xf0) == 0) w83877f_regs[0x28] |= 0x40; + if (!(w83877f_regs[4] & 0x20)) + { + serial1_set(make_port(0x24), (w83877f_regs[0x28] & 0xF0) >> 8); + // mouse_serial_init(); + } + } + break; + } +} + +uint8_t w83877f_read(uint16_t port, void *priv) +{ + uint8_t index = (port & 1) ? 0 : 1; + + if (!w83877f_locked) + { + // pclog("w83877f_read : port=%04x = FF locked=%i\n", port, w83877f_locked); + return 0xff; + } + + if (index) + { + // pclog("w83877f_read : port=%04x = %02X locked=%i\n", port, w83877f_curreg, w83877f_locked); + return w83877f_curreg; + } + else + { + if ((w83877f_curreg < 0x18) && w83877f_rw_locked) return 0xff; + if (w83877f_curreg == 7) + { + // pclog("w83877f_read : port=%04x reg %02X = %02X locked=%i\n", port, w83877f_curreg, (fdc_get_rwc(0) | (fdc_get_rwc(1) << 2)), w83877f_locked); + return (fdc_get_rwc(0) | (fdc_get_rwc(1) << 2)); + } + // pclog("w83877f_read : port=%04x reg %02X = %02X locked=%i\n", port, w83877f_curreg, w83877f_regs[w83877f_curreg], w83877f_locked); + return w83877f_regs[w83877f_curreg]; + } +} + +void w83877f_init() +{ + fdc_remove(); + fdc_add_for_superio(); + lpt1_remove(); + lpt1_init(0x378); + lpt2_remove(); + w83877f_regs[3] = 0x30; + w83877f_regs[7] = 0xF5; + w83877f_regs[9] = 0x0A; + w83877f_regs[0xA] = 0x1F; + w83877f_regs[0xC] = 0x28; + w83877f_regs[0xD] = 0xA3; + w83877f_regs[0x16] = 5; + w83877f_regs[0x1E] = 0x81; + w83877f_regs[0x20] = (0x3f0 >> 2) & 0xfc; + w83877f_regs[0x21] = (0x1f0 >> 2) & 0xfc; + w83877f_regs[0x22] = ((0x3f6 >> 2) & 0xfc) | 1; + w83877f_regs[0x23] = (0x378 >> 2); + w83877f_regs[0x24] = (0x3f8 >> 2) & 0xfe; + w83877f_regs[0x25] = (0x2f8 >> 2) & 0xfe; + w83877f_regs[0x26] = (2 << 4) | 4; + w83877f_regs[0x27] = (6 << 4) | 7; + w83877f_regs[0x28] = (4 << 4) | 3; + w83877f_regs[0x29] = 0x62; + + fdc_update_densel_polarity(1); + fdc_update_densel_force(0); + fdc_update_rwc(0, 1); + fdc_update_rwc(1, 1); + fdc_update_drvrate(0, 0); + fdc_update_drvrate(1, 0); + fdc_update_enh_mode(0); + swwp = 0; + disable_write = 0; + fdc_update_drv2en(1); + fdd_swap = 0; + serial1_set(0x3f8, 4); + serial2_set(0x2f8, 3); + w83877f_remap(); + w83877f_locked = 0; + w83877f_rw_locked = 0; +} diff --git a/src/w83877f.h b/src/w83877f.h new file mode 100644 index 000000000..37595ab66 --- /dev/null +++ b/src/w83877f.h @@ -0,0 +1 @@ +extern void w83877f_init(); diff --git a/src/wd76c10.c b/src/wd76c10.c new file mode 100644 index 000000000..4f33b07d9 --- /dev/null +++ b/src/wd76c10.c @@ -0,0 +1,99 @@ +#include "ibm.h" +#include "fdc.h" +#include "io.h" +#include "mem.h" +#include "serial.h" +#include "wd76c10.h" + +static uint16_t wd76c10_0092; +static uint16_t wd76c10_2072; +static uint16_t wd76c10_2872; +static uint16_t wd76c10_5872; + +uint16_t wd76c10_read(uint16_t port, void *priv) +{ + switch (port) + { + case 0x0092: + return wd76c10_0092; + + case 0x2072: + return wd76c10_2072; + + case 0x2872: + return wd76c10_2872; + + case 0x5872: + return wd76c10_5872; + } + return 0; +} + +void wd76c10_write(uint16_t port, uint16_t val, void *priv) +{ + pclog("WD76C10 write %04X %04X\n", port, val); + switch (port) + { + case 0x0092: + wd76c10_0092 = val; + + mem_a20_alt = val & 2; + mem_a20_recalc(); + break; + + case 0x2072: + wd76c10_2072 = val; + + switch ((val >> 5) & 7) + { + case 1: serial1_set(0x3f8, 4); break; + case 2: serial1_set(0x2f8, 4); break; + case 3: serial1_set(0x3e8, 4); break; + case 4: serial1_set(0x2e8, 4); break; + } + switch ((val >> 1) & 7) + { + case 1: serial2_set(0x3f8, 3); break; + case 2: serial2_set(0x2f8, 3); break; + case 3: serial2_set(0x3e8, 3); break; + case 4: serial2_set(0x2e8, 3); break; + } + break; + + case 0x2872: + wd76c10_2872 = val; + + fdc_remove(); + if (!(val & 1)) + fdc_add(); + break; + + case 0x5872: + wd76c10_5872 = val; + break; + } +} + +uint8_t wd76c10_readb(uint16_t port, void *priv) +{ + if (port & 1) + return wd76c10_read(port & ~1, priv) >> 8; + return wd76c10_read(port, priv) & 0xff; +} + +void wd76c10_writeb(uint16_t port, uint8_t val, void *priv) +{ + uint16_t temp = wd76c10_read(port, priv); + if (port & 1) + wd76c10_write(port & ~1, (temp & 0x00ff) | (val << 8), priv); + else + wd76c10_write(port , (temp & 0xff00) | val, priv); +} + +void wd76c10_init() +{ + io_sethandler(0x0092, 0x0002, wd76c10_readb, wd76c10_read, NULL, wd76c10_writeb, wd76c10_write, NULL, NULL); + io_sethandler(0x2072, 0x0002, wd76c10_readb, wd76c10_read, NULL, wd76c10_writeb, wd76c10_write, NULL, NULL); + io_sethandler(0x2872, 0x0002, wd76c10_readb, wd76c10_read, NULL, wd76c10_writeb, wd76c10_write, NULL, NULL); + io_sethandler(0x5872, 0x0002, wd76c10_readb, wd76c10_read, NULL, wd76c10_writeb, wd76c10_write, NULL, NULL); +} diff --git a/src/wd76c10.h b/src/wd76c10.h new file mode 100644 index 000000000..44528f0f5 --- /dev/null +++ b/src/wd76c10.h @@ -0,0 +1 @@ +void wd76c10_init(); diff --git a/src/win-config.c b/src/win-config.c new file mode 100644 index 000000000..4291802b2 --- /dev/null +++ b/src/win-config.c @@ -0,0 +1,694 @@ +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP + +#include + +#include "nethandler.h" +#include "ibm.h" +#include "ide.h" +#include "cpu.h" +#include "device.h" +#include "fdd.h" +#include "gameport.h" +#include "model.h" +#include "nvr.h" +#include "resources.h" +#include "sound.h" +#include "video.h" +#include "vid_voodoo.h" +#include "win.h" + +extern int is486; +static int romstolist[ROM_MAX], listtomodel[ROM_MAX], romstomodel[ROM_MAX], modeltolist[ROM_MAX]; +static int settings_sound_to_list[20], settings_list_to_sound[20]; +static int settings_network_to_list[20], settings_list_to_network[20]; + +static BOOL CALLBACK config_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + char temp_str[256]; + HWND h; + int c, d; + int rom, gfx, mem, fpu; + int temp_cpu, temp_cpu_m, temp_model; + int temp_GAMEBLASTER, temp_GUS, temp_SSI2001, temp_voodoo, temp_sound_card_current; + int temp_dynarec; + int cpu_flags; + int temp_fda_type, temp_fdb_type; + int temp_network_card_current; + int temp_network_interface_current; + int temp_always_serial; + int temp_joystick_type; + + UDACCEL accel; +// pclog("Dialog msg %i %08X\n",message,message); + switch (message) + { + case WM_INITDIALOG: + pause = 1; + h = GetDlgItem(hdlg, IDC_COMBO1); + for (c = 0; c < ROM_MAX; c++) + romstolist[c] = 0; + c = d = 0; + while (models[c].id != -1) + { + pclog("INITDIALOG : %i %i %i\n",c,models[c].id,romspresent[models[c].id]); + if (romspresent[models[c].id]) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)models[c].name); + modeltolist[c] = d; + listtomodel[d] = c; + romstolist[models[c].id] = d; + romstomodel[models[c].id] = c; + d++; + } + c++; + } + SendMessage(h, CB_SETCURSEL, modeltolist[model], 0); + + h = GetDlgItem(hdlg, IDC_COMBOVID); + c = d = 0; + while (1) + { + char *s = video_card_getname(c); + + if (!s[0]) + break; + + if (video_card_available(c) && gfx_present[video_new_to_old(c)]) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); + if (video_new_to_old(c) == gfxcard) + SendMessage(h, CB_SETCURSEL, d, 0); + + d++; + } + + c++; + } + if (models[model].fixed_gfxcard) + EnableWindow(h, FALSE); + + h = GetDlgItem(hdlg, IDC_COMBOCPUM); + c = 0; + while (models[romstomodel[romset]].cpu[c].cpus != NULL && c < 3) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)models[romstomodel[romset]].cpu[c].name); + c++; + } + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, cpu_manufacturer, 0); + if (c == 1) EnableWindow(h, FALSE); + else EnableWindow(h, TRUE); + + h = GetDlgItem(hdlg, IDC_COMBO3); + c = 0; + while (models[romstomodel[romset]].cpu[cpu_manufacturer].cpus[c].cpu_type != -1) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)models[romstomodel[romset]].cpu[cpu_manufacturer].cpus[c].name); + c++; + } + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, cpu, 0); + + h = GetDlgItem(hdlg, IDC_COMBOSND); + c = d = 0; + while (1) + { + char *s = sound_card_getname(c); + + if (!s[0]) + break; + + settings_sound_to_list[c] = d; + + if (sound_card_available(c)) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); + settings_list_to_sound[d] = c; + d++; + } + + c++; + } + SendMessage(h, CB_SETCURSEL, settings_sound_to_list[sound_card_current], 0); + + /*NIC config*/ + h = GetDlgItem(hdlg, IDC_COMBONET); + c = d = 0; + while (1) + { + char *s = network_card_getname(c); + + if (!s[0]) + break; + + settings_network_to_list[c] = d; + + if (network_card_available(c)) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); + settings_list_to_network[d] = c; + d++; + } + + c++; + } + SendMessage(h, CB_SETCURSEL, settings_network_to_list[network_card_current], 0); + + h=GetDlgItem(hdlg, IDC_CHECK3); + SendMessage(h, BM_SETCHECK, GAMEBLASTER, 0); + + h=GetDlgItem(hdlg, IDC_CHECKGUS); + SendMessage(h, BM_SETCHECK, GUS, 0); + + h=GetDlgItem(hdlg, IDC_CHECKSSI); + SendMessage(h, BM_SETCHECK, SSI2001, 0); + + h=GetDlgItem(hdlg, IDC_CHECK2); + SendMessage(h, BM_SETCHECK, slowega, 0); + + h=GetDlgItem(hdlg, IDC_CHECK4); + SendMessage(h, BM_SETCHECK, cga_comp, 0); + + h=GetDlgItem(hdlg, IDC_CHECKCBURST); + SendMessage(h, BM_SETCHECK, cga_color_burst, 0); + + h=GetDlgItem(hdlg, IDC_CHECKBROWN); + SendMessage(h, BM_SETCHECK, cga_brown, 0); + + h=GetDlgItem(hdlg, IDC_CHECKFORCE43); + SendMessage(h, BM_SETCHECK, force_43, 0); + + h=GetDlgItem(hdlg, IDC_CHECKOVERSCAN); + SendMessage(h, BM_SETCHECK, enable_overscan, 0); + + h=GetDlgItem(hdlg, IDC_CHECKFLASH); + SendMessage(h, BM_SETCHECK, enable_flash, 0); + + h=GetDlgItem(hdlg, IDC_CHECKSYNC); + SendMessage(h, BM_SETCHECK, enable_sync, 0); + + h=GetDlgItem(hdlg, IDC_CHECKSERIAL); + SendMessage(h, BM_SETCHECK, mouse_always_serial, 0); + + h=GetDlgItem(hdlg, IDC_CHECKVOODOO); + SendMessage(h, BM_SETCHECK, voodoo_enabled, 0); + + cpu_flags = models[romstomodel[romset]].cpu[cpu_manufacturer].cpus[cpu].cpu_flags; + h=GetDlgItem(hdlg, IDC_CHECKDYNAREC); + if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC)) + EnableWindow(h, FALSE); + else + EnableWindow(h, TRUE); + SendMessage(h, BM_SETCHECK, ((cpu_flags & CPU_SUPPORTS_DYNAREC) && cpu_use_dynarec) || (cpu_flags & CPU_REQUIRES_DYNAREC), 0); + + h = GetDlgItem(hdlg, IDC_COMBOCHC); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"A little"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"A bit"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Some"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"A lot"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Infinite"); + SendMessage(h, CB_SETCURSEL, cache, 0); + + h = GetDlgItem(hdlg, IDC_COMBOSPD); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"8-bit"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Slow 16-bit"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Fast 16-bit"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Slow VLB/PCI"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Mid VLB/PCI"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"Fast VLB/PCI"); + SendMessage(h, CB_SETCURSEL, video_speed, 0); + + h = GetDlgItem(hdlg, IDC_MEMSPIN); + SendMessage(h, UDM_SETBUDDY, (WPARAM)GetDlgItem(hdlg, IDC_MEMTEXT), 0); + SendMessage(h, UDM_SETRANGE, 0, (models[romstomodel[romset]].min_ram << 16) | models[romstomodel[romset]].max_ram); + if (!models[model].is_at) + SendMessage(h, UDM_SETPOS, 0, mem_size); + else + SendMessage(h, UDM_SETPOS, 0, mem_size / 1024); + accel.nSec = 0; + accel.nInc = models[model].ram_granularity; + SendMessage(h, UDM_SETACCEL, 1, (LPARAM)&accel); + + h = GetDlgItem(hdlg, IDC_CONFIGUREVID); + if (video_card_has_config(video_old_to_new(gfxcard))) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + h = GetDlgItem(hdlg, IDC_CONFIGURESND); + if (sound_card_has_config(sound_card_current)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + h = GetDlgItem(hdlg, IDC_CONFIGURENET); + if (network_card_has_config(network_card_current)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + + h = GetDlgItem(hdlg, IDC_COMBODRA); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"None"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5.25\" 360k"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5.25\" 1.2M"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5.25\" 1.2M Dual RPM"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 720k"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 1.44M"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 1.44M 3-Mode"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 2.88M"); + SendMessage(h, CB_SETCURSEL, fdd_get_type(0), 0); + h = GetDlgItem(hdlg, IDC_COMBODRB); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"None"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5.25\" 360k"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5.25\" 1.2M"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"5.25\" 1.2M Dual RPM"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 720k"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 1.44M"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 1.44M 3-Mode"); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"3.5\" 2.88M"); + SendMessage(h, CB_SETCURSEL, fdd_get_type(1), 0); + + h = GetDlgItem(hdlg, IDC_TEXT_MB); + if (models[model].is_at) + SendMessage(h, WM_SETTEXT, 0, (LPARAM)(LPCSTR)"MB"); + else + SendMessage(h, WM_SETTEXT, 0, (LPARAM)(LPCSTR)"KB"); + + h = GetDlgItem(hdlg, IDC_COMBOJOY); + c = 0; + while (joystick_get_name(c)) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)joystick_get_name(c)); + c++; + } + EnableWindow(h, TRUE); + SendMessage(h, CB_SETCURSEL, joystick_type, 0); + + h = GetDlgItem(hdlg, IDC_JOY1); + EnableWindow(h, (joystick_get_max_joysticks(joystick_type) >= 1) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY2); + EnableWindow(h, (joystick_get_max_joysticks(joystick_type) >= 2) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY3); + EnableWindow(h, (joystick_get_max_joysticks(joystick_type) >= 3) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY4); + EnableWindow(h, (joystick_get_max_joysticks(joystick_type) >= 4) ? TRUE : FALSE); + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + h = GetDlgItem(hdlg, IDC_COMBO1); + temp_model = listtomodel[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_MEMTEXT); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)temp_str); + sscanf(temp_str, "%i", &mem); + mem &= ~(models[temp_model].ram_granularity - 1); + if (mem < models[temp_model].min_ram) + mem = models[temp_model].min_ram; + else if (mem > models[temp_model].max_ram) + mem = models[temp_model].max_ram; + if (models[temp_model].is_at) + mem *= 1024; + + h = GetDlgItem(hdlg, IDC_COMBOVID); + SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM)temp_str); + gfx = video_new_to_old(video_card_getid(temp_str)); + + h = GetDlgItem(hdlg, IDC_COMBOCPUM); + temp_cpu_m = SendMessage(h, CB_GETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_COMBO3); + temp_cpu = SendMessage(h, CB_GETCURSEL, 0, 0); + fpu = (models[temp_model].cpu[temp_cpu_m].cpus[temp_cpu].cpu_type >= CPU_i486DX) ? 1 : 0; + + h = GetDlgItem(hdlg, IDC_CHECK3); + temp_GAMEBLASTER = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECKGUS); + temp_GUS = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECKSSI); + temp_SSI2001 = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECKFORCE43); + force_43 = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECKOVERSCAN); + enable_overscan = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECKCBURST); + cga_color_burst=SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECKBROWN); + cga_brown=SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECKFLASH); + enable_flash=SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECKSYNC); + enable_sync = SendMessage(h, BM_GETCHECK, 0, 0); + update_sync(); + + h = GetDlgItem(hdlg, IDC_CHECKSERIAL); + temp_always_serial = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECKVOODOO); + temp_voodoo = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_COMBOSND); + temp_sound_card_current = settings_list_to_sound[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_CHECKDYNAREC); + temp_dynarec = SendMessage(h, BM_GETCHECK, 0, 0); + + h = GetDlgItem(hdlg, IDC_COMBONET); + temp_network_card_current = settings_list_to_network[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_COMBODRA); + temp_fda_type = SendMessage(h, CB_GETCURSEL, 0, 0); + h = GetDlgItem(hdlg, IDC_COMBODRB); + temp_fdb_type = SendMessage(h, CB_GETCURSEL, 0, 0); + + h = GetDlgItem(hdlg, IDC_COMBOJOY); + temp_joystick_type = SendMessage(h, CB_GETCURSEL, 0, 0); + + if (temp_model != model || gfx != gfxcard || mem != mem_size || temp_cpu != cpu || temp_cpu_m != cpu_manufacturer || + fpu != hasfpu || temp_GAMEBLASTER != GAMEBLASTER || temp_GUS != GUS || + temp_SSI2001 != SSI2001 || temp_sound_card_current != sound_card_current || + temp_voodoo != voodoo_enabled || temp_dynarec != cpu_use_dynarec || temp_always_serial != mouse_always_serial || + temp_fda_type != fdd_get_type(0) || temp_fdb_type != fdd_get_type(1) || temp_network_card_current != network_card_current) + { + if (MessageBox(NULL,"This will reset PCem!\nOkay to continue?","PCem",MB_OKCANCEL)==IDOK) + { + savenvr(); + model = temp_model; + romset = model_getromset(); + gfxcard = gfx; + mem_size = mem; + cpu_manufacturer = temp_cpu_m; + cpu = temp_cpu; + GAMEBLASTER = temp_GAMEBLASTER; + GUS = temp_GUS; + SSI2001 = temp_SSI2001; + sound_card_current = temp_sound_card_current; + voodoo_enabled = temp_voodoo; + cpu_use_dynarec = temp_dynarec; + + fdd_set_type(0, temp_fda_type); + fdd_set_type(1, temp_fdb_type); + + network_card_current = temp_network_card_current; + mouse_always_serial = temp_always_serial; + + mem_resize(); + loadbios(); + resetpchard(); + } + else + { + EndDialog(hdlg, 0); + pause = 0; + return TRUE; + } + } + + h = GetDlgItem(hdlg, IDC_COMBOSPD); + video_speed = SendMessage(h, CB_GETCURSEL, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECK4); + cga_comp=SendMessage(h, BM_GETCHECK, 0, 0); + + cpu_manufacturer = temp_cpu_m; + cpu = temp_cpu; + cpu_set(); + + h = GetDlgItem(hdlg, IDC_COMBOCHC); + cache=SendMessage(h, CB_GETCURSEL, 0, 0); + mem_updatecache(); + + saveconfig(); + + speedchanged(); + + joystick_type = temp_joystick_type; + gameport_update_joystick_type(); + + case IDCANCEL: + EndDialog(hdlg, 0); + pause=0; + return TRUE; + case IDC_COMBO1: + if (HIWORD(wParam) == CBN_SELCHANGE) + { + h = GetDlgItem(hdlg,IDC_COMBO1); + temp_model = listtomodel[SendMessage(h,CB_GETCURSEL,0,0)]; + + /*Enable/disable gfxcard list*/ + h = GetDlgItem(hdlg, IDC_COMBOVID); + if (!models[temp_model].fixed_gfxcard) + { + char *s = video_card_getname(video_old_to_new(gfxcard)); + + EnableWindow(h, TRUE); + + c = 0; + while (1) + { + SendMessage(h, CB_GETLBTEXT, c, (LPARAM)temp_str); + if (!strcmp(temp_str, s)) + break; + c++; + } + SendMessage(h, CB_SETCURSEL, c, 0); + } + else + EnableWindow(h, FALSE); + + /*Rebuild manufacturer list*/ + h = GetDlgItem(hdlg, IDC_COMBOCPUM); + temp_cpu_m = SendMessage(h, CB_GETCURSEL, 0, 0); + SendMessage(h, CB_RESETCONTENT, 0, 0); + c = 0; + while (models[temp_model].cpu[c].cpus != NULL && c < 3) + { + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)models[temp_model].cpu[c].name); + c++; + } + if (temp_cpu_m >= c) temp_cpu_m = c - 1; + SendMessage(h, CB_SETCURSEL, temp_cpu_m, 0); + if (c == 1) EnableWindow(h, FALSE); + else EnableWindow(h, TRUE); + + /*Rebuild CPU list*/ + h = GetDlgItem(hdlg, IDC_COMBO3); + temp_cpu = SendMessage(h, CB_GETCURSEL, 0, 0); + SendMessage(h, CB_RESETCONTENT, 0, 0); + c = 0; + while (models[temp_model].cpu[temp_cpu_m].cpus[c].cpu_type != -1) + { + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)models[temp_model].cpu[temp_cpu_m].cpus[c].name); + c++; + } + if (temp_cpu >= c) temp_cpu = c - 1; + SendMessage(h, CB_SETCURSEL, temp_cpu, 0); + + h = GetDlgItem(hdlg, IDC_CHECKDYNAREC); + temp_dynarec = SendMessage(h, BM_GETCHECK, 0, 0); + + cpu_flags = models[temp_model].cpu[temp_cpu_m].cpus[temp_cpu].cpu_flags; + h=GetDlgItem(hdlg, IDC_CHECKDYNAREC); + if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC)) + EnableWindow(h, FALSE); + else + EnableWindow(h, TRUE); + SendMessage(h, BM_SETCHECK, ((cpu_flags & CPU_SUPPORTS_DYNAREC) && temp_dynarec) || (cpu_flags & CPU_REQUIRES_DYNAREC), 0); + + h = GetDlgItem(hdlg, IDC_TEXT_MB); + if (models[temp_model].is_at) + SendMessage(h, WM_SETTEXT, 0, (LPARAM)(LPCSTR)"MB"); + else + SendMessage(h, WM_SETTEXT, 0, (LPARAM)(LPCSTR)"KB"); + + h = GetDlgItem(hdlg, IDC_MEMTEXT); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)temp_str); + sscanf(temp_str, "%i", &mem); + + h = GetDlgItem(hdlg, IDC_MEMSPIN); + SendMessage(h, UDM_SETRANGE, 0, (models[temp_model].min_ram << 16) | models[temp_model].max_ram); + mem &= ~(models[temp_model].ram_granularity - 1); + if (mem < models[temp_model].min_ram) + mem = models[temp_model].min_ram; + else if (mem > models[temp_model].max_ram) + mem = models[temp_model].max_ram; + SendMessage(h, UDM_SETPOS, 0, mem); + accel.nSec = 0; + accel.nInc = models[temp_model].ram_granularity; + SendMessage(h, UDM_SETACCEL, 1, (LPARAM)&accel); + } + break; + case IDC_COMBOCPUM: + if (HIWORD(wParam) == CBN_SELCHANGE) + { + h = GetDlgItem(hdlg, IDC_COMBO1); + temp_model = listtomodel[SendMessage(h, CB_GETCURSEL, 0, 0)]; + h = GetDlgItem(hdlg, IDC_COMBOCPUM); + temp_cpu_m = SendMessage(h, CB_GETCURSEL, 0, 0); + + /*Rebuild CPU list*/ + h=GetDlgItem(hdlg, IDC_COMBO3); + temp_cpu = SendMessage(h, CB_GETCURSEL, 0, 0); + SendMessage(h, CB_RESETCONTENT, 0, 0); + c = 0; + while (models[temp_model].cpu[temp_cpu_m].cpus[c].cpu_type != -1) + { + SendMessage(h,CB_ADDSTRING,0,(LPARAM)(LPCSTR)models[temp_model].cpu[temp_cpu_m].cpus[c].name); + c++; + } + if (temp_cpu >= c) temp_cpu = c - 1; + SendMessage(h, CB_SETCURSEL, temp_cpu, 0); + + h = GetDlgItem(hdlg, IDC_CHECKDYNAREC); + temp_dynarec = SendMessage(h, BM_GETCHECK, 0, 0); + + cpu_flags = models[temp_model].cpu[temp_cpu_m].cpus[temp_cpu].cpu_flags; + h=GetDlgItem(hdlg, IDC_CHECKDYNAREC); + if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC)) + EnableWindow(h, FALSE); + else + EnableWindow(h, TRUE); + SendMessage(h, BM_SETCHECK, ((cpu_flags & CPU_SUPPORTS_DYNAREC) && temp_dynarec) || (cpu_flags & CPU_REQUIRES_DYNAREC), 0); + } + break; + case IDC_COMBO3: + if (HIWORD(wParam) == CBN_SELCHANGE) + { + h = GetDlgItem(hdlg, IDC_COMBO1); + temp_model = listtomodel[SendMessage(h, CB_GETCURSEL, 0, 0)]; + h = GetDlgItem(hdlg, IDC_COMBOCPUM); + temp_cpu_m = SendMessage(h, CB_GETCURSEL, 0, 0); + h=GetDlgItem(hdlg, IDC_COMBO3); + temp_cpu = SendMessage(h, CB_GETCURSEL, 0, 0); + + h = GetDlgItem(hdlg, IDC_CHECKDYNAREC); + temp_dynarec = SendMessage(h, BM_GETCHECK, 0, 0); + + cpu_flags = models[temp_model].cpu[temp_cpu_m].cpus[temp_cpu].cpu_flags; + h=GetDlgItem(hdlg, IDC_CHECKDYNAREC); + if (!(cpu_flags & CPU_SUPPORTS_DYNAREC) || (cpu_flags & CPU_REQUIRES_DYNAREC)) + EnableWindow(h, FALSE); + else + EnableWindow(h, TRUE); + SendMessage(h, BM_SETCHECK, ((cpu_flags & CPU_SUPPORTS_DYNAREC) && temp_dynarec) || (cpu_flags & CPU_REQUIRES_DYNAREC), 0); + } + break; + + case IDC_CONFIGUREVID: + h = GetDlgItem(hdlg, IDC_COMBOVID); + SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM)temp_str); + + deviceconfig_open(hdlg, (void *)video_card_getdevice(video_card_getid(temp_str))); + break; + + case IDC_COMBOVID: + h = GetDlgItem(hdlg, IDC_COMBOVID); + SendMessage(h, CB_GETLBTEXT, SendMessage(h, CB_GETCURSEL, 0, 0), (LPARAM)temp_str); + gfx = video_card_getid(temp_str); + + h = GetDlgItem(hdlg, IDC_CONFIGUREVID); + if (video_card_has_config(gfx)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + break; + + case IDC_CONFIGURESND: + h = GetDlgItem(hdlg, IDC_COMBOSND); + temp_sound_card_current = settings_list_to_sound[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + deviceconfig_open(hdlg, (void *)sound_card_getdevice(temp_sound_card_current)); + break; + + case IDC_COMBOSND: + h = GetDlgItem(hdlg, IDC_COMBOSND); + temp_sound_card_current = settings_list_to_sound[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_CONFIGURESND); + if (sound_card_has_config(temp_sound_card_current)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + break; + + case IDC_CONFIGURENET: + h = GetDlgItem(hdlg, IDC_COMBONET); + temp_network_card_current = settings_list_to_network[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + deviceconfig_open(hdlg, (void *)network_card_getdevice(temp_network_card_current)); + break; + + case IDC_COMBONET: + h = GetDlgItem(hdlg, IDC_COMBONET); + temp_network_card_current = settings_list_to_network[SendMessage(h, CB_GETCURSEL, 0, 0)]; + + h = GetDlgItem(hdlg, IDC_CONFIGURENET); + if (network_card_has_config(temp_network_card_current)) + EnableWindow(h, TRUE); + else + EnableWindow(h, FALSE); + break; + + case IDC_CONFIGUREVOODOO: + deviceconfig_open(hdlg, (void *)&voodoo_device); + break; + + case IDC_COMBOJOY: + if (HIWORD(wParam) == CBN_SELCHANGE) + { + h = GetDlgItem(hdlg, IDC_COMBOJOY); + temp_joystick_type = SendMessage(h, CB_GETCURSEL, 0, 0); + + h = GetDlgItem(hdlg, IDC_JOY1); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick_type) >= 1) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY2); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick_type) >= 2) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY3); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick_type) >= 3) ? TRUE : FALSE); + h = GetDlgItem(hdlg, IDC_JOY4); + EnableWindow(h, (joystick_get_max_joysticks(temp_joystick_type) >= 4) ? TRUE : FALSE); + } + break; + + case IDC_JOY1: + h = GetDlgItem(hdlg, IDC_COMBOJOY); + temp_joystick_type = SendMessage(h, CB_GETCURSEL, 0, 0); + joystickconfig_open(hdlg, 0, temp_joystick_type); + break; + case IDC_JOY2: + h = GetDlgItem(hdlg, IDC_COMBOJOY); + temp_joystick_type = SendMessage(h, CB_GETCURSEL, 0, 0); + joystickconfig_open(hdlg, 1, temp_joystick_type); + break; + case IDC_JOY3: + h = GetDlgItem(hdlg, IDC_COMBOJOY); + temp_joystick_type = SendMessage(h, CB_GETCURSEL, 0, 0); + joystickconfig_open(hdlg, 2, temp_joystick_type); + break; + case IDC_JOY4: + h = GetDlgItem(hdlg, IDC_COMBOJOY); + temp_joystick_type = SendMessage(h, CB_GETCURSEL, 0, 0); + joystickconfig_open(hdlg, 3, temp_joystick_type); + break; + } + break; + } + return FALSE; +} + +void config_open(HWND hwnd) +{ + DialogBox(hinstance, TEXT("ConfigureDlg"), hwnd, config_dlgproc); +} diff --git a/src/win-d3d-fs.cc b/src/win-d3d-fs.cc new file mode 100644 index 000000000..7603dd23f --- /dev/null +++ b/src/win-d3d-fs.cc @@ -0,0 +1,506 @@ +#include +#define BITMAP WINDOWS_BITMAP +#include +#undef BITMAP +#include +#include "resources.h" +#include "video.h" +#include "win-d3d-fs.h" +#include "win.h" + +extern "C" void fatal(const char *format, ...); +extern "C" void pclog(const char *format, ...); + +extern "C" void device_force_redraw(); + +static void d3d_fs_init_objects(); +static void d3d_fs_close_objects(); +static void d3d_fs_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h); +static void d3d_fs_blit_memtoscreen_8(int x, int y, int w, int h); + +static LPDIRECT3D9 d3d = NULL; +static LPDIRECT3DDEVICE9 d3ddev = NULL; +static LPDIRECT3DVERTEXBUFFER9 v_buffer = NULL; +static LPDIRECT3DTEXTURE9 d3dTexture = NULL; +static D3DPRESENT_PARAMETERS d3dpp; + +static HWND d3d_hwnd; +static HWND d3d_device_window; + +static int d3d_fs_w, d3d_fs_h; + +struct CUSTOMVERTEX +{ + FLOAT x, y, z, rhw; // from the D3DFVF_XYZRHW flag + FLOAT tu, tv; +}; + +static PALETTE cgapal= +{ + {0,0,0},{0,42,0},{42,0,0},{42,21,0}, + {0,0,0},{0,42,42},{42,0,42},{42,42,42}, + {0,0,0},{21,63,21},{63,21,21},{63,63,21}, + {0,0,0},{21,63,63},{63,21,63},{63,63,63}, + + {0,0,0},{0,0,42},{0,42,0},{0,42,42}, + {42,0,0},{42,0,42},{42,21,00},{42,42,42}, + {21,21,21},{21,21,63},{21,63,21},{21,63,63}, + {63,21,21},{63,21,63},{63,63,21},{63,63,63}, + + {0,0,0},{0,21,0},{0,0,42},{0,42,42}, + {42,0,21},{21,10,21},{42,0,42},{42,0,63}, + {21,21,21},{21,63,21},{42,21,42},{21,63,63}, + {63,0,0},{42,42,0},{63,21,42},{41,41,41}, + + {0,0,0},{0,42,42},{42,0,0},{42,42,42}, + {0,0,0},{0,42,42},{42,0,0},{42,42,42}, + {0,0,0},{0,63,63},{63,0,0},{63,63,63}, + {0,0,0},{0,63,63},{63,0,0},{63,63,63}, +}; + +static uint32_t pal_lookup[256]; + +static CUSTOMVERTEX d3d_verts[] = +{ + { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f}, + {2080.0f, 2080.0f, 1.0f, 1.0f, 1.0f, 1.0f}, + { 0.0f, 2080.0f, 1.0f, 1.0f, 0.0f, 1.0f}, + + { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f}, + {2080.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f}, + {2080.0f, 2080.0f, 1.0f, 1.0f, 1.0f, 1.0f}, +}; + +void d3d_fs_init(HWND h) +{ + int c; + HRESULT hr; + + d3d_fs_w = GetSystemMetrics(SM_CXSCREEN); + d3d_fs_h = GetSystemMetrics(SM_CYSCREEN); + + for (c = 0; c < 256; c++) + pal_lookup[c] = makecol(cgapal[c].r << 2, cgapal[c].g << 2, cgapal[c].b << 2); + + d3d_hwnd = h; + + d3d_device_window = CreateWindowEx ( + 0, + szSubClassName, + "PCem v11 [Experimental]", + WS_POPUP, + CW_USEDEFAULT, + CW_USEDEFAULT, + 640, + 480, + HWND_DESKTOP, + NULL, + NULL, + NULL + ); + + d3d = Direct3DCreate9(D3D_SDK_VERSION); + + memset(&d3dpp, 0, sizeof(d3dpp)); + + d3dpp.Flags = 0; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.hDeviceWindow = d3d_device_window; + d3dpp.BackBufferCount = 1; + d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; + d3dpp.MultiSampleQuality = 0; + d3dpp.EnableAutoDepthStencil = false; + d3dpp.AutoDepthStencilFormat = D3DFMT_UNKNOWN; + d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + d3dpp.Windowed = false; + d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8; + d3dpp.BackBufferWidth = d3d_fs_w; + d3dpp.BackBufferHeight = d3d_fs_h; + + hr = d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, h, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev); + + d3d_fs_init_objects(); + + video_blit_memtoscreen = d3d_fs_blit_memtoscreen; + video_blit_memtoscreen_8 = d3d_fs_blit_memtoscreen_8; +} + +static void d3d_fs_close_objects() +{ + if (d3dTexture) + { + d3dTexture->Release(); + d3dTexture = NULL; + } + if (v_buffer) + { + v_buffer->Release(); + v_buffer = NULL; + } +} + +static void d3d_fs_init_objects() +{ + HRESULT hr; + D3DLOCKED_RECT dr; + int y; + RECT r; + + hr = d3ddev->CreateVertexBuffer(6*sizeof(CUSTOMVERTEX), + 0, + D3DFVF_XYZRHW | D3DFVF_TEX1, + D3DPOOL_MANAGED, + &v_buffer, + NULL); + + d3ddev->CreateTexture(2080, 2080, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &d3dTexture, NULL); + + r.top = r.left = 0; + r.bottom = 2079; + r.right = 2079; + + if (FAILED(d3dTexture->LockRect(0, &dr, &r, 0))) + fatal("LockRect failed\n"); + + for (y = 0; y < 2080; y++) + { + uint32_t *p = (uint32_t *)(dr.pBits + (y * dr.Pitch)); + memset(p, 0, 2080 * 4); + } + + d3dTexture->UnlockRect(0); + + d3ddev->SetTextureStageState(0,D3DTSS_COLOROP, D3DTOP_SELECTARG1); + d3ddev->SetTextureStageState(0,D3DTSS_COLORARG1, D3DTA_TEXTURE); + d3ddev->SetTextureStageState(0,D3DTSS_ALPHAOP, D3DTOP_DISABLE); + + d3ddev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + d3ddev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); +} + +/*void d3d_resize(int x, int y) +{ + HRESULT hr; + + d3dpp.BackBufferWidth = x; + d3dpp.BackBufferHeight = y; + + d3d_reset(); +}*/ + +void d3d_fs_reset() +{ + HRESULT hr; + + memset(&d3dpp, 0, sizeof(d3dpp)); + + d3dpp.Flags = 0; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.hDeviceWindow = d3d_device_window; + d3dpp.BackBufferCount = 1; + d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; + d3dpp.MultiSampleQuality = 0; + d3dpp.EnableAutoDepthStencil = false; + d3dpp.AutoDepthStencilFormat = D3DFMT_UNKNOWN; + d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + d3dpp.Windowed = false; + d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8; + d3dpp.BackBufferWidth = d3d_fs_w; + d3dpp.BackBufferHeight = d3d_fs_h; + + hr = d3ddev->Reset(&d3dpp); + + if (hr == D3DERR_DEVICELOST) + return; + + d3ddev->SetTextureStageState(0,D3DTSS_COLOROP, D3DTOP_SELECTARG1); + d3ddev->SetTextureStageState(0,D3DTSS_COLORARG1, D3DTA_TEXTURE); + d3ddev->SetTextureStageState(0,D3DTSS_ALPHAOP, D3DTOP_DISABLE); + + d3ddev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + d3ddev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + + device_force_redraw(); +} + +void d3d_fs_close() +{ + if (d3dTexture) + { + d3dTexture->Release(); + d3dTexture = NULL; + } + if (v_buffer) + { + v_buffer->Release(); + v_buffer = NULL; + } + if (d3ddev) + { + d3ddev->Release(); + d3ddev = NULL; + } + if (d3d) + { + d3d->Release(); + d3d = NULL; + } + DestroyWindow(d3d_device_window); +} + +static void d3d_fs_size(RECT window_rect, double *l, double *t, double *r, double *b, int w, int h) +{ + int ratio_w, ratio_h; + switch (video_fullscreen_scale) + { + case FULLSCR_SCALE_FULL: + *l = -0.5; + *t = -0.5; + *r = (window_rect.right - window_rect.left) - 0.5; + *b = (window_rect.bottom - window_rect.top) - 0.5; + break; + case FULLSCR_SCALE_43: + *t = -0.5; + *b = (window_rect.bottom - window_rect.top) - 0.5; + *l = ((window_rect.right - window_rect.left) / 2) - (((window_rect.bottom - window_rect.top) * 4) / (3 * 2)) - 0.5; + *r = ((window_rect.right - window_rect.left) / 2) + (((window_rect.bottom - window_rect.top) * 4) / (3 * 2)) - 0.5; + if (*l < -0.5) + { + *l = -0.5; + *r = (window_rect.right - window_rect.left) - 0.5; + *t = ((window_rect.bottom - window_rect.top) / 2) - (((window_rect.right - window_rect.left) * 3) / (4 * 2)) - 0.5; + *b = ((window_rect.bottom - window_rect.top) / 2) + (((window_rect.right - window_rect.left) * 3) / (4 * 2)) - 0.5; + } + break; + case FULLSCR_SCALE_SQ: + *t = -0.5; + *b = (window_rect.bottom - window_rect.top) - 0.5; + *l = ((window_rect.right - window_rect.left) / 2) - (((window_rect.bottom - window_rect.top) * w) / (h * 2)) - 0.5; + *r = ((window_rect.right - window_rect.left) / 2) + (((window_rect.bottom - window_rect.top) * w) / (h * 2)) - 0.5; + if (*l < -0.5) + { + *l = -0.5; + *r = (window_rect.right - window_rect.left) - 0.5; + *t = ((window_rect.bottom - window_rect.top) / 2) - (((window_rect.right - window_rect.left) * h) / (w * 2)) - 0.5; + *b = ((window_rect.bottom - window_rect.top) / 2) + (((window_rect.right - window_rect.left) * h) / (w * 2)) - 0.5; + } + break; + case FULLSCR_SCALE_INT: + ratio_w = (window_rect.right - window_rect.left) / w; + ratio_h = (window_rect.bottom - window_rect.top) / h; + if (ratio_h < ratio_w) + ratio_w = ratio_h; + *l = ((window_rect.right - window_rect.left) / 2) - ((w * ratio_w) / 2) - 0.5; + *r = ((window_rect.right - window_rect.left) / 2) + ((w * ratio_w) / 2) - 0.5; + *t = ((window_rect.bottom - window_rect.top) / 2) - ((h * ratio_w) / 2) - 0.5; + *b = ((window_rect.bottom - window_rect.top) / 2) + ((h * ratio_w) / 2) - 0.5; + break; + } +} + +static void d3d_fs_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) +{ + HRESULT hr = D3D_OK; + VOID* pVoid; + D3DLOCKED_RECT dr; + RECT window_rect; + uint32_t *p, *src; + int yy; + double l, t, r, b; + + if (y1 == y2) + return; /*Nothing to do*/ + + d3d_verts[0].tu = d3d_verts[2].tu = d3d_verts[3].tu = 0; + d3d_verts[0].tv = d3d_verts[3].tv = d3d_verts[4].tv = 0; + d3d_verts[1].tu = d3d_verts[4].tu = d3d_verts[5].tu = (float)w / 2080.0; + d3d_verts[1].tv = d3d_verts[2].tv = d3d_verts[5].tv = (float)h / 2080.0; + + GetClientRect(d3d_device_window, &window_rect); + d3d_fs_size(window_rect, &l, &t, &r, &b, w, h); + + d3d_verts[0].x = l; + d3d_verts[0].y = t; + d3d_verts[1].x = r; + d3d_verts[1].y = b; + d3d_verts[2].x = l; + d3d_verts[2].y = b; + d3d_verts[3].x = l; + d3d_verts[3].y = t; + d3d_verts[4].x = r; + d3d_verts[4].y = t; + d3d_verts[5].x = r; + d3d_verts[5].y = b; + + if (hr == D3D_OK) + hr = v_buffer->Lock(0, 0, (void**)&pVoid, 0); + if (hr == D3D_OK) + memcpy(pVoid, d3d_verts, sizeof(d3d_verts)); + if (hr == D3D_OK) + hr = v_buffer->Unlock(); + + if (hr == D3D_OK && !(y1 == 0 && y2 == 0)) + { + RECT lock_rect; + + lock_rect.top = y1; + lock_rect.left = 0; + lock_rect.bottom = y2; + lock_rect.right = 2079; + + if (FAILED(d3dTexture->LockRect(0, &dr, &lock_rect, 0))) + fatal("LockRect failed\n"); + + for (yy = y1; yy < y2; yy++) + memcpy(dr.pBits + ((yy - y1) * dr.Pitch), &(((uint32_t *)buffer32->line[yy + y])[x]), w * 4); + + d3dTexture->UnlockRect(0); + } + + if (hr == D3D_OK) + hr = d3ddev->BeginScene(); + + if (hr == D3D_OK) + { + if (hr == D3D_OK) + d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0, 0); + + if (hr == D3D_OK) + hr = d3ddev->SetTexture(0, d3dTexture); + + if (hr == D3D_OK) + hr = d3ddev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + + if (hr == D3D_OK) + hr = d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX)); + + if (hr == D3D_OK) + hr = d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2); + + if (hr == D3D_OK) + hr = d3ddev->SetTexture(0, NULL); + + if (hr == D3D_OK) + hr = d3ddev->EndScene(); + } + + if (hr == D3D_OK) + hr = d3ddev->Present(NULL, NULL, d3d_device_window, NULL); + + if (hr == D3DERR_DEVICELOST || hr == D3DERR_INVALIDCALL) + PostMessage(ghwnd, WM_RESETD3D, 0, 0); +} + +static void d3d_fs_blit_memtoscreen_8(int x, int y, int w, int h) +{ + HRESULT hr = D3D_OK; + VOID* pVoid; + D3DLOCKED_RECT dr; + RECT window_rect; + uint32_t *p, *src; + int xx, yy; + double l, t, r, b; + + if (!h) + return; /*Nothing to do*/ + + d3d_verts[0].tu = d3d_verts[2].tu = d3d_verts[3].tu = 0; + d3d_verts[0].tv = d3d_verts[3].tv = d3d_verts[4].tv = 0; + d3d_verts[1].tu = d3d_verts[4].tu = d3d_verts[5].tu = (float)w / 2080.0; + d3d_verts[1].tv = d3d_verts[2].tv = d3d_verts[5].tv = (float)h / 2080.0; + + GetClientRect(d3d_device_window, &window_rect); + d3d_fs_size(window_rect, &l, &t, &r, &b, w, h); + + d3d_verts[0].x = l; + d3d_verts[0].y = t; + d3d_verts[1].x = r; + d3d_verts[1].y = b; + d3d_verts[2].x = l; + d3d_verts[2].y = b; + d3d_verts[3].x = l; + d3d_verts[3].y = t; + d3d_verts[4].x = r; + d3d_verts[4].y = t; + d3d_verts[5].x = r; + d3d_verts[5].y = b; + + if (hr == D3D_OK) + hr = v_buffer->Lock(0, 0, (void**)&pVoid, 0); + if (hr == D3D_OK) + memcpy(pVoid, d3d_verts, sizeof(d3d_verts)); + if (hr == D3D_OK) + hr = v_buffer->Unlock(); + + if (hr == D3D_OK) + { + RECT lock_rect; + + lock_rect.top = 0; + lock_rect.left = 0; + lock_rect.bottom = 2079; + lock_rect.right = 2079; + + if (FAILED(d3dTexture->LockRect(0, &dr, &lock_rect, 0))) + fatal("LockRect failed\n"); + + for (yy = 0; yy < h; yy++) + { + uint32_t *p = (uint32_t *)(dr.pBits + (yy * dr.Pitch)); + if ((y + yy) >= 0 && (y + yy) < buffer->h) + { + for (xx = 0; xx < w; xx++) + p[xx] = pal_lookup[buffer->line[y + yy][x + xx]]; + } + } + + d3dTexture->UnlockRect(0); + } + + if (hr == D3D_OK) + hr = d3ddev->BeginScene(); + + if (hr == D3D_OK) + { + if (hr == D3D_OK) + d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0, 0); + + if (hr == D3D_OK) + hr = d3ddev->SetTexture(0, d3dTexture); + + if (hr == D3D_OK) + hr = d3ddev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + + if (hr == D3D_OK) + hr = d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX)); + + if (hr == D3D_OK) + hr = d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2); + + if (hr == D3D_OK) + hr = d3ddev->SetTexture(0, NULL); + + if (hr == D3D_OK) + hr = d3ddev->EndScene(); + } + + if (hr == D3D_OK) + hr = d3ddev->Present(NULL, NULL, d3d_device_window, NULL); + + if (hr == D3DERR_DEVICELOST || hr == D3DERR_INVALIDCALL) + PostMessage(ghwnd, WM_RESETD3D, 0, 0); +} + +void d3d_fs_take_screenshot(char *fn) +{ + HRESULT hr = D3D_OK; + LPDIRECT3DSURFACE9 d3dSurface = NULL; + + if (!d3dTexture) return; + + hr = d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &d3dSurface); + hr = D3DXSaveSurfaceToFile(fn, D3DXIFF_PNG, d3dSurface, NULL, NULL); + + d3dSurface->Release(); + d3dSurface = NULL; +} diff --git a/src/win-d3d-fs.h b/src/win-d3d-fs.h new file mode 100644 index 000000000..e0684ec1c --- /dev/null +++ b/src/win-d3d-fs.h @@ -0,0 +1,10 @@ +#ifdef __cplusplus +extern "C" { +#endif + void d3d_fs_init(HWND h); + void d3d_fs_close(); + void d3d_fs_reset(); + void d3d_fs_resize(int x, int y); +#ifdef __cplusplus +} +#endif diff --git a/src/win-d3d.cc b/src/win-d3d.cc new file mode 100644 index 000000000..a5a04b824 --- /dev/null +++ b/src/win-d3d.cc @@ -0,0 +1,401 @@ +#include +#define BITMAP WINDOWS_BITMAP +#include +#undef BITMAP +#include +#include "resources.h" +#include "win-d3d.h" +#include "video.h" + +extern "C" void fatal(const char *format, ...); +extern "C" void pclog(const char *format, ...); + +extern "C" void device_force_redraw(); + +void d3d_init_objects(); +void d3d_close_objects(); +void d3d_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h); +void d3d_blit_memtoscreen_8(int x, int y, int w, int h); + +static LPDIRECT3D9 d3d = NULL; +static LPDIRECT3DDEVICE9 d3ddev = NULL; +static LPDIRECT3DVERTEXBUFFER9 v_buffer = NULL; +static LPDIRECT3DTEXTURE9 d3dTexture = NULL; +static D3DPRESENT_PARAMETERS d3dpp; + +static HWND d3d_hwnd; + +struct CUSTOMVERTEX +{ + FLOAT x, y, z, rhw; // from the D3DFVF_XYZRHW flag + FLOAT tu, tv; +}; + +static PALETTE cgapal= +{ + {0,0,0},{0,42,0},{42,0,0},{42,21,0}, + {0,0,0},{0,42,42},{42,0,42},{42,42,42}, + {0,0,0},{21,63,21},{63,21,21},{63,63,21}, + {0,0,0},{21,63,63},{63,21,63},{63,63,63}, + + {0,0,0},{0,0,42},{0,42,0},{0,42,42}, + {42,0,0},{42,0,42},{42,21,00},{42,42,42}, + {21,21,21},{21,21,63},{21,63,21},{21,63,63}, + {63,21,21},{63,21,63},{63,63,21},{63,63,63}, + + {0,0,0},{0,21,0},{0,0,42},{0,42,42}, + {42,0,21},{21,10,21},{42,0,42},{42,0,63}, + {21,21,21},{21,63,21},{42,21,42},{21,63,63}, + {63,0,0},{42,42,0},{63,21,42},{41,41,41}, + + {0,0,0},{0,42,42},{42,0,0},{42,42,42}, + {0,0,0},{0,42,42},{42,0,0},{42,42,42}, + {0,0,0},{0,63,63},{63,0,0},{63,63,63}, + {0,0,0},{0,63,63},{63,0,0},{63,63,63}, +}; + +static uint32_t pal_lookup[256]; + +static CUSTOMVERTEX d3d_verts[] = +{ + { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f}, + {2080.0f, 2080.0f, 1.0f, 1.0f, 1.0f, 1.0f}, + { 0.0f, 2080.0f, 1.0f, 1.0f, 0.0f, 1.0f}, + + { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f}, + {2080.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f}, + {2080.0f, 2080.0f, 1.0f, 1.0f, 1.0f, 1.0f}, +}; + +void d3d_init(HWND h) +{ + int c; + HRESULT hr; + + for (c = 0; c < 256; c++) + pal_lookup[c] = makecol(cgapal[c].r << 2, cgapal[c].g << 2, cgapal[c].b << 2); + + d3d_hwnd = h; + + d3d = Direct3DCreate9(D3D_SDK_VERSION); + + memset(&d3dpp, 0, sizeof(d3dpp)); + + d3dpp.Flags = 0; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.hDeviceWindow = h; + d3dpp.BackBufferCount = 1; + d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; + d3dpp.MultiSampleQuality = 0; + d3dpp.EnableAutoDepthStencil = false; + d3dpp.AutoDepthStencilFormat = D3DFMT_UNKNOWN; + d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + d3dpp.Windowed = true; + d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; + d3dpp.BackBufferWidth = 0; + d3dpp.BackBufferHeight = 0; + + hr = d3d->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, h, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev); + + d3d_init_objects(); + + video_blit_memtoscreen = d3d_blit_memtoscreen; + video_blit_memtoscreen_8 = d3d_blit_memtoscreen_8; +} + +void d3d_close_objects() +{ + if (d3dTexture) + { + d3dTexture->Release(); + d3dTexture = NULL; + } + if (v_buffer) + { + v_buffer->Release(); + v_buffer = NULL; + } +} + +void d3d_init_objects() +{ + HRESULT hr; + D3DLOCKED_RECT dr; + int y; + RECT r; + + hr = d3ddev->CreateVertexBuffer(6*sizeof(CUSTOMVERTEX), + 0, + D3DFVF_XYZRHW | D3DFVF_TEX1, + D3DPOOL_MANAGED, + &v_buffer, + NULL); + + d3ddev->CreateTexture(2080, 2080, 1, 0, D3DFMT_X8R8G8B8, D3DPOOL_MANAGED, &d3dTexture, NULL); + + r.top = r.left = 0; + r.bottom = 2079; + r.right = 2079; + + if (FAILED(d3dTexture->LockRect(0, &dr, &r, 0))) + fatal("LockRect failed\n"); + + for (y = 0; y < 2056; y++) + { + uint32_t *p = (uint32_t *)(dr.pBits + (y * dr.Pitch)); + memset(p, 0, 2064 * 4); + } + + d3dTexture->UnlockRect(0); + + d3ddev->SetTextureStageState(0,D3DTSS_COLOROP, D3DTOP_SELECTARG1); + d3ddev->SetTextureStageState(0,D3DTSS_COLORARG1, D3DTA_TEXTURE); + d3ddev->SetTextureStageState(0,D3DTSS_ALPHAOP, D3DTOP_DISABLE); + + d3ddev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + d3ddev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); +} + +void d3d_resize(int x, int y) +{ + HRESULT hr; + + d3dpp.BackBufferWidth = x; + d3dpp.BackBufferHeight = y; + + d3d_reset(); +} + +void d3d_reset() +{ + HRESULT hr; + + memset(&d3dpp, 0, sizeof(d3dpp)); + + d3dpp.Flags = 0; + d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD; + d3dpp.hDeviceWindow = d3d_hwnd; + d3dpp.BackBufferCount = 1; + d3dpp.MultiSampleType = D3DMULTISAMPLE_NONE; + d3dpp.MultiSampleQuality = 0; + d3dpp.EnableAutoDepthStencil = false; + d3dpp.AutoDepthStencilFormat = D3DFMT_UNKNOWN; + d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; + d3dpp.Windowed = true; + d3dpp.BackBufferFormat = D3DFMT_UNKNOWN; + d3dpp.BackBufferWidth = 0; + d3dpp.BackBufferHeight = 0; + + hr = d3ddev->Reset(&d3dpp); + + if (hr == D3DERR_DEVICELOST) + return; + + d3ddev->SetTextureStageState(0,D3DTSS_COLOROP, D3DTOP_SELECTARG1); + d3ddev->SetTextureStageState(0,D3DTSS_COLORARG1, D3DTA_TEXTURE); + d3ddev->SetTextureStageState(0,D3DTSS_ALPHAOP, D3DTOP_DISABLE); + + d3ddev->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + d3ddev->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + + device_force_redraw(); +} + +void d3d_close() +{ + if (d3dTexture) + { + d3dTexture->Release(); + d3dTexture = NULL; + } + if (v_buffer) + { + v_buffer->Release(); + v_buffer = NULL; + } + if (d3ddev) + { + d3ddev->Release(); + d3ddev = NULL; + } + if (d3d) + { + d3d->Release(); + d3d = NULL; + } +} + +void d3d_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) +{ + HRESULT hr = D3D_OK; + VOID* pVoid; + D3DLOCKED_RECT dr; + RECT r; + uint32_t *p, *src; + int yy; + + if (y1 == y2) + return; /*Nothing to do*/ + + d3d_verts[0].tu = d3d_verts[2].tu = d3d_verts[3].tu = 0;//0.5 / 2048.0; + d3d_verts[0].tv = d3d_verts[3].tv = d3d_verts[4].tv = 0;//0.5 / 2048.0; + d3d_verts[1].tu = d3d_verts[4].tu = d3d_verts[5].tu = (float)w / 2080.0; + d3d_verts[1].tv = d3d_verts[2].tv = d3d_verts[5].tv = (float)h / 2080.0; + + GetClientRect(d3d_hwnd, &r); + d3d_verts[0].x = d3d_verts[2].x = d3d_verts[3].x = -0.5; + d3d_verts[0].y = d3d_verts[3].y = d3d_verts[4].y = -0.5; + d3d_verts[1].x = d3d_verts[4].x = d3d_verts[5].x = (r.right - r.left) - 0.5; + d3d_verts[1].y = d3d_verts[2].y = d3d_verts[5].y = (r.bottom - r.top) - 0.5; + + if (hr == D3D_OK) + hr = v_buffer->Lock(0, 0, (void**)&pVoid, 0); // lock the vertex buffer + if (hr == D3D_OK) + memcpy(pVoid, d3d_verts, sizeof(d3d_verts)); // copy the vertices to the locked buffer + if (hr == D3D_OK) + hr = v_buffer->Unlock(); // unlock the vertex buffer + + r.top = y1; + r.left = 0; + r.bottom = y2; + r.right = 2079; + + if (hr == D3D_OK) + { + if (FAILED(d3dTexture->LockRect(0, &dr, &r, 0))) + fatal("LockRect failed\n"); + + for (yy = y1; yy < y2; yy++) + memcpy(dr.pBits + ((yy - y1) * dr.Pitch), &(((uint32_t *)buffer32->line[yy + y])[x]), w * 4); + + d3dTexture->UnlockRect(0); + } + + if (hr == D3D_OK) + hr = d3ddev->BeginScene(); + + if (hr == D3D_OK) + { + if (hr == D3D_OK) + hr = d3ddev->SetTexture(0, d3dTexture); + + if (hr == D3D_OK) + hr = d3ddev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + + if (hr == D3D_OK) + hr = d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX)); + + if (hr == D3D_OK) + hr = d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2); + + if (hr == D3D_OK) + hr = d3ddev->SetTexture(0, NULL); + + if (hr == D3D_OK) + hr = d3ddev->EndScene(); + } + + if (hr == D3D_OK) + hr = d3ddev->Present(NULL, NULL, d3d_hwnd, NULL); + + if (hr == D3DERR_DEVICELOST || hr == D3DERR_INVALIDCALL) + PostMessage(d3d_hwnd, WM_RESETD3D, 0, 0); +} + +void d3d_blit_memtoscreen_8(int x, int y, int w, int h) +{ + VOID* pVoid; + D3DLOCKED_RECT dr; + RECT r; + uint32_t *p, *src; + int yy, xx; + HRESULT hr = D3D_OK; + + if (h == 0) + return; /*Nothing to do*/ + + d3d_verts[0].tu = d3d_verts[2].tu = d3d_verts[3].tu = 0;//0.5 / 2080.0; + d3d_verts[0].tv = d3d_verts[3].tv = d3d_verts[4].tv = 0;//0.5 / 2080.0; + d3d_verts[1].tu = d3d_verts[4].tu = d3d_verts[5].tu = (float)w / 2080.0; + d3d_verts[1].tv = d3d_verts[2].tv = d3d_verts[5].tv = (float)h / 2080.0; + + GetClientRect(d3d_hwnd, &r); + d3d_verts[0].x = d3d_verts[2].x = d3d_verts[3].x = -0.5; + d3d_verts[0].y = d3d_verts[3].y = d3d_verts[4].y = -0.5; + d3d_verts[1].x = d3d_verts[4].x = d3d_verts[5].x = (r.right - r.left) - 0.5; + d3d_verts[1].y = d3d_verts[2].y = d3d_verts[5].y = (r.bottom - r.top) - 0.5; + + if (hr == D3D_OK) + hr = v_buffer->Lock(0, 0, (void**)&pVoid, 0); // lock the vertex buffer + if (hr == D3D_OK) + memcpy(pVoid, d3d_verts, sizeof(d3d_verts)); // copy the vertices to the locked buffer + if (hr == D3D_OK) + hr = v_buffer->Unlock(); // unlock the vertex buffer + + r.top = 0; + r.left = 0; + r.bottom = h; + r.right = 2079; + + if (hr == D3D_OK) + { + if (FAILED(d3dTexture->LockRect(0, &dr, &r, 0))) + fatal("LockRect failed\n"); + + for (yy = 0; yy < h; yy++) + { + uint32_t *p = (uint32_t *)(dr.pBits + (yy * dr.Pitch)); + if ((y + yy) >= 0 && (y + yy) < buffer->h) + { + for (xx = 0; xx < w; xx++) + p[xx] = pal_lookup[buffer->line[y + yy][x + xx]]; + } + } + + d3dTexture->UnlockRect(0); + } + + if (hr == D3D_OK) + hr = d3ddev->BeginScene(); + + if (hr == D3D_OK) + { + if (hr == D3D_OK) + hr = d3ddev->SetTexture(0, d3dTexture); + + if (hr == D3D_OK) + hr = d3ddev->SetFVF(D3DFVF_XYZRHW | D3DFVF_TEX1); + + if (hr == D3D_OK) + hr = d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(CUSTOMVERTEX)); + + if (hr == D3D_OK) + hr = d3ddev->DrawPrimitive(D3DPT_TRIANGLELIST, 0, 2); + + if (hr == D3D_OK) + hr = d3ddev->SetTexture(0, NULL); + + if (hr == D3D_OK) + hr = d3ddev->EndScene(); + } + + if (hr == D3D_OK) + hr = d3ddev->Present(NULL, NULL, d3d_hwnd, NULL); + + if (hr == D3DERR_DEVICELOST || hr == D3DERR_INVALIDCALL) + PostMessage(d3d_hwnd, WM_RESETD3D, 0, 0); +} + +void d3d_take_screenshot(char *fn) +{ + HRESULT hr = D3D_OK; + LPDIRECT3DSURFACE9 d3dSurface = NULL; + + if (!d3dTexture) return; + + hr = d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &d3dSurface); + hr = D3DXSaveSurfaceToFile(fn, D3DXIFF_PNG, d3dSurface, NULL, NULL); + + d3dSurface->Release(); + d3dSurface = NULL; +} diff --git a/src/win-d3d.h b/src/win-d3d.h new file mode 100644 index 000000000..33a23432a --- /dev/null +++ b/src/win-d3d.h @@ -0,0 +1,10 @@ +#ifdef __cplusplus +extern "C" { +#endif + void d3d_init(HWND h); + void d3d_close(); + void d3d_reset(); + void d3d_resize(int x, int y); +#ifdef __cplusplus +} +#endif diff --git a/src/win-ddraw-fs.cc b/src/win-ddraw-fs.cc new file mode 100644 index 000000000..b598d0a28 --- /dev/null +++ b/src/win-ddraw-fs.cc @@ -0,0 +1,336 @@ +#include +#define BITMAP WINDOWS_BITMAP +#include +#undef BITMAP +#include "win-ddraw-fs.h" +#include "win-ddraw-screenshot.h" +#include "video.h" + +extern "C" void fatal(const char *format, ...); +extern "C" void pclog(const char *format, ...); + +extern "C" void device_force_redraw(); + +extern "C" void ddraw_fs_init(HWND h); +extern "C" void ddraw_fs_close(); + +static void ddraw_fs_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h); +static void ddraw_fs_blit_memtoscreen_8(int x, int y, int w, int h); + +static LPDIRECTDRAW lpdd = NULL; +static LPDIRECTDRAW4 lpdd4 = NULL; +static LPDIRECTDRAWSURFACE4 lpdds_pri = NULL; +static LPDIRECTDRAWSURFACE4 lpdds_back = NULL; +static LPDIRECTDRAWSURFACE4 lpdds_back2 = NULL; +static LPDIRECTDRAWCLIPPER lpdd_clipper = NULL; +static DDSURFACEDESC2 ddsd; + +static HWND ddraw_hwnd; +static int ddraw_w, ddraw_h; + +static PALETTE cgapal = +{ + {0,0,0},{0,42,0},{42,0,0},{42,21,0}, + {0,0,0},{0,42,42},{42,0,42},{42,42,42}, + {0,0,0},{21,63,21},{63,21,21},{63,63,21}, + {0,0,0},{21,63,63},{63,21,63},{63,63,63}, + + {0,0,0},{0,0,42},{0,42,0},{0,42,42}, + {42,0,0},{42,0,42},{42,21,00},{42,42,42}, + {21,21,21},{21,21,63},{21,63,21},{21,63,63}, + {63,21,21},{63,21,63},{63,63,21},{63,63,63}, + + {0,0,0},{0,21,0},{0,0,42},{0,42,42}, + {42,0,21},{21,10,21},{42,0,42},{42,0,63}, + {21,21,21},{21,63,21},{42,21,42},{21,63,63}, + {63,0,0},{42,42,0},{63,21,42},{41,41,41}, + + {0,0,0},{0,42,42},{42,0,0},{42,42,42}, + {0,0,0},{0,42,42},{42,0,0},{42,42,42}, + {0,0,0},{0,63,63},{63,0,0},{63,63,63}, + {0,0,0},{0,63,63},{63,0,0},{63,63,63}, +}; + +static uint32_t pal_lookup[256]; + +void ddraw_fs_init(HWND h) +{ + int c; + + ddraw_w = GetSystemMetrics(SM_CXSCREEN); + ddraw_h = GetSystemMetrics(SM_CYSCREEN); + + for (c = 0; c < 256; c++) + pal_lookup[c] = makecol(cgapal[c].r << 2, cgapal[c].g << 2, cgapal[c].b << 2); + + if (FAILED(DirectDrawCreate(NULL, &lpdd, NULL))) + fatal("DirectDrawCreate failed\n"); + + if (FAILED(lpdd->QueryInterface(IID_IDirectDraw4, (LPVOID *)&lpdd4))) + fatal("QueryInterface failed\n"); + + lpdd->Release(); + lpdd = NULL; + + atexit(ddraw_fs_close); + + if (FAILED(lpdd4->SetCooperativeLevel(h, DDSCL_SETFOCUSWINDOW | + DDSCL_CREATEDEVICEWINDOW | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN | DDSCL_ALLOWREBOOT))) + fatal("SetCooperativeLevel failed\n"); + + if (FAILED(lpdd4->SetDisplayMode(ddraw_w, ddraw_h, 32, 0 ,0))) + fatal("SetDisplayMode failed\n"); + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; + ddsd.dwBackBufferCount = 1; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_COMPLEX | DDSCAPS_FLIP; + if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_pri, NULL))) + fatal("CreateSurface failed\n"); + + ddsd.ddsCaps.dwCaps = DDSCAPS_BACKBUFFER; + if (FAILED(lpdds_pri->GetAttachedSurface(&ddsd.ddsCaps, &lpdds_back2))) + fatal("CreateSurface back failed\n"); + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + ddsd.dwWidth = 2080; + ddsd.dwHeight = 2080; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; + if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_back, NULL))) + fatal("CreateSurface back failed\n"); + + pclog("DDRAW_INIT complete\n"); + ddraw_hwnd = h; + video_blit_memtoscreen = ddraw_fs_blit_memtoscreen; + video_blit_memtoscreen_8 = ddraw_fs_blit_memtoscreen_8; +} + +void ddraw_fs_close() +{ + if (lpdds_back2) + { + lpdds_back2->Release(); + lpdds_back2 = NULL; + } + if (lpdds_back) + { + lpdds_back->Release(); + lpdds_back = NULL; + } + if (lpdds_pri) + { + lpdds_pri->Release(); + lpdds_pri = NULL; + } + if (lpdd_clipper) + { + lpdd_clipper->Release(); + lpdd_clipper = NULL; + } + if (lpdd4) + { + lpdd4->Release(); + lpdd4 = NULL; + } +} + +static void ddraw_fs_size(RECT window_rect, RECT *r_dest, int w, int h) +{ + int ratio_w, ratio_h; + switch (video_fullscreen_scale) + { + case FULLSCR_SCALE_FULL: + r_dest->left = 0; + r_dest->top = 0; + r_dest->right = (window_rect.right - window_rect.left) - 1; + r_dest->bottom = (window_rect.bottom - window_rect.top) - 1; + break; + case FULLSCR_SCALE_43: + r_dest->top = 0; + r_dest->bottom = (window_rect.bottom - window_rect.top) - 1; + r_dest->left = ((window_rect.right - window_rect.left) / 2) - (((window_rect.bottom - window_rect.top) * 4) / (3 * 2)); + r_dest->right = ((window_rect.right - window_rect.left) / 2) + (((window_rect.bottom - window_rect.top) * 4) / (3 * 2)) - 1; + if (r_dest->left < 0) + { + r_dest->left = 0; + r_dest->right = (window_rect.right - window_rect.left) - 1; + r_dest->top = ((window_rect.bottom - window_rect.top) / 2) - (((window_rect.right - window_rect.left) * 3) / (4 * 2)); + r_dest->bottom = ((window_rect.bottom - window_rect.top) / 2) + (((window_rect.right - window_rect.left) * 3) / (4 * 2)) - 1; + } + break; + case FULLSCR_SCALE_SQ: + r_dest->top = 0; + r_dest->bottom = (window_rect.bottom - window_rect.top) - 1; + r_dest->left = ((window_rect.right - window_rect.left) / 2) - (((window_rect.bottom - window_rect.top) * w) / (h * 2)); + r_dest->right = ((window_rect.right - window_rect.left) / 2) + (((window_rect.bottom - window_rect.top) * w) / (h * 2)) - 1; + if (r_dest->left < 0) + { + r_dest->left = 0; + r_dest->right = (window_rect.right - window_rect.left) - 1; + r_dest->top = ((window_rect.bottom - window_rect.top) / 2) - (((window_rect.right - window_rect.left) * h) / (w * 2)); + r_dest->bottom = ((window_rect.bottom - window_rect.top) / 2) + (((window_rect.right - window_rect.left) * h) / (w * 2)) - 1; + } + break; + case FULLSCR_SCALE_INT: + ratio_w = (window_rect.right - window_rect.left) / w; + ratio_h = (window_rect.bottom - window_rect.top) / h; + if (ratio_h < ratio_w) + ratio_w = ratio_h; + r_dest->left = ((window_rect.right - window_rect.left) / 2) - ((w * ratio_w) / 2); + r_dest->right = ((window_rect.right - window_rect.left) / 2) + ((w * ratio_w) / 2) - 1; + r_dest->top = ((window_rect.bottom - window_rect.top) / 2) - ((h * ratio_w) / 2); + r_dest->bottom = ((window_rect.bottom - window_rect.top) / 2) + ((h * ratio_w) / 2) - 1; + break; + } +} + +static void ddraw_fs_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) +{ + RECT r_src; + RECT r_dest; + RECT window_rect; + int yy; + HRESULT hr; + DDBLTFX ddbltfx; + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + hr = lpdds_back->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_back->Restore(); + lpdds_back->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + device_force_redraw(); + } + if (!ddsd.lpSurface) return; + for (yy = y1; yy < y2; yy++) + { + if ((y + yy) >= 0) memcpy((unsigned char*)ddsd.lpSurface + (yy * ddsd.lPitch), &(((uint32_t *)buffer32->line[y + yy])[x]), w * 4); + } + lpdds_back->Unlock(NULL); + + window_rect.left = 0; + window_rect.top = 0; + window_rect.right = ddraw_w; + window_rect.bottom = ddraw_h; + ddraw_fs_size(window_rect, &r_dest, w, h); + + r_src.left = 0; + r_src.top = 0; + r_src.right = w; + r_src.bottom = h; + + ddbltfx.dwSize = sizeof(ddbltfx); + ddbltfx.dwFillColor = 0; + + lpdds_back2->Blt(&window_rect, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx); + + hr = lpdds_back2->Blt(&r_dest, lpdds_back, &r_src, DDBLT_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_back2->Restore(); + lpdds_back2->Blt(&r_dest, lpdds_back, &r_src, DDBLT_WAIT, NULL); + } + + if (readflash && enable_flash) + { + RECT r; + r.left = window_rect.right - 40; + r.right = window_rect.right - 8; + r.top = 8; + r.bottom = 14; + ddbltfx.dwFillColor = 0xffffff; + lpdds_back2->Blt(&r, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx); + } + + hr = lpdds_pri->Flip(NULL, DDFLIP_NOVSYNC); + if (hr == DDERR_SURFACELOST) + { + lpdds_pri->Restore(); + lpdds_pri->Flip(NULL, DDFLIP_NOVSYNC); + } +} + +static void ddraw_fs_blit_memtoscreen_8(int x, int y, int w, int h) +{ + RECT r_src; + RECT r_dest; + RECT window_rect; + int xx, yy; + HRESULT hr; + DDBLTFX ddbltfx; + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + hr = lpdds_back->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + + if (hr == DDERR_SURFACELOST) + { + lpdds_back->Restore(); + lpdds_back->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + device_force_redraw(); + } + if (!ddsd.lpSurface) return; + for (yy = 0; yy < h; yy++) + { + if ((y + yy) >= 0 && (y + yy) < buffer->h) + { + uint32_t *p = (uint32_t *)(ddsd.lpSurface + (yy * ddsd.lPitch)); + for (xx = 0; xx < w; xx++) + { + p[xx] = pal_lookup[buffer->line[y + yy][x + xx]]; + /* If brown circuity is disabled, double the green component. */ + if ((buffer->line[y + yy][x + xx] == 0x16) && !cga_brown) p[xx] += (p[xx] & 0xff00); + } + } + } + lpdds_back->Unlock(NULL); + + window_rect.left = 0; + window_rect.top = 0; + window_rect.right = ddraw_w; + window_rect.bottom = ddraw_h; + ddraw_fs_size(window_rect, &r_dest, w, h); + + r_src.left = 0; + r_src.top = 0; + r_src.right = w; + r_src.bottom = h; + + ddbltfx.dwSize = sizeof(ddbltfx); + ddbltfx.dwFillColor = 0; + + lpdds_back2->Blt(&window_rect, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx); + + hr = lpdds_back2->Blt(&r_dest, lpdds_back, &r_src, DDBLT_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_back2->Restore(); + lpdds_back2->Blt(&r_dest, lpdds_back, &r_src, DDBLT_WAIT, NULL); + } + + if (readflash && enable_flash) + { + RECT r; + r.left = window_rect.right - 40; + r.right = window_rect.right - 8; + r.top = 8; + r.bottom = 14; + ddbltfx.dwFillColor = 0xffffff; + lpdds_back2->Blt(&r, NULL, NULL, DDBLT_WAIT | DDBLT_COLORFILL, &ddbltfx); + } + + lpdds_pri->Flip(NULL, DDFLIP_NOVSYNC); +} + +void ddraw_fs_take_screenshot(char *fn) +{ + ddraw_common_take_screenshot(fn, lpdds_back2); +} diff --git a/src/win-ddraw-fs.h b/src/win-ddraw-fs.h new file mode 100644 index 000000000..89a863e1f --- /dev/null +++ b/src/win-ddraw-fs.h @@ -0,0 +1,8 @@ +#ifdef __cplusplus +extern "C" { +#endif + void ddraw_fs_init(HWND h); + void ddraw_fs_close(); +#ifdef __cplusplus +} +#endif diff --git a/src/win-ddraw-screenshot.cc b/src/win-ddraw-screenshot.cc new file mode 100644 index 000000000..c397ee862 --- /dev/null +++ b/src/win-ddraw-screenshot.cc @@ -0,0 +1,169 @@ +#include +#include +#define BITMAP WINDOWS_BITMAP +#include +#undef BITMAP +#include "win-ddraw-screenshot.h" +#include "video.h" + +extern "C" void fatal(const char *format, ...); +extern "C" void pclog(const char *format, ...); + +extern "C" void device_force_redraw(); + +extern "C" void ddraw_init(HWND h); +extern "C" void ddraw_close(); + +HBITMAP hbitmap; + +int xs, ys, ys2; + +void CopySurface(IDirectDrawSurface4 *pDDSurface) +{ + HDC hdc, hmemdc; + + HBITMAP hprevbitmap; + + DDSURFACEDESC2 ddsd2; + + pDDSurface->GetDC(&hdc); + + hmemdc = CreateCompatibleDC(hdc); + + ZeroMemory(&ddsd2 ,sizeof( ddsd2 )); // better to clear before using + + ddsd2.dwSize = sizeof( ddsd2 ); //initialize with size + + pDDSurface->GetSurfaceDesc(&ddsd2); + + hbitmap = CreateCompatibleBitmap( hdc ,xs ,ys); + + hprevbitmap = (HBITMAP) SelectObject( hmemdc, hbitmap ); + + BitBlt(hmemdc,0 ,0 ,xs ,ys ,hdc ,0 ,0,SRCCOPY); + + SelectObject(hmemdc,hprevbitmap); // restore the old bitmap + + DeleteDC(hmemdc); + + pDDSurface->ReleaseDC(hdc); + + return ; +} + +void DoubleLines(uint8_t *dst, uint8_t *src) +{ + int i = 0; + uint8_t temp_buf[8320]; + for (i = 0; i < ys; i++) + { + memcpy(dst + (i * xs * 8), src + (i * xs * 4), xs * 4); + memcpy(dst + ((i * xs * 8) + (xs * 4)), src + (i * xs * 4), xs * 4); + } +} + +void SaveBitmap(char *szFilename,HBITMAP hBitmap) +{ + HDC hdc=NULL; + FILE* fp=NULL; + LPVOID pBuf=NULL; + LPVOID pBuf2=NULL; + BITMAPINFO bmpInfo; + BITMAPFILEHEADER bmpFileHeader; + + do{ + + hdc=GetDC(NULL); + + ZeroMemory(&bmpInfo,sizeof(BITMAPINFO)); + + bmpInfo.bmiHeader.biSize=sizeof(BITMAPINFOHEADER); + + GetDIBits(hdc,hBitmap,0,0,NULL,&bmpInfo,DIB_RGB_COLORS); + + if(bmpInfo.bmiHeader.biSizeImage<=0) + bmpInfo.bmiHeader.biSizeImage=bmpInfo.bmiHeader.biWidth*abs(bmpInfo.bmiHeader.biHeight)*(bmpInfo.bmiHeader.biBitCount+7)/8; + + if((pBuf = malloc(bmpInfo.bmiHeader.biSizeImage))==NULL) + { + // pclog("ERROR: Unable to Allocate Bitmap Memory"); + break; + } + + if (ys2 <= 250) + { + pBuf2 = malloc(bmpInfo.bmiHeader.biSizeImage * 2); + } + + bmpInfo.bmiHeader.biCompression=BI_RGB; + + GetDIBits(hdc,hBitmap,0,bmpInfo.bmiHeader.biHeight,pBuf, &bmpInfo, DIB_RGB_COLORS); + + if((fp = fopen(szFilename,"wb"))==NULL) + { + MessageBox( NULL, "Unable to Create Bitmap File", "Error", MB_OK|MB_ICONERROR); + break; + } + + bmpFileHeader.bfReserved1=0; + + bmpFileHeader.bfReserved2=0; + + if (pBuf2) + { + bmpInfo.bmiHeader.biSizeImage <<= 1; + bmpInfo.bmiHeader.biHeight <<= 1; + } + + bmpFileHeader.bfSize=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER)+bmpInfo.bmiHeader.biSizeImage; + + bmpFileHeader.bfType='MB'; + + bmpFileHeader.bfOffBits=sizeof(BITMAPFILEHEADER)+sizeof(BITMAPINFOHEADER); + + fwrite(&bmpFileHeader,sizeof(BITMAPFILEHEADER),1,fp); + + fwrite(&bmpInfo.bmiHeader,sizeof(BITMAPINFOHEADER),1,fp); + + if (pBuf2) + { + DoubleLines((uint8_t *) pBuf2, (uint8_t *) pBuf); + fwrite(pBuf2,bmpInfo.bmiHeader.biSizeImage,1,fp); + } + else + { + fwrite(pBuf,bmpInfo.bmiHeader.biSizeImage,1,fp); + } + + }while(false); + + if(hdc) ReleaseDC(NULL,hdc); + + if(pBuf2) free(pBuf2); + + if(pBuf) free(pBuf); + + if(fp) fclose(fp); +} + +void ddraw_common_take_screenshot(char *fn, IDirectDrawSurface4 *pDDSurface) +{ + xs = xsize; + ys = ys2 = ysize; + /* For EGA/(S)VGA, the size is NOT adjusted for overscan. */ + if ((overscan_y > 16) && enable_overscan) + { + xs += overscan_x; + ys += overscan_y; + } + /* For CGA, the width is adjusted for overscan, but the height is not. */ + if (overscan_y == 16) + { + if (ys2 <= 250) + ys += (overscan_y >> 1); + else + ys += overscan_y; + } + CopySurface(pDDSurface); + SaveBitmap(fn, hbitmap); +} diff --git a/src/win-ddraw-screenshot.h b/src/win-ddraw-screenshot.h new file mode 100644 index 000000000..c493c4fb0 --- /dev/null +++ b/src/win-ddraw-screenshot.h @@ -0,0 +1 @@ +void ddraw_common_take_screenshot(char *fn, IDirectDrawSurface4 *pDDSurface); diff --git a/src/win-ddraw.cc b/src/win-ddraw.cc new file mode 100644 index 000000000..d449f42fa --- /dev/null +++ b/src/win-ddraw.cc @@ -0,0 +1,315 @@ +#include +#include +#define BITMAP WINDOWS_BITMAP +#include +#undef BITMAP +#include "win-ddraw.h" +#include "win-ddraw-screenshot.h" +#include "video.h" + +extern "C" void fatal(const char *format, ...); +extern "C" void pclog(const char *format, ...); + +extern "C" void device_force_redraw(); + +extern "C" void ddraw_init(HWND h); +extern "C" void ddraw_close(); + +static void ddraw_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h); +static void ddraw_blit_memtoscreen_8(int x, int y, int w, int h); + +static LPDIRECTDRAW lpdd = NULL; +static LPDIRECTDRAW4 lpdd4 = NULL; +static LPDIRECTDRAWSURFACE4 lpdds_pri = NULL; +static LPDIRECTDRAWSURFACE4 lpdds_back = NULL; +static LPDIRECTDRAWSURFACE4 lpdds_back2 = NULL; +static LPDIRECTDRAWCLIPPER lpdd_clipper = NULL; +static DDSURFACEDESC2 ddsd; + +static HWND ddraw_hwnd; + +static PALETTE cgapal= +{ + {0,0,0},{0,42,0},{42,0,0},{42,21,0}, + {0,0,0},{0,42,42},{42,0,42},{42,42,42}, + {0,0,0},{21,63,21},{63,21,21},{63,63,21}, + {0,0,0},{21,63,63},{63,21,63},{63,63,63}, + + {0,0,0},{0,0,42},{0,42,0},{0,42,42}, + {42,0,0},{42,0,42},{42,21,00},{42,42,42}, + {21,21,21},{21,21,63},{21,63,21},{21,63,63}, + {63,21,21},{63,21,63},{63,63,21},{63,63,63}, + + {0,0,0},{0,21,0},{0,0,42},{0,42,42}, + {42,0,21},{21,10,21},{42,0,42},{42,0,63}, + {21,21,21},{21,63,21},{42,21,42},{21,63,63}, + {63,0,0},{42,42,0},{63,21,42},{41,41,41}, + + {0,0,0},{0,42,42},{42,0,0},{42,42,42}, + {0,0,0},{0,42,42},{42,0,0},{42,42,42}, + {0,0,0},{0,63,63},{63,0,0},{63,63,63}, + {0,0,0},{0,63,63},{63,0,0},{63,63,63}, +}; + +static uint32_t pal_lookup[256]; + +void ddraw_init(HWND h) +{ + int c; + + for (c = 0; c < 256; c++) + pal_lookup[c] = makecol(cgapal[c].r << 2, cgapal[c].g << 2, cgapal[c].b << 2); + + if (FAILED(DirectDrawCreate(NULL, &lpdd, NULL))) + fatal("DirectDrawCreate failed\n"); + + if (FAILED(lpdd->QueryInterface(IID_IDirectDraw4, (LPVOID *)&lpdd4))) + fatal("QueryInterface failed\n"); + + lpdd->Release(); + lpdd = NULL; + + atexit(ddraw_close); + + if (FAILED(lpdd4->SetCooperativeLevel(h, DDSCL_NORMAL))) + fatal("SetCooperativeLevel failed\n"); + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + ddsd.dwFlags = DDSD_CAPS; + ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; + if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_pri, NULL))) + fatal("CreateSurface failed\n"); + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + ddsd.dwWidth = 2080; + ddsd.dwHeight = 2080; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; + if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_back, NULL))) + fatal("CreateSurface back failed\n"); + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + ddsd.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT; + ddsd.dwWidth = 2080; + ddsd.dwHeight = 2080; + ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_VIDEOMEMORY; + if (FAILED(lpdd4->CreateSurface(&ddsd, &lpdds_back2, NULL))) + fatal("CreateSurface back failed\n"); + + if (FAILED(lpdd4->CreateClipper(0, &lpdd_clipper, NULL))) + fatal("CreateClipper failed\n"); + if (FAILED(lpdd_clipper->SetHWnd(0, h))) + fatal("SetHWnd failed\n"); + if (FAILED(lpdds_pri->SetClipper(lpdd_clipper))) + fatal("SetClipper failed\n"); + + pclog("DDRAW_INIT complete\n"); + ddraw_hwnd = h; + video_blit_memtoscreen = ddraw_blit_memtoscreen; + video_blit_memtoscreen_8 = ddraw_blit_memtoscreen_8; +} + +void ddraw_close() +{ + if (lpdds_back2) + { + lpdds_back2->Release(); + lpdds_back2 = NULL; + } + if (lpdds_back) + { + lpdds_back->Release(); + lpdds_back = NULL; + } + if (lpdds_pri) + { + lpdds_pri->Release(); + lpdds_pri = NULL; + } + if (lpdd_clipper) + { + lpdd_clipper->Release(); + lpdd_clipper = NULL; + } + if (lpdd4) + { + lpdd4->Release(); + lpdd4 = NULL; + } +} + +static void ddraw_blit_memtoscreen(int x, int y, int y1, int y2, int w, int h) +{ + RECT r_src; + RECT r_dest; + int xx, yy; + POINT po; + uint32_t *p; + HRESULT hr; + +// pclog("Blit memtoscreen %i,%i %i %i %i,%i\n", x, y, y1, y2, w, h); + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + hr = lpdds_back->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_back->Restore(); + lpdds_back->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + device_force_redraw(); + } + if (!ddsd.lpSurface) return; + for (yy = y1; yy < y2; yy++) + { + if ((y + yy) >= 0 && (y + yy) < buffer->h) + memcpy(ddsd.lpSurface + (yy * ddsd.lPitch), &(((uint32_t *)buffer32->line[y + yy])[x]), w * 4); + } + lpdds_back->Unlock(NULL); + + po.x = po.y = 0; + + ClientToScreen(ddraw_hwnd, &po); + GetClientRect(ddraw_hwnd, &r_dest); + OffsetRect(&r_dest, po.x, po.y); + + r_src.left = 0; + r_src.top = 0; + r_src.right = w; + r_src.bottom = h; + + hr = lpdds_back2->Blt(&r_src, lpdds_back, &r_src, DDBLT_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_back2->Restore(); + lpdds_back2->Blt(&r_src, lpdds_back, &r_src, DDBLT_WAIT, NULL); + } + + if (readflash) + { + readflash = 0; + if (enable_flash) + { + hr = lpdds_back2->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_back2->Restore(); + lpdds_back2->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + device_force_redraw(); + } + if (!ddsd.lpSurface) return; + for (yy = 8; yy < 14; yy++) + { + p = (uint32_t *)(ddsd.lpSurface + (yy * ddsd.lPitch)); + for (xx = (w - 40); xx < (w - 8); xx++) + p[xx] = 0xffffffff; + } + } + } + lpdds_back2->Unlock(NULL); + +// pclog("Blit from %i,%i %i,%i to %i,%i %i,%i\n", r_src.left, r_src.top, r_src.right, r_src.bottom, r_dest.left, r_dest.top, r_dest.right, r_dest.bottom); + hr = lpdds_pri->Blt(&r_dest, lpdds_back2, &r_src, DDBLT_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_pri->Restore(); + lpdds_pri->Blt(&r_dest, lpdds_back2, &r_src, DDBLT_WAIT, NULL); + } +} + +static void ddraw_blit_memtoscreen_8(int x, int y, int w, int h) +{ + RECT r_src; + RECT r_dest; + int xx, yy; + POINT po; + uint32_t *p; + HRESULT hr; + + memset(&ddsd, 0, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + + hr = lpdds_back->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + + if (hr == DDERR_SURFACELOST) + { + lpdds_back->Restore(); + lpdds_back->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + device_force_redraw(); + } + if (!ddsd.lpSurface) return; + for (yy = 0; yy < h; yy++) + { + if ((y + yy) >= 0 && (y + yy) < buffer->h) + { + p = (uint32_t *)(ddsd.lpSurface + (yy * ddsd.lPitch)); + for (xx = 0; xx < w; xx++) + { + p[xx] = pal_lookup[buffer->line[y + yy][x + xx]]; + /* If brown circuity is disabled, double the green component. */ + if ((buffer->line[y + yy][x + xx] == 0x16) && !cga_brown) p[xx] += (p[xx] & 0xff00); + } + } + } + p = (uint32_t *)(ddsd.lpSurface + (4 * ddsd.lPitch)); + lpdds_back->Unlock(NULL); + + po.x = po.y = 0; + + ClientToScreen(ddraw_hwnd, &po); + GetClientRect(ddraw_hwnd, &r_dest); + OffsetRect(&r_dest, po.x, po.y); + + r_src.left = 0; + r_src.top = 0; + r_src.right = w; + r_src.bottom = h; + + hr = lpdds_back2->Blt(&r_src, lpdds_back, &r_src, DDBLT_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_back2->Restore(); + lpdds_back2->Blt(&r_src, lpdds_back, &r_src, DDBLT_WAIT, NULL); + } + + if (readflash) + { + readflash = 0; + if (enable_flash) + { + hr = lpdds_back2->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_back2->Restore(); + lpdds_back2->Lock(NULL, &ddsd, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, NULL); + device_force_redraw(); + } + if (!ddsd.lpSurface) return; + for (yy = 8; yy < 14; yy++) + { + p = (uint32_t *)(ddsd.lpSurface + (yy * ddsd.lPitch)); + for (xx = (w - 40); xx < (w - 8); xx++) + p[xx] = 0xffffffff; + } + lpdds_back2->Unlock(NULL); + } + } + + hr = lpdds_pri->Blt(&r_dest, lpdds_back2, &r_src, DDBLT_WAIT, NULL); + if (hr == DDERR_SURFACELOST) + { + lpdds_pri->Restore(); + hr = lpdds_pri->Blt(&r_dest, lpdds_back2, &r_src, DDBLT_WAIT, NULL); + } +} + +void ddraw_take_screenshot(char *fn) +{ + ddraw_common_take_screenshot(fn, lpdds_back2); +} diff --git a/src/win-ddraw.h b/src/win-ddraw.h new file mode 100644 index 000000000..3d3ecb39a --- /dev/null +++ b/src/win-ddraw.h @@ -0,0 +1,9 @@ +#ifdef __cplusplus +extern "C" { +#endif + void ddraw_init(HWND h); + void ddraw_close(); +#ifdef __cplusplus +} +#endif + diff --git a/src/win-deviceconfig.c b/src/win-deviceconfig.c new file mode 100644 index 000000000..ede50e060 --- /dev/null +++ b/src/win-deviceconfig.c @@ -0,0 +1,354 @@ +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP + +#include "ibm.h" +#include "config.h" +#include "device.h" +#include "resources.h" +#include "win.h" + +static device_t *config_device; + +static BOOL CALLBACK deviceconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + { + int id = IDC_CONFIG_BASE; + device_config_t *config = config_device->config; + int c; + + while (config->type != -1) + { + device_config_selection_t *selection = config->selection; + HWND h = GetDlgItem(hdlg, id); + int val_int; + char *val_string; + int num; + char s[80]; + + switch (config->type) + { + case CONFIG_BINARY: + val_int = config_get_int(config_device->name, config->name, config->default_int); + + SendMessage(h, BM_SETCHECK, val_int, 0); + + id++; + break; + + case CONFIG_SELECTION: + val_int = config_get_int(config_device->name, config->name, config->default_int); + + c = 0; + while (selection->description[0]) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)selection->description); + if (val_int == selection->value) + SendMessage(h, CB_SETCURSEL, c, 0); + selection++; + c++; + } + + id += 2; + break; + + case CONFIG_MIDI: + val_int = config_get_int(NULL, config->name, config->default_int); + + num = midi_get_num_devs(); + for (c = 0; c < num; c++) + { + midi_get_dev_name(c, s); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); + if (val_int == c) + SendMessage(h, CB_SETCURSEL, c, 0); + } + + id += 2; + break; + } + config++; + } + } + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + { + int id = IDC_CONFIG_BASE; + device_config_t *config = config_device->config; + int c; + int changed = 0; + + while (config->type != -1) + { + device_config_selection_t *selection = config->selection; + HWND h = GetDlgItem(hdlg, id); + int val_int; + char *val_string; + + switch (config->type) + { + case CONFIG_BINARY: + val_int = config_get_int(config_device->name, config->name, config->default_int); + + if (val_int != SendMessage(h, BM_GETCHECK, 0, 0)) + changed = 1; + + id++; + break; + + case CONFIG_SELECTION: + val_int = config_get_int(config_device->name, config->name, config->default_int); + + c = SendMessage(h, CB_GETCURSEL, 0, 0); + + for (; c > 0; c--) + selection++; + + if (val_int != selection->value) + changed = 1; + + id += 2; + break; + + case CONFIG_MIDI: + val_int = config_get_int(NULL, config->name, config->default_int); + + c = SendMessage(h, CB_GETCURSEL, 0, 0); + + if (val_int != c) + changed = 1; + + id += 2; + break; + } + config++; + } + + if (!changed) + { + EndDialog(hdlg, 0); + return TRUE; + } + + if (MessageBox(NULL, "This will reset PCem!\nOkay to continue?", "PCem", MB_OKCANCEL) != IDOK) + { + EndDialog(hdlg, 0); + return TRUE; + } + + id = IDC_CONFIG_BASE; + config = config_device->config; + + while (config->type != -1) + { + device_config_selection_t *selection = config->selection; + HWND h = GetDlgItem(hdlg, id); + int val_int; + char *val_string; + + switch (config->type) + { + case CONFIG_BINARY: + config_set_int(config_device->name, config->name, SendMessage(h, BM_GETCHECK, 0, 0)); + + id++; + break; + + case CONFIG_SELECTION: + c = SendMessage(h, CB_GETCURSEL, 0, 0); + for (; c > 0; c--) + selection++; + config_set_int(config_device->name, config->name, selection->value); + + id += 2; + break; + + case CONFIG_MIDI: + c = SendMessage(h, CB_GETCURSEL, 0, 0); + config_set_int(NULL, config->name, c); + + id += 2; + break; + } + config++; + } + + saveconfig(); + + resetpchard(); + + EndDialog(hdlg, 0); + return TRUE; + } + case IDCANCEL: + EndDialog(hdlg, 0); + return TRUE; + } + break; + } + return FALSE; +} + +void deviceconfig_open(HWND hwnd, device_t *device) +{ + device_config_t *config = device->config; + uint16_t *data_block = malloc(16384); + uint16_t *data; + DLGTEMPLATE *dlg = (DLGTEMPLATE *)data_block; + DLGITEMTEMPLATE *item; + int y = 10; + int id = IDC_CONFIG_BASE; + + memset(data_block, 0, 4096); + + dlg->style = DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU; + dlg->x = 10; + dlg->y = 10; + dlg->cx = 220; + dlg->cy = 70; + + data = (uint16_t *)(dlg + 1); + + *data++ = 0; /*no menu*/ + *data++ = 0; /*predefined dialog box class*/ + data += MultiByteToWideChar(CP_ACP, 0, "Device Configuration", -1, data, 50); + + *data++ = 8; /*Point*/ + data += MultiByteToWideChar(CP_ACP, 0, "MS Sans Serif", -1, data, 50); + + if (((unsigned long)data) & 2) + data++; + + while (config->type != -1) + { + switch (config->type) + { + case CONFIG_BINARY: + item = (DLGITEMTEMPLATE *)data; + item->x = 10; + item->y = y; + item->id = id++; + + item->cx = 80; + item->cy = 15; + + item->style = WS_CHILD | WS_VISIBLE | BS_AUTOCHECKBOX; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0080; // button class + + data += MultiByteToWideChar(CP_ACP, 0, config->description, -1, data, 256); + *data++ = 0; // no creation data + + y += 20; + break; + + case CONFIG_SELECTION: + case CONFIG_MIDI: + /*Combo box*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 70; + item->y = y; + item->id = id++; + + item->cx = 140; + item->cy = 150; + + item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0085; // combo box class + + data += MultiByteToWideChar(CP_ACP, 0, config->description, -1, data, 256); + *data++ = 0; // no creation data + + if (((unsigned long)data) & 2) + data++; + + /*Static text*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 10; + item->y = y; + item->id = id++; + + item->cx = 60; + item->cy = 15; + + item->style = WS_CHILD | WS_VISIBLE; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0082; // static class + + data += MultiByteToWideChar(CP_ACP, 0, config->description, -1, data, 256); + *data++ = 0; // no creation data + + if (((unsigned long)data) & 2) + data++; + + y += 20; + break; + } + + if (((unsigned long)data) & 2) + data++; + + config++; + } + + dlg->cdit = (id - IDC_CONFIG_BASE) + 2; + +// DEFPUSHBUTTON "OK",IDOK,64,232,50,14, WS_TABSTOP +// PUSHBUTTON "Cancel",IDCANCEL,128,232,50,14, WS_TABSTOP + + item = (DLGITEMTEMPLATE *)data; + item->x = 20; + item->y = y; + item->cx = 50; + item->cy = 14; + item->id = IDOK; // OK button identifier + item->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0080; // button class + + data += MultiByteToWideChar(CP_ACP, 0, "OK", -1, data, 50); + *data++ = 0; // no creation data + + if (((unsigned long)data) & 2) + data++; + + item = (DLGITEMTEMPLATE *)data; + item->x = 80; + item->y = y; + item->cx = 50; + item->cy = 14; + item->id = IDCANCEL; // OK button identifier + item->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0080; // button class + + data += MultiByteToWideChar(CP_ACP, 0, "Cancel", -1, data, 50); + *data++ = 0; // no creation data + + dlg->cy = y + 20; + + config_device = device; + + DialogBoxIndirect(hinstance, dlg, hwnd, deviceconfig_dlgproc); + + free(data_block); +} diff --git a/src/win-hdconf.c b/src/win-hdconf.c new file mode 100644 index 000000000..c0c288ba0 --- /dev/null +++ b/src/win-hdconf.c @@ -0,0 +1,809 @@ +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP + +#include "ibm.h" +#include "ide.h" +#include "resources.h" +#include "win.h" + +static int hd_changed = 0; + +static char hd_new_name[512]; +static int hd_new_spt, hd_new_hpc, hd_new_cyl; +static int new_cdrom_channel; + +static void update_hdd_cdrom(HWND hdlg) +{ + HWND h; + + h = GetDlgItem(hdlg, IDC_CHDD); + SendMessage(h, BM_SETCHECK, (new_cdrom_channel == 0) ? 0 : 1, 0); + h = GetDlgItem(hdlg, IDC_CCDROM); + SendMessage(h, BM_SETCHECK, (new_cdrom_channel == 0) ? 1 : 0, 0); + h = GetDlgItem(hdlg, IDC_DHDD); + SendMessage(h, BM_SETCHECK, (new_cdrom_channel == 1) ? 0 : 1, 0); + h = GetDlgItem(hdlg, IDC_DCDROM); + SendMessage(h, BM_SETCHECK, (new_cdrom_channel == 1) ? 1 : 0, 0); + h = GetDlgItem(hdlg, IDC_EHDD); + SendMessage(h, BM_SETCHECK, (new_cdrom_channel == 2) ? 0 : 1, 0); + h = GetDlgItem(hdlg, IDC_ECDROM); + SendMessage(h, BM_SETCHECK, (new_cdrom_channel == 2) ? 1 : 0, 0); + h = GetDlgItem(hdlg, IDC_FHDD); + SendMessage(h, BM_SETCHECK, (new_cdrom_channel == 3) ? 0 : 1, 0); + h = GetDlgItem(hdlg, IDC_FCDROM); + SendMessage(h, BM_SETCHECK, (new_cdrom_channel == 3) ? 1 : 0, 0); + h = GetDlgItem(hdlg, IDC_GCDROM); + SendMessage(h, BM_SETCHECK, (new_cdrom_channel == 4) ? 1 : 0, 0); + h = GetDlgItem(hdlg, IDC_HCDROM); + SendMessage(h, BM_SETCHECK, (new_cdrom_channel == 5) ? 1 : 0, 0); +} + +static BOOL CALLBACK hdnew_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + char s[260]; + HWND h; + int c; + PcemHDC hd[4]; + FILE *f; + uint8_t buf[512]; + switch (message) + { + case WM_INITDIALOG: + h = GetDlgItem(hdlg, IDC_EDIT1); + sprintf(s, "%i", 63); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT2); + sprintf(s, "%i", 16); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT3); + sprintf(s, "%i", 511); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + h = GetDlgItem(hdlg, IDC_EDITC); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)""); + + h = GetDlgItem(hdlg, IDC_TEXT1); + sprintf(s, "Size : %imb", (((511*16*63)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + return TRUE; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + h = GetDlgItem(hdlg, IDC_EDITC); + SendMessage(h, WM_GETTEXT, 511, (LPARAM)hd_new_name); + if (!hd_new_name[0]) + { + MessageBox(ghwnd,"Please enter a valid filename","PCem error",MB_OK); + return TRUE; + } + h = GetDlgItem(hdlg, IDC_EDIT1); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd_new_spt); + h = GetDlgItem(hdlg, IDC_EDIT2); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd_new_hpc); + h = GetDlgItem(hdlg, IDC_EDIT3); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd_new_cyl); + + if (hd_new_spt > 63) + { + MessageBox(ghwnd, "Drive has too many sectors (maximum is 63)", "PCem error", MB_OK); + return TRUE; + } + if (hd_new_hpc > 16) + { + MessageBox(ghwnd, "Drive has too many heads (maximum is 16)", "PCem error", MB_OK); + return TRUE; + } + if (hd_new_cyl > 16383) + { + MessageBox(ghwnd, "Drive has too many cylinders (maximum is 16383)", "PCem error", MB_OK); + return TRUE; + } + + f = fopen64(hd_new_name, "wb"); + if (!f) + { + MessageBox(ghwnd, "Can't open file for write", "PCem error", MB_OK); + return TRUE; + } + memset(buf, 0, 512); + for (c = 0; c < (hd_new_cyl * hd_new_hpc * hd_new_spt); c++) + fwrite(buf, 512, 1, f); + fclose(f); + + MessageBox(ghwnd, "Remember to partition and format the new drive", "PCem", MB_OK); + + EndDialog(hdlg, 1); + return TRUE; + case IDCANCEL: + EndDialog(hdlg, 0); + return TRUE; + + case IDC_CFILE: + if (!getsfile(hdlg, "Hard disc image (*.IMG)\0*.IMG\0All files (*.*)\0*.*\0", "")) + { + h = GetDlgItem(hdlg, IDC_EDITC); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)openfilestring); + } + return TRUE; + + case IDC_EDIT1: case IDC_EDIT2: case IDC_EDIT3: + h = GetDlgItem(hdlg, IDC_EDIT1); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[0].spt); + h = GetDlgItem(hdlg, IDC_EDIT2); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[0].hpc); + h = GetDlgItem(hdlg, IDC_EDIT3); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[0].tracks); + + h = GetDlgItem(hdlg, IDC_TEXT1); + sprintf(s, "Size : %imb", (((((uint64_t)hd[0].tracks*(uint64_t)hd[0].hpc)*(uint64_t)hd[0].spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + return TRUE; + } + break; + + } + return FALSE; +} + +BOOL CALLBACK hdsize_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + char s[260]; + HWND h; + PcemHDC hd[2]; + switch (message) + { + case WM_INITDIALOG: + h = GetDlgItem(hdlg, IDC_EDIT1); + sprintf(s, "%i", hd_new_spt); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT2); + sprintf(s, "%i", hd_new_hpc); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT3); + sprintf(s, "%i", hd_new_cyl); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + h = GetDlgItem(hdlg, IDC_TEXT1); + sprintf(s, "Size : %imb", ((((uint64_t)hd_new_spt*(uint64_t)hd_new_hpc*(uint64_t)hd_new_cyl)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + return TRUE; + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + h = GetDlgItem(hdlg, IDC_EDIT1); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd_new_spt); + h = GetDlgItem(hdlg, IDC_EDIT2); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd_new_hpc); + h = GetDlgItem(hdlg, IDC_EDIT3); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd_new_cyl); + + if (hd_new_spt > 63) + { + MessageBox(ghwnd,"Drive has too many sectors (maximum is 63)","PCem error",MB_OK); + return TRUE; + } + if (hd_new_hpc > 16) + { + MessageBox(ghwnd,"Drive has too many heads (maximum is 16)","PCem error",MB_OK); + return TRUE; + } + if (hd_new_cyl > 16383) + { + MessageBox(ghwnd,"Drive has too many cylinders (maximum is 16383)","PCem error",MB_OK); + return TRUE; + } + + EndDialog(hdlg,1); + return TRUE; + case IDCANCEL: + EndDialog(hdlg,0); + return TRUE; + + case IDC_EDIT1: case IDC_EDIT2: case IDC_EDIT3: + h = GetDlgItem(hdlg, IDC_EDIT1); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[0].spt); + h = GetDlgItem(hdlg, IDC_EDIT2); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[0].hpc); + h = GetDlgItem(hdlg, IDC_EDIT3); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[0].tracks); + + h = GetDlgItem(hdlg, IDC_TEXT1); + sprintf(s, "Size : %imb", (((((uint64_t)hd[0].tracks*(uint64_t)hd[0].hpc)*(uint64_t)hd[0].spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + return TRUE; + } + break; + + } + return FALSE; +} + +static BOOL CALLBACK hdconf_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + char s[260]; + HWND h; + PcemHDC hd[4]; + FILE *f; + off64_t sz; + switch (message) + { + case WM_INITDIALOG: + pause = 1; + hd[0] = hdc[0]; + hd[1] = hdc[1]; + hd[2] = hdc[2]; + hd[3] = hdc[3]; + hd_changed = 0; + + h = GetDlgItem(hdlg, IDC_EDIT_C_SPT); + sprintf(s, "%i", hdc[0].spt); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_C_HPC); + sprintf(s, "%i", hdc[0].hpc); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_C_CYL); + sprintf(s, "%i", hdc[0].tracks); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_C_FN); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)ide_fn[0]); + + h = GetDlgItem(hdlg, IDC_EDIT_D_SPT); + sprintf(s, "%i", hdc[1].spt); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_D_HPC); + sprintf(s, "%i", hdc[1].hpc); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_D_CYL); + sprintf(s, "%i", hdc[1].tracks); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h= GetDlgItem(hdlg, IDC_EDIT_D_FN); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)ide_fn[1]); + + h = GetDlgItem(hdlg, IDC_EDIT_E_SPT); + sprintf(s, "%i", hdc[2].spt); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_E_HPC); + sprintf(s, "%i", hdc[2].hpc); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_E_CYL); + sprintf(s, "%i", hdc[2].tracks); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h= GetDlgItem(hdlg, IDC_EDIT_E_FN); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)ide_fn[2]); + + h = GetDlgItem(hdlg, IDC_EDIT_F_SPT); + sprintf(s, "%i", hdc[3].spt); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_F_HPC); + sprintf(s, "%i", hdc[3].hpc); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_F_CYL); + sprintf(s, "%i", hdc[3].tracks); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h= GetDlgItem(hdlg, IDC_EDIT_F_FN); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)ide_fn[3]); + + h = GetDlgItem(hdlg, IDC_TEXT_C_SIZE); + sprintf(s, "Size : %imb", (((((uint64_t)hd[0].tracks*(uint64_t)hd[0].hpc)*(uint64_t)hd[0].spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + h = GetDlgItem(hdlg, IDC_TEXT_D_SIZE); + sprintf(s, "Size : %imb", (((((uint64_t)hd[1].tracks*(uint64_t)hd[1].hpc)*(uint64_t)hd[1].spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + h = GetDlgItem(hdlg, IDC_TEXT_E_SIZE); + sprintf(s, "Size : %imb", (((((uint64_t)hd[2].tracks*(uint64_t)hd[2].hpc)*(uint64_t)hd[2].spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + h = GetDlgItem(hdlg, IDC_TEXT_F_SIZE); + sprintf(s, "Size : %imb", (((((uint64_t)hd[3].tracks*(uint64_t)hd[3].hpc)*(uint64_t)hd[3].spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + new_cdrom_channel = cdrom_channel; + + update_hdd_cdrom(hdlg); + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + if (hd_changed || cdrom_channel != new_cdrom_channel) + { + if (MessageBox(NULL, "This will reset PCem!\nOkay to continue?", "PCem", MB_OKCANCEL) == IDOK) + { + h = GetDlgItem(hdlg, IDC_EDIT_C_SPT); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[0].spt); + h = GetDlgItem(hdlg, IDC_EDIT_C_HPC); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[0].hpc); + h = GetDlgItem(hdlg, IDC_EDIT_C_CYL); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[0].tracks); + h = GetDlgItem(hdlg, IDC_EDIT_C_FN); + SendMessage(h, WM_GETTEXT, 511, (LPARAM)ide_fn[0]); + + h = GetDlgItem(hdlg, IDC_EDIT_D_SPT); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[1].spt); + h = GetDlgItem(hdlg, IDC_EDIT_D_HPC); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[1].hpc); + h = GetDlgItem(hdlg, IDC_EDIT_D_CYL); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[1].tracks); + h = GetDlgItem(hdlg, IDC_EDIT_D_FN); + SendMessage(h, WM_GETTEXT, 511, (LPARAM)ide_fn[1]); + + h = GetDlgItem(hdlg, IDC_EDIT_E_SPT); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[2].spt); + h = GetDlgItem(hdlg, IDC_EDIT_E_HPC); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[2].hpc); + h = GetDlgItem(hdlg, IDC_EDIT_E_CYL); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[2].tracks); + h = GetDlgItem(hdlg, IDC_EDIT_E_FN); + SendMessage(h, WM_GETTEXT, 511, (LPARAM)ide_fn[2]); + + h = GetDlgItem(hdlg, IDC_EDIT_F_SPT); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[3].spt); + h = GetDlgItem(hdlg, IDC_EDIT_F_HPC); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[3].hpc); + h = GetDlgItem(hdlg, IDC_EDIT_F_CYL); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[3].tracks); + h = GetDlgItem(hdlg, IDC_EDIT_F_FN); + SendMessage(h, WM_GETTEXT, 511, (LPARAM)ide_fn[3]); + + hdc[0] = hd[0]; + hdc[1] = hd[1]; + hdc[2] = hd[2]; + hdc[3] = hd[3]; + + cdrom_channel = new_cdrom_channel; + + saveconfig(); + + resetpchard(); + } + } + case IDCANCEL: + EndDialog(hdlg, 0); + pause = 0; + return TRUE; + + case IDC_EJECTC: + hd[0].spt = 0; + hd[0].hpc = 0; + hd[0].tracks = 0; + ide_fn[0][0] = 0; + SetDlgItemText(hdlg, IDC_EDIT_C_SPT, "0"); + SetDlgItemText(hdlg, IDC_EDIT_C_HPC, "0"); + SetDlgItemText(hdlg, IDC_EDIT_C_CYL, "0"); + SetDlgItemText(hdlg, IDC_EDIT_C_FN, ""); + hd_changed = 1; + return TRUE; + case IDC_EJECTD: + hd[1].spt = 0; + hd[1].hpc = 0; + hd[1].tracks = 0; + ide_fn[1][0] = 0; + SetDlgItemText(hdlg, IDC_EDIT_D_SPT, "0"); + SetDlgItemText(hdlg, IDC_EDIT_D_HPC, "0"); + SetDlgItemText(hdlg, IDC_EDIT_D_CYL, "0"); + SetDlgItemText(hdlg, IDC_EDIT_D_FN, ""); + hd_changed = 1; + return TRUE; + case IDC_EJECTE: + hd[2].spt = 0; + hd[2].hpc = 0; + hd[2].tracks = 0; + ide_fn[2][0] = 0; + SetDlgItemText(hdlg, IDC_EDIT_E_SPT, "0"); + SetDlgItemText(hdlg, IDC_EDIT_E_HPC, "0"); + SetDlgItemText(hdlg, IDC_EDIT_E_CYL, "0"); + SetDlgItemText(hdlg, IDC_EDIT_E_FN, ""); + hd_changed = 1; + return TRUE; + case IDC_EJECTF: + hd[3].spt = 0; + hd[3].hpc = 0; + hd[3].tracks = 0; + ide_fn[3][0] = 0; + SetDlgItemText(hdlg, IDC_EDIT_F_SPT, "0"); + SetDlgItemText(hdlg, IDC_EDIT_F_HPC, "0"); + SetDlgItemText(hdlg, IDC_EDIT_F_CYL, "0"); + SetDlgItemText(hdlg, IDC_EDIT_F_FN, ""); + hd_changed = 1; + return TRUE; + + case IDC_CNEW: + if (DialogBox(hinstance, TEXT("HdNewDlg"), hdlg, hdnew_dlgproc) == 1) + { + h = GetDlgItem(hdlg, IDC_EDIT_C_SPT); + sprintf(s, "%i", hd_new_spt); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_C_HPC); + sprintf(s, "%i", hd_new_hpc); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_C_CYL); + sprintf(s, "%i", hd_new_cyl); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_C_FN); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)hd_new_name); + + h = GetDlgItem(hdlg, IDC_TEXT_C_SIZE); + sprintf(s, "Size : %imb", (((((uint64_t)hd_new_cyl*(uint64_t)hd_new_hpc)*(uint64_t)hd_new_spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + hd_changed = 1; + } + return TRUE; + + case IDC_CFILE: + if (!getfile(hdlg, "Hard disc image (*.IMG)\0*.IMG\0All files (*.*)\0*.*\0", "")) + { + f = fopen64(openfilestring, "rb"); + if (!f) + { + MessageBox(ghwnd,"Can't open file for read","PCem error",MB_OK); + return TRUE; + } + fseeko64(f, -1, SEEK_END); + sz = ftello64(f) + 1; + fclose(f); + hd_new_spt = 63; + hd_new_hpc = 16; + hd_new_cyl = ((sz / 512) / 16) / 63; + + if (DialogBox(hinstance, TEXT("HdSizeDlg"), hdlg, hdsize_dlgproc) == 1) + { + h = GetDlgItem(hdlg, IDC_EDIT_C_SPT); + sprintf(s, "%i", hd_new_spt); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_C_HPC); + sprintf(s, "%i", hd_new_hpc); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_C_CYL); + sprintf(s, "%i", hd_new_cyl); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_C_FN); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)openfilestring); + + h= GetDlgItem(hdlg, IDC_TEXT_C_SIZE); + sprintf(s, "Size : %imb", (((((uint64_t)hd_new_cyl*(uint64_t)hd_new_hpc)*(uint64_t)hd_new_spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + hd_changed = 1; + } + } + return TRUE; + + case IDC_DNEW: + if (DialogBox(hinstance, TEXT("HdNewDlg"), hdlg, hdnew_dlgproc) == 1) + { + h = GetDlgItem(hdlg, IDC_EDIT_D_SPT); + sprintf(s, "%i", hd_new_spt); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_D_HPC); + sprintf(s, "%i", hd_new_hpc); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_D_CYL); + sprintf(s, "%i", hd_new_cyl); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_D_FN); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)hd_new_name); + + h= GetDlgItem(hdlg, IDC_TEXT_D_SIZE); + sprintf(s, "Size : %imb", (((((uint64_t)hd_new_cyl*(uint64_t)hd_new_hpc)*(uint64_t)hd_new_spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + hd_changed = 1; + } + return TRUE; + + case IDC_DFILE: + if (!getfile(hdlg, "Hard disc image (*.IMG)\0*.IMG\0All files (*.*)\0*.*\0", "")) + { + f = fopen64(openfilestring, "rb"); + if (!f) + { + MessageBox(ghwnd,"Can't open file for read","PCem error",MB_OK); + return TRUE; + } + fseeko64(f, -1, SEEK_END); + sz = ftello64(f) + 1; + fclose(f); + hd_new_spt = 63; + hd_new_hpc = 16; + hd_new_cyl = ((sz / 512) / 16) / 63; + + if (DialogBox(hinstance, TEXT("HdSizeDlg"), hdlg, hdsize_dlgproc) == 1) + { + h = GetDlgItem(hdlg, IDC_EDIT_D_SPT); + sprintf(s, "%i", hd_new_spt); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_D_HPC); + sprintf(s, "%i", hd_new_hpc); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_D_CYL); + sprintf(s, "%i", hd_new_cyl); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_D_FN); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)openfilestring); + + h = GetDlgItem(hdlg, IDC_TEXT_D_SIZE); + sprintf(s, "Size : %imb", (((((uint64_t)hd_new_cyl*(uint64_t)hd_new_hpc)*(uint64_t)hd_new_spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + hd_changed = 1; + } + } + return TRUE; + + case IDC_ENEW: + if (DialogBox(hinstance, TEXT("HdNewDlg"), hdlg, hdnew_dlgproc) == 1) + { + h = GetDlgItem(hdlg, IDC_EDIT_E_SPT); + sprintf(s, "%i", hd_new_spt); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_E_HPC); + sprintf(s, "%i", hd_new_hpc); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_E_CYL); + sprintf(s, "%i", hd_new_cyl); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_E_FN); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)hd_new_name); + + h= GetDlgItem(hdlg, IDC_TEXT_E_SIZE); + sprintf(s, "Size : %imb", (((((uint64_t)hd_new_cyl*(uint64_t)hd_new_hpc)*(uint64_t)hd_new_spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + hd_changed = 1; + } + return TRUE; + + case IDC_EFILE: + if (!getfile(hdlg, "Hard disc image (*.IMG)\0*.IMG\0All files (*.*)\0*.*\0", "")) + { + f = fopen64(openfilestring, "rb"); + if (!f) + { + MessageBox(ghwnd,"Can't open file for read","PCem error",MB_OK); + return TRUE; + } + fseeko64(f, -1, SEEK_END); + sz = ftello64(f) + 1; + fclose(f); + hd_new_spt = 63; + hd_new_hpc = 16; + hd_new_cyl = ((sz / 512) / 16) / 63; + + if (DialogBox(hinstance, TEXT("HdSizeDlg"), hdlg, hdsize_dlgproc) == 1) + { + h = GetDlgItem(hdlg, IDC_EDIT_E_SPT); + sprintf(s, "%i", hd_new_spt); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_E_HPC); + sprintf(s, "%i", hd_new_hpc); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_E_CYL); + sprintf(s, "%i", hd_new_cyl); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_E_FN); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)openfilestring); + + h = GetDlgItem(hdlg, IDC_TEXT_E_SIZE); + sprintf(s, "Size : %imb", (((((uint64_t)hd_new_cyl*(uint64_t)hd_new_hpc)*(uint64_t)hd_new_spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + hd_changed = 1; + } + } + return TRUE; + + case IDC_FNEW: + if (DialogBox(hinstance, TEXT("HdNewDlg"), hdlg, hdnew_dlgproc) == 1) + { + h = GetDlgItem(hdlg, IDC_EDIT_F_SPT); + sprintf(s, "%i", hd_new_spt); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_F_HPC); + sprintf(s, "%i", hd_new_hpc); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_F_CYL); + sprintf(s, "%i", hd_new_cyl); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_F_FN); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)hd_new_name); + + h= GetDlgItem(hdlg, IDC_TEXT_F_SIZE); + sprintf(s, "Size : %imb", (((((uint64_t)hd_new_cyl*(uint64_t)hd_new_hpc)*(uint64_t)hd_new_spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + hd_changed = 1; + } + return TRUE; + + case IDC_FFILE: + if (!getfile(hdlg, "Hard disc image (*.IMG)\0*.IMG\0All files (*.*)\0*.*\0", "")) + { + f = fopen64(openfilestring, "rb"); + if (!f) + { + MessageBox(ghwnd,"Can't open file for read","PCem error",MB_OK); + return TRUE; + } + fseeko64(f, -1, SEEK_END); + sz = ftello64(f) + 1; + fclose(f); + hd_new_spt = 63; + hd_new_hpc = 16; + hd_new_cyl = ((sz / 512) / 16) / 63; + + if (DialogBox(hinstance, TEXT("HdSizeDlg"), hdlg, hdsize_dlgproc) == 1) + { + h = GetDlgItem(hdlg, IDC_EDIT_F_SPT); + sprintf(s, "%i", hd_new_spt); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_F_HPC); + sprintf(s, "%i", hd_new_hpc); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_F_CYL); + sprintf(s, "%i", hd_new_cyl); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + h = GetDlgItem(hdlg, IDC_EDIT_F_FN); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)openfilestring); + + h = GetDlgItem(hdlg, IDC_TEXT_F_SIZE); + sprintf(s, "Size : %imb", (((((uint64_t)hd_new_cyl*(uint64_t)hd_new_hpc)*(uint64_t)hd_new_spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + + hd_changed = 1; + } + } + return TRUE; + + case IDC_EDIT_C_SPT: case IDC_EDIT_C_HPC: case IDC_EDIT_C_CYL: + h = GetDlgItem(hdlg, IDC_EDIT_C_SPT); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[0].spt); + h = GetDlgItem(hdlg, IDC_EDIT_C_HPC); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[0].hpc); + h = GetDlgItem(hdlg, IDC_EDIT_C_CYL); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[0].tracks); + + h = GetDlgItem(hdlg, IDC_TEXT_C_SIZE); + sprintf(s, "Size : %imb", ((((hd[0].tracks*hd[0].hpc)*hd[0].spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + return TRUE; + + case IDC_EDIT_D_SPT: case IDC_EDIT_D_HPC: case IDC_EDIT_D_CYL: + h = GetDlgItem(hdlg, IDC_EDIT_D_SPT); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[1].spt); + h = GetDlgItem(hdlg, IDC_EDIT_D_HPC); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[1].hpc); + h = GetDlgItem(hdlg, IDC_EDIT_D_CYL); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[1].tracks); + + h = GetDlgItem(hdlg, IDC_TEXT_D_SIZE); + sprintf(s, "Size : %imb", ((((hd[1].tracks*hd[1].hpc)*hd[1].spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + return TRUE; + + case IDC_EDIT_E_SPT: case IDC_EDIT_E_HPC: case IDC_EDIT_E_CYL: + h = GetDlgItem(hdlg, IDC_EDIT_E_SPT); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[2].spt); + h = GetDlgItem(hdlg, IDC_EDIT_E_HPC); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[2].hpc); + h = GetDlgItem(hdlg, IDC_EDIT_E_CYL); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[2].tracks); + + h = GetDlgItem(hdlg, IDC_TEXT_E_SIZE); + sprintf(s, "Size : %imb", ((((hd[2].tracks*hd[2].hpc)*hd[2].spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + return TRUE; + + case IDC_EDIT_F_SPT: case IDC_EDIT_F_HPC: case IDC_EDIT_F_CYL: + h = GetDlgItem(hdlg, IDC_EDIT_F_SPT); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[3].spt); + h = GetDlgItem(hdlg, IDC_EDIT_F_HPC); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[3].hpc); + h = GetDlgItem(hdlg, IDC_EDIT_F_CYL); + SendMessage(h, WM_GETTEXT, 255, (LPARAM)s); + sscanf(s, "%i", &hd[3].tracks); + + h = GetDlgItem(hdlg, IDC_TEXT_F_SIZE); + sprintf(s, "Size : %imb", ((((hd[3].tracks*hd[3].hpc)*hd[3].spt)*512)/1024)/1024); + SendMessage(h, WM_SETTEXT, 0, (LPARAM)s); + return TRUE; + + case IDC_CHDD: + if (new_cdrom_channel == 0) + new_cdrom_channel = -1; + update_hdd_cdrom(hdlg); + return TRUE; + case IDC_DHDD: + if (new_cdrom_channel == 1) + new_cdrom_channel = -1; + update_hdd_cdrom(hdlg); + return TRUE; + case IDC_EHDD: + if (new_cdrom_channel == 2) + new_cdrom_channel = -1; + update_hdd_cdrom(hdlg); + return TRUE; + case IDC_FHDD: + if (new_cdrom_channel == 3) + new_cdrom_channel = -1; + update_hdd_cdrom(hdlg); + return TRUE; + + case IDC_CCDROM: + new_cdrom_channel = 0; + update_hdd_cdrom(hdlg); + return TRUE; + case IDC_DCDROM: + new_cdrom_channel = 1; + update_hdd_cdrom(hdlg); + return TRUE; + case IDC_ECDROM: + new_cdrom_channel = 2; + update_hdd_cdrom(hdlg); + return TRUE; + case IDC_FCDROM: + new_cdrom_channel = 3; + update_hdd_cdrom(hdlg); + return TRUE; + case IDC_GCDROM: + new_cdrom_channel = 4; + update_hdd_cdrom(hdlg); + return TRUE; + case IDC_HCDROM: + new_cdrom_channel = 5; + update_hdd_cdrom(hdlg); + return TRUE; + } + break; + + } + return FALSE; +} + +void hdconf_open(HWND hwnd) +{ + DialogBox(hinstance, TEXT("HdConfDlg"), hwnd, hdconf_dlgproc); +} diff --git a/src/win-joystick.cc b/src/win-joystick.cc new file mode 100644 index 000000000..55e3206f2 --- /dev/null +++ b/src/win-joystick.cc @@ -0,0 +1,255 @@ +#define DIRECTINPUT_VERSION 0x0800 +#include +#include +#include +extern "C" { +#include "device.h" +#include "gameport.h" +} +#include "plat-joystick.h" +#include "win.h" + +extern "C" int video_fullscreen; + +extern "C" void fatal(const char *format, ...); +extern "C" void pclog(const char *format, ...); + +extern "C" void joystick_init(); +extern "C" void joystick_close(); +extern "C" void poll_joystick(); + +plat_joystick_t plat_joystick_state[MAX_PLAT_JOYSTICKS]; +joystick_t joystick_state[MAX_JOYSTICKS]; + +static LPDIRECTINPUT8 lpdi; +static LPDIRECTINPUTDEVICE8 lpdi_joystick[2] = {NULL, NULL}; + +int joysticks_present = 0; +static GUID joystick_guids[MAX_JOYSTICKS]; + +static BOOL CALLBACK joystick_enum_callback(LPCDIDEVICEINSTANCE lpddi, LPVOID data) +{ + if (joysticks_present >= MAX_JOYSTICKS) + return DIENUM_STOP; + + pclog("joystick_enum_callback : found joystick %i : %s\n", joysticks_present, lpddi->tszProductName); + + joystick_guids[joysticks_present++] = lpddi->guidInstance; + + if (joysticks_present >= MAX_JOYSTICKS) + return DIENUM_STOP; + + return DIENUM_CONTINUE; +} + +BOOL CALLBACK DIEnumDeviceObjectsCallback( + LPCDIDEVICEOBJECTINSTANCE lpddoi, + LPVOID pvRef) +{ + plat_joystick_t *state = (plat_joystick_t *)pvRef; + + if (lpddoi->guidType == GUID_XAxis || lpddoi->guidType == GUID_YAxis || lpddoi->guidType == GUID_ZAxis || + lpddoi->guidType == GUID_RxAxis || lpddoi->guidType == GUID_RyAxis || lpddoi->guidType == GUID_RzAxis || + lpddoi->guidType == GUID_Slider) + { + strncpy(state->axis[state->nr_axes].name, lpddoi->tszName, sizeof(state->axis[state->nr_axes].name)); + pclog("Axis %i : %s %x %x\n", state->nr_axes, state->axis[state->nr_axes].name, lpddoi->dwOfs, lpddoi->dwType); + if (lpddoi->guidType == GUID_XAxis) + state->axis[state->nr_axes].id = 0; + else if (lpddoi->guidType == GUID_YAxis) + state->axis[state->nr_axes].id = 1; + else if (lpddoi->guidType == GUID_ZAxis) + state->axis[state->nr_axes].id = 2; + else if (lpddoi->guidType == GUID_RxAxis) + state->axis[state->nr_axes].id = 3; + else if (lpddoi->guidType == GUID_RyAxis) + state->axis[state->nr_axes].id = 4; + else if (lpddoi->guidType == GUID_RzAxis) + state->axis[state->nr_axes].id = 5; + state->nr_axes++; + } + else if (lpddoi->guidType == GUID_Button) + { + strncpy(state->button[state->nr_buttons].name, lpddoi->tszName, sizeof(state->button[state->nr_buttons].name)); + pclog("Button %i : %s %x %x\n", state->nr_buttons, state->button[state->nr_buttons].name, lpddoi->dwOfs, lpddoi->dwType); + state->nr_buttons++; + } + else if (lpddoi->guidType == GUID_POV) + { + strncpy(state->pov[state->nr_povs].name, lpddoi->tszName, sizeof(state->pov[state->nr_povs].name)); + pclog("POV %i : %s %x %x\n", state->nr_povs, state->pov[state->nr_povs].name, lpddoi->dwOfs, lpddoi->dwType); + state->nr_povs++; + } + + return DIENUM_CONTINUE; +} + +void joystick_init() +{ + int c; + + atexit(joystick_close); + + joysticks_present = 0; + + if (FAILED(DirectInput8Create(hinstance, DIRECTINPUT_VERSION, IID_IDirectInput8A, (void **) &lpdi, NULL))) + fatal("joystick_init : DirectInputCreate failed\n"); + + if (FAILED(lpdi->EnumDevices(DIDEVTYPE_JOYSTICK, joystick_enum_callback, NULL, DIEDFL_ATTACHEDONLY))) + fatal("joystick_init : EnumDevices failed\n"); + + pclog("joystick_init: joysticks_present=%i\n", joysticks_present); + + for (c = 0; c < joysticks_present; c++) + { + LPDIRECTINPUTDEVICE8 lpdi_joystick_temp = NULL; + DIPROPRANGE joy_axis_range; + DIDEVICEINSTANCE device_instance; + DIDEVCAPS devcaps; + int d; + + if (FAILED(lpdi->CreateDevice(joystick_guids[c], &lpdi_joystick_temp, NULL))) + fatal("joystick_init : CreateDevice failed\n"); + if (FAILED(lpdi_joystick_temp->QueryInterface(IID_IDirectInputDevice8, (void **)&lpdi_joystick[c]))) + fatal("joystick_init : CreateDevice failed\n"); + lpdi_joystick_temp->Release(); + + memset(&device_instance, 0, sizeof(device_instance)); + device_instance.dwSize = sizeof(device_instance); + if (FAILED(lpdi_joystick[c]->GetDeviceInfo(&device_instance))) + fatal("joystick_init : GetDeviceInfo failed\n"); + pclog("Joystick %i :\n", c); + pclog(" tszInstanceName = %s\n", device_instance.tszInstanceName); + pclog(" tszProductName = %s\n", device_instance.tszProductName); + strncpy(plat_joystick_state[c].name, device_instance.tszInstanceName, 64); + + memset(&devcaps, 0, sizeof(devcaps)); + devcaps.dwSize = sizeof(devcaps); + if (FAILED(lpdi_joystick[c]->GetCapabilities(&devcaps))) + fatal("joystick_init : GetCapabilities failed\n"); + pclog(" Axes = %i\n", devcaps.dwAxes); + pclog(" Buttons = %i\n", devcaps.dwButtons); + pclog(" POVs = %i\n", devcaps.dwPOVs); + + lpdi_joystick[c]->EnumObjects(DIEnumDeviceObjectsCallback, &plat_joystick_state[c], DIDFT_ALL); + + if (FAILED(lpdi_joystick[c]->SetCooperativeLevel(ghwnd, DISCL_BACKGROUND | DISCL_NONEXCLUSIVE))) + fatal("joystick_init : SetCooperativeLevel failed\n"); + if (FAILED(lpdi_joystick[c]->SetDataFormat(&c_dfDIJoystick))) + fatal("joystick_init : SetDataFormat failed\n"); + + joy_axis_range.lMin = -32768; + joy_axis_range.lMax = 32767; + joy_axis_range.diph.dwSize = sizeof(DIPROPRANGE); + joy_axis_range.diph.dwHeaderSize = sizeof(DIPROPHEADER); + joy_axis_range.diph.dwHow = DIPH_BYOFFSET; + joy_axis_range.diph.dwObj = DIJOFS_X; + lpdi_joystick[c]->SetProperty(DIPROP_RANGE, &joy_axis_range.diph); + joy_axis_range.diph.dwObj = DIJOFS_Y; + lpdi_joystick[c]->SetProperty(DIPROP_RANGE, &joy_axis_range.diph); + joy_axis_range.diph.dwObj = DIJOFS_Z; + lpdi_joystick[c]->SetProperty(DIPROP_RANGE, &joy_axis_range.diph); + joy_axis_range.diph.dwObj = DIJOFS_RX; + lpdi_joystick[c]->SetProperty(DIPROP_RANGE, &joy_axis_range.diph); + joy_axis_range.diph.dwObj = DIJOFS_RY; + lpdi_joystick[c]->SetProperty(DIPROP_RANGE, &joy_axis_range.diph); + joy_axis_range.diph.dwObj = DIJOFS_RZ; + lpdi_joystick[c]->SetProperty(DIPROP_RANGE, &joy_axis_range.diph); + + if (FAILED(lpdi_joystick[c]->Acquire())) + fatal("joystick_init : Acquire failed\n"); + } +} + +void joystick_close() +{ + if (lpdi_joystick[1]) + { + lpdi_joystick[1]->Release(); + lpdi_joystick[1] = NULL; + } + if (lpdi_joystick[0]) + { + lpdi_joystick[0]->Release(); + lpdi_joystick[0] = NULL; + } +} + +void joystick_poll() +{ + int c, d; + + for (c = 0; c < joysticks_present; c++) + { + DIJOYSTATE joystate; + int b; + + if (FAILED(lpdi_joystick[c]->Poll())) + { + lpdi_joystick[c]->Acquire(); + lpdi_joystick[c]->Poll(); + } + if (FAILED(lpdi_joystick[c]->GetDeviceState(sizeof(DIJOYSTATE), (LPVOID)&joystate))) + { + lpdi_joystick[c]->Acquire(); + lpdi_joystick[c]->Poll(); + lpdi_joystick[c]->GetDeviceState(sizeof(DIJOYSTATE), (LPVOID)&joystate); + } + + plat_joystick_state[c].a[0] = joystate.lX; + plat_joystick_state[c].a[1] = joystate.lY; + plat_joystick_state[c].a[2] = joystate.lZ; + plat_joystick_state[c].a[3] = joystate.lRx; + plat_joystick_state[c].a[4] = joystate.lRy; + plat_joystick_state[c].a[5] = joystate.lRz; + + for (b = 0; b < 16; b++) + plat_joystick_state[c].b[b] = joystate.rgbButtons[b] & 0x80; + + for (b = 0; b < 4; b++) + plat_joystick_state[c].p[b] = joystate.rgdwPOV[b]; +// pclog("joystick %i - x=%i y=%i b[0]=%i b[1]=%i %i\n", c, joystick_state[c].x, joystick_state[c].y, joystick_state[c].b[0], joystick_state[c].b[1], joysticks_present); + } + + for (c = 0; c < joystick_get_max_joysticks(joystick_type); c++) + { + if (joystick_state[c].plat_joystick_nr) + { + int joystick_nr = joystick_state[c].plat_joystick_nr - 1; + + for (d = 0; d < joystick_get_axis_count(joystick_type); d++) + { + if (joystick_state[c].axis_mapping[d] & POV_X) + { + int pov = plat_joystick_state[joystick_nr].p[joystick_state[c].axis_mapping[d] & 3]; + + if (LOWORD(pov) == 0xFFFF) + joystick_state[c].axis[d] = 0; + else + joystick_state[c].axis[d] = sin((2*M_PI * (double)pov) / 36000.0) * 32767; + } + else if (joystick_state[c].axis_mapping[d] & POV_Y) + { + int pov = plat_joystick_state[joystick_nr].p[joystick_state[c].axis_mapping[d] & 3]; + + if (LOWORD(pov) == 0xFFFF) + joystick_state[c].axis[d] = 0; + else + joystick_state[c].axis[d] = -cos((2*M_PI * (double)pov) / 36000.0) * 32767; + } + else + joystick_state[c].axis[d] = plat_joystick_state[joystick_nr].a[plat_joystick_state[joystick_nr].axis[joystick_state[c].axis_mapping[d]].id]; + } + for (d = 0; d < joystick_get_button_count(joystick_type); d++) + joystick_state[c].button[d] = plat_joystick_state[joystick_nr].b[joystick_state[c].button_mapping[d]]; + } + else + { + for (d = 0; d < joystick_get_axis_count(joystick_type); d++) + joystick_state[c].axis[d] = 0; + for (d = 0; d < joystick_get_button_count(joystick_type); d++) + joystick_state[c].button[d] = 0; + } + } +} + diff --git a/src/win-joystickconfig.c b/src/win-joystickconfig.c new file mode 100644 index 000000000..4aff40248 --- /dev/null +++ b/src/win-joystickconfig.c @@ -0,0 +1,407 @@ +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP + +#include "ibm.h" +#include "config.h" +#include "device.h" +#include "gameport.h" +#include "plat-joystick.h" +#include "resources.h" +#include "win.h" + +static int joystick_nr; +static int joystick_config_type; +#define AXIS_STRINGS_MAX 3 +static char *axis_strings[AXIS_STRINGS_MAX] = {"X Axis", "Y Axis", "Z Axis"}; + +static void rebuild_axis_button_selections(HWND hdlg) +{ + int id = IDC_CONFIG_BASE + 2; + HWND h; + int joystick; + int c, d; + + h = GetDlgItem(hdlg, IDC_CONFIG_BASE); + joystick = SendMessage(h, CB_GETCURSEL, 0, 0); + + for (c = 0; c < joystick_get_axis_count(joystick_config_type); c++) + { + int sel = c; + + h = GetDlgItem(hdlg, id); + SendMessage(h, CB_RESETCONTENT, 0, 0); + + if (joystick) + { + for (d = 0; d < plat_joystick_state[joystick-1].nr_axes; d++) + { + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)plat_joystick_state[joystick-1].axis[d].name); + if (c < AXIS_STRINGS_MAX) + { + if (!stricmp(axis_strings[c], plat_joystick_state[joystick-1].axis[d].name)) + sel = d; + } + } + for (d = 0; d < plat_joystick_state[joystick-1].nr_povs; d++) + { + char s[80]; + + sprintf(s, "%s (X axis)", plat_joystick_state[joystick-1].pov[d].name); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); + sprintf(s, "%s (Y axis)", plat_joystick_state[joystick-1].pov[d].name); + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)s); + } + SendMessage(h, CB_SETCURSEL, sel, 0); + EnableWindow(h, TRUE); + } + else + EnableWindow(h, FALSE); + + id += 2; + } + + for (c = 0; c < joystick_get_button_count(joystick_config_type); c++) + { + h = GetDlgItem(hdlg, id); + SendMessage(h, CB_RESETCONTENT, 0, 0); + + if (joystick) + { + for (d = 0; d < plat_joystick_state[joystick-1].nr_buttons; d++) + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)plat_joystick_state[joystick-1].button[d].name); + SendMessage(h, CB_SETCURSEL, c, 0); + EnableWindow(h, TRUE); + } + else + EnableWindow(h, FALSE); + + id += 2; + } +} + +static int get_axis(HWND hdlg, int id) +{ + HWND h = GetDlgItem(hdlg, id); + int axis_sel = SendMessage(h, CB_GETCURSEL, 0, 0); + int nr_axes = plat_joystick_state[joystick_state[joystick_nr].plat_joystick_nr-1].nr_axes; + + if (axis_sel < nr_axes) + return axis_sel; + + axis_sel -= nr_axes; + if (axis_sel & 1) + return POV_Y | (axis_sel >> 1); + else + return POV_X | (axis_sel >> 1); +} + +static BOOL CALLBACK joystickconfig_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_INITDIALOG: + { + HWND h = GetDlgItem(hdlg, IDC_CONFIG_BASE); + int c, d; + int id = IDC_CONFIG_BASE + 2; + int joystick = joystick_state[joystick_nr].plat_joystick_nr; + + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)"None"); + + for (c = 0; c < joysticks_present; c++) + SendMessage(h, CB_ADDSTRING, 0, (LPARAM)(LPCSTR)plat_joystick_state[c].name); + + SendMessage(h, CB_SETCURSEL, joystick, 0); + + rebuild_axis_button_selections(hdlg); + + if (joystick_state[joystick_nr].plat_joystick_nr) + { + int nr_axes = plat_joystick_state[joystick-1].nr_axes; + for (c = 0; c < joystick_get_axis_count(joystick_config_type); c++) + { + int mapping = joystick_state[joystick_nr].axis_mapping[c]; + + h = GetDlgItem(hdlg, id); + if (mapping & POV_X) + SendMessage(h, CB_SETCURSEL, nr_axes + (mapping & 3)*2, 0); + else if (mapping & POV_Y) + SendMessage(h, CB_SETCURSEL, nr_axes + (mapping & 3)*2 + 1, 0); + else + SendMessage(h, CB_SETCURSEL, mapping, 0); + id += 2; + } + for (c = 0; c < joystick_get_button_count(joystick_config_type); c++) + { + h = GetDlgItem(hdlg, id); + SendMessage(h, CB_SETCURSEL, joystick_state[joystick_nr].button_mapping[c], 0); + id += 2; + } + } + } + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDC_CONFIG_BASE: + if (HIWORD(wParam) == CBN_SELCHANGE) + rebuild_axis_button_selections(hdlg); + break; + + case IDOK: + { + HWND h; + int joystick; + int c, d; + int id = IDC_CONFIG_BASE + 2; + + h = GetDlgItem(hdlg, IDC_CONFIG_BASE); + joystick_state[joystick_nr].plat_joystick_nr = SendMessage(h, CB_GETCURSEL, 0, 0); + + if (joystick_state[joystick_nr].plat_joystick_nr) + { + for (c = 0; c < joystick_get_axis_count(joystick_config_type); c++) + { + joystick_state[joystick_nr].axis_mapping[c] = get_axis(hdlg, id); + id += 2; + } + for (c = 0; c < joystick_get_button_count(joystick_config_type); c++) + { + h = GetDlgItem(hdlg, id); + joystick_state[joystick_nr].button_mapping[c] = SendMessage(h, CB_GETCURSEL, 0, 0); + id += 2; + } + } + } + case IDCANCEL: + EndDialog(hdlg, 0); + return TRUE; + } + break; + } + return FALSE; +} + +void joystickconfig_open(HWND hwnd, int joy_nr, int type) +{ +// device_config_t *config = device->config; + uint16_t *data_block = malloc(16384); + uint16_t *data; + DLGTEMPLATE *dlg = (DLGTEMPLATE *)data_block; + DLGITEMTEMPLATE *item; + int y = 10; + int id = IDC_CONFIG_BASE; + int c; + + joystick_nr = joy_nr; + joystick_config_type = type; + + memset(data_block, 0, 4096); + + dlg->style = DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU; + dlg->x = 10; + dlg->y = 10; + dlg->cx = 220; + dlg->cy = 70; + + data = (uint16_t *)(dlg + 1); + + *data++ = 0; /*no menu*/ + *data++ = 0; /*predefined dialog box class*/ + data += MultiByteToWideChar(CP_ACP, 0, "Device Configuration", -1, data, 50); + + *data++ = 8; /*Point*/ + data += MultiByteToWideChar(CP_ACP, 0, "MS Sans Serif", -1, data, 50); + + if (((unsigned long)data) & 2) + data++; + + + /*Combo box*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 70; + item->y = y; + item->id = id++; + + item->cx = 140; + item->cy = 150; + + item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0085; // combo box class + + data += MultiByteToWideChar(CP_ACP, 0, "Device", -1, data, 256); + *data++ = 0; // no creation data + + if (((unsigned long)data) & 2) + data++; + + /*Static text*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 10; + item->y = y; + item->id = id++; + + item->cx = 60; + item->cy = 15; + + item->style = WS_CHILD | WS_VISIBLE; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0082; // static class + + data += MultiByteToWideChar(CP_ACP, 0, "Device :", -1, data, 256); + *data++ = 0; // no creation data + + if (((unsigned long)data) & 2) + data++; + + y += 20; + + + for (c = 0; c < joystick_get_axis_count(type); c++) + { + /*Combo box*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 70; + item->y = y; + item->id = id++; + + item->cx = 140; + item->cy = 150; + + item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0085; // combo box class + + data += MultiByteToWideChar(CP_ACP, 0, joystick_get_axis_name(type, c), -1, data, 256); + *data++ = 0; // no creation data + + if (((unsigned long)data) & 2) + data++; + + /*Static text*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 10; + item->y = y; + item->id = id++; + + item->cx = 60; + item->cy = 15; + + item->style = WS_CHILD | WS_VISIBLE; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0082; // static class + + data += MultiByteToWideChar(CP_ACP, 0, joystick_get_axis_name(type, c), -1, data, 256); + *data++ = 0; // no creation data + + if (((unsigned long)data) & 2) + data++; + + y += 20; + } + + for (c = 0; c < joystick_get_button_count(type); c++) + { + /*Combo box*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 70; + item->y = y; + item->id = id++; + + item->cx = 140; + item->cy = 150; + + item->style = WS_CHILD | WS_VISIBLE | CBS_DROPDOWN | WS_VSCROLL; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0085; // combo box class + + data += MultiByteToWideChar(CP_ACP, 0, joystick_get_button_name(type, c), -1, data, 256); + *data++ = 0; // no creation data + + if (((unsigned long)data) & 2) + data++; + + /*Static text*/ + item = (DLGITEMTEMPLATE *)data; + item->x = 10; + item->y = y; + item->id = id++; + + item->cx = 60; + item->cy = 15; + + item->style = WS_CHILD | WS_VISIBLE; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0082; // static class + + data += MultiByteToWideChar(CP_ACP, 0, joystick_get_button_name(type, c), -1, data, 256); + *data++ = 0; // no creation data + + if (((unsigned long)data) & 2) + data++; + + y += 20; + } + + dlg->cdit = (id - IDC_CONFIG_BASE) + 2; + +// DEFPUSHBUTTON "OK",IDOK,64,232,50,14, WS_TABSTOP +// PUSHBUTTON "Cancel",IDCANCEL,128,232,50,14, WS_TABSTOP + + item = (DLGITEMTEMPLATE *)data; + item->x = 20; + item->y = y; + item->cx = 50; + item->cy = 14; + item->id = IDOK; // OK button identifier + item->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0080; // button class + + data += MultiByteToWideChar(CP_ACP, 0, "OK", -1, data, 50); + *data++ = 0; // no creation data + + if (((unsigned long)data) & 2) + data++; + + item = (DLGITEMTEMPLATE *)data; + item->x = 80; + item->y = y; + item->cx = 50; + item->cy = 14; + item->id = IDCANCEL; // OK button identifier + item->style = WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON; + + data = (uint16_t *)(item + 1); + *data++ = 0xFFFF; + *data++ = 0x0080; // button class + + data += MultiByteToWideChar(CP_ACP, 0, "Cancel", -1, data, 50); + *data++ = 0; // no creation data + + dlg->cy = y + 20; + +// config_device = device; + + DialogBoxIndirect(hinstance, dlg, hwnd, joystickconfig_dlgproc); + + free(data_block); +} diff --git a/src/win-keyboard.cc b/src/win-keyboard.cc new file mode 100644 index 000000000..6cd5723e6 --- /dev/null +++ b/src/win-keyboard.cc @@ -0,0 +1,57 @@ +#define UNICODE +#include +#include +#include +#define BITMAP WINDOWS_BITMAP +#include +#undef BITMAP +#include "plat-keyboard.h" +#include "win.h" +#include "video.h" + +extern "C" int pcem_key[272]; + +extern "C" void fatal(const char *format, ...); +extern "C" void pclog(const char *format, ...); + +extern "C" void keyboard_init(); +extern "C" void keyboard_close(); +extern "C" void keyboard_poll(); + +int pcem_key[272]; + +void keyboard_init() +{ + atexit(keyboard_close); + + memset(pcem_key, 0, sizeof(pcem_key)); + pclog("Keyboard initialized!\n"); +} + +void keyboard_close() +{ +} + +void keyboard_poll_host() +{ +#if 0 + int c; + + for (c = 0; c < 272; c++) + pcem_key[c] = rawinputkey[c]; + + if ((rawinputkey[0x1D] || rawinputkey[0x9D]) && + (rawinputkey[0x38] || rawinputkey[0xB8]) && + (rawinputkey[0x51] || rawinputkey[0xD1]) && + video_fullscreen) + leave_fullscreen(); + + if ((rawinputkey[0x1D] || rawinputkey[0x9D]) && +// (rawinputkey[0x38] || rawinputkey[0xB8]) && + (rawinputkey[0x57] || rawinputkey[0x57])) + { + pclog("Taking screenshot...\n"); + take_screenshot(); + } +#endif +} diff --git a/src/win-midi.c b/src/win-midi.c new file mode 100644 index 000000000..ba8965102 --- /dev/null +++ b/src/win-midi.c @@ -0,0 +1,113 @@ +#include +#include +#include "ibm.h" +#include "plat-midi.h" + +static int midi_id; +static HMIDIOUT midi_out_device = NULL; + +void midi_close(); + +void midi_init() +{ + int c; + int n; + MIDIOUTCAPS ocaps; + MMRESULT hr; + + midi_id = config_get_int(NULL, "midi", 0); + + hr = midiOutOpen(&midi_out_device, midi_id, 0, + 0, CALLBACK_NULL); + if (hr != MMSYSERR_NOERROR) { + printf("midiOutOpen error - %08X\n",hr); + midi_id = 0; + hr = midiOutOpen(&midi_out_device, midi_id, 0, + 0, CALLBACK_NULL); + if (hr != MMSYSERR_NOERROR) { + printf("midiOutOpen error - %08X\n",hr); + return; + } + } + + midiOutReset(midi_out_device); +} + +void midi_close() +{ + if (midi_out_device != NULL) + { + midiOutReset(midi_out_device); + midiOutClose(midi_out_device); + midi_out_device = NULL; + } +} + +int midi_get_num_devs() +{ + return midiOutGetNumDevs(); +} +void midi_get_dev_name(int num, char *s) +{ + MIDIOUTCAPS caps; + + midiOutGetDevCaps(num, &caps, sizeof(caps)); + strcpy(s, caps.szPname); +} + +static int midi_pos, midi_len; +static uint32_t midi_command; +static int midi_lengths[8] = {3, 3, 3, 3, 2, 2, 3, 1}; +static int midi_insysex; +static uint8_t midi_sysex_data[1024+2]; + +static void midi_send_sysex() +{ + MIDIHDR hdr; + int c; + + hdr.lpData = midi_sysex_data; + hdr.dwBufferLength = midi_pos; + hdr.dwFlags = 0; + +/* pclog("Sending sysex : "); + for (c = 0; c < midi_pos; c++) + pclog("%02x ", midi_sysex_data[c]); + pclog("\n");*/ + + midiOutPrepareHeader(midi_out_device, &hdr, sizeof(MIDIHDR)); + midiOutLongMsg(midi_out_device, &hdr, sizeof(MIDIHDR)); + + midi_insysex = 0; +} + +void midi_write(uint8_t val) +{ + if ((val & 0x80) && !(val == 0xf7 && midi_insysex)) + { + midi_pos = 0; + midi_len = midi_lengths[(val >> 4) & 7]; + midi_command = 0; + if (val == 0xf0) + midi_insysex = 1; + } + + if (midi_insysex) + { + midi_sysex_data[midi_pos++] = val; + + if (val == 0xf7 || midi_pos >= 1024+2) + midi_send_sysex(); + return; + } + + if (midi_len) + { + midi_command |= (val << (midi_pos * 8)); + + midi_pos++; + + if (midi_pos == midi_len) + midiOutShortMsg(midi_out_device, midi_command); + } +} diff --git a/src/win-mouse.cc b/src/win-mouse.cc new file mode 100644 index 000000000..e769c7a45 --- /dev/null +++ b/src/win-mouse.cc @@ -0,0 +1,70 @@ +#define DIRECTINPUT_VERSION 0x0800 +#include +#include "plat-mouse.h" +#include "win.h" + +extern "C" int video_fullscreen; + +extern "C" void fatal(const char *format, ...); +extern "C" void pclog(const char *format, ...); + +extern "C" void mouse_init(); +extern "C" void mouse_close(); +extern "C" void mouse_poll_host(); +extern "C" void mouse_get_mickeys(int *x, int *y); + +static LPDIRECTINPUT8 lpdi; +static LPDIRECTINPUTDEVICE8 lpdi_mouse = NULL; +static DIMOUSESTATE mousestate; +static int mouse_x = 0, mouse_y = 0; +int mouse_buttons = 0; + +void mouse_init() +{ + atexit(mouse_close); + + if (FAILED(DirectInput8Create(hinstance, DIRECTINPUT_VERSION, IID_IDirectInput8A, (void **) &lpdi, NULL))) + fatal("mouse_init : DirectInputCreate failed\n"); + if (FAILED(lpdi->CreateDevice(GUID_SysMouse, &lpdi_mouse, NULL))) + fatal("mouse_init : CreateDevice failed\n"); + if (FAILED(lpdi_mouse->SetCooperativeLevel(ghwnd, DISCL_FOREGROUND | (video_fullscreen ? DISCL_EXCLUSIVE : DISCL_NONEXCLUSIVE)))) + fatal("mouse_init : SetCooperativeLevel failed\n"); + if (FAILED(lpdi_mouse->SetDataFormat(&c_dfDIMouse))) + fatal("mouse_init : SetDataFormat failed\n"); +} + +void mouse_close() +{ + if (lpdi_mouse) + { + lpdi_mouse->Release(); + lpdi_mouse = NULL; + } +} + +void mouse_poll_host() +{ + if (FAILED(lpdi_mouse->GetDeviceState(sizeof(DIMOUSESTATE), (LPVOID)&mousestate))) + { + lpdi_mouse->Acquire(); + lpdi_mouse->GetDeviceState(sizeof(DIMOUSESTATE), (LPVOID)&mousestate); + } + mouse_buttons = 0; + if (mousestate.rgbButtons[0] & 0x80) + mouse_buttons |= 1; + if (mousestate.rgbButtons[1] & 0x80) + mouse_buttons |= 2; + if (mousestate.rgbButtons[2] & 0x80) + mouse_buttons |= 4; + mouse_x += mousestate.lX; + mouse_y += mousestate.lY; + if (!mousecapture && !video_fullscreen) + mouse_x = mouse_y = mouse_buttons = 0; +} + +void mouse_get_mickeys(int *x, int *y) +{ + *x = mouse_x; + *y = mouse_y; + mouse_x = mouse_y = 0; +} diff --git a/src/win-status.c b/src/win-status.c new file mode 100644 index 000000000..8d7e1f09d --- /dev/null +++ b/src/win-status.c @@ -0,0 +1,103 @@ +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP + +#include "ibm.h" +#include "device.h" +#include "video.h" +#include "resources.h" +#include "win.h" +#include "x86_ops.h" +#include "mem.h" +#include "codegen.h" + +HWND status_hwnd; +int status_is_open = 0; + +extern int sreadlnum, swritelnum, segareads, segawrites, scycles_lost; + +extern uint64_t main_time; +static uint64_t status_time; + +static BOOL CALLBACK status_dlgproc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) +{ + char device_s[4096]; + switch (message) + { + case WM_INITDIALOG: + status_is_open = 1; + case WM_USER: + { + uint64_t new_time = timer_read(); + uint64_t status_diff = new_time - status_time; + status_time = new_time; + sprintf(device_s, + "CPU speed : %f MIPS\n" + "FPU speed : %f MFLOPS\n\n" + +/* "Cache misses (read) : %i/sec\n" + "Cache misses (write) : %i/sec\n\n"*/ + + "Video throughput (read) : %i bytes/sec\n" + "Video throughput (write) : %i bytes/sec\n\n" + "Effective clockspeed : %iHz\n\n" + "Timer 0 frequency : %fHz\n\n" + "CPU time : %f%% (%f%%)\n" + + "New blocks : %i\nOld blocks : %i\nRecompiled speed : %f MIPS\nAverage size : %f\n" + "Flushes : %i\nEvicted : %i\nReused : %i\nRemoved : %i\nReal speed : %f MIPS" +// "\nFully recompiled ins %% : %f%%" + ,mips, + flops, +/*#ifndef DYNAREC + sreadlnum, + swritelnum, +#endif*/ + segareads, + segawrites, + clockrate - (sreadlnum*memwaitstate) - (swritelnum*memwaitstate) - scycles_lost, + pit_timer0_freq(), + ((double)main_time * 100.0) / status_diff, + ((double)main_time * 100.0) / timer_freq + + , cpu_new_blocks_latched, cpu_recomp_blocks_latched, (double)cpu_recomp_ins_latched / 1000000.0, (double)cpu_recomp_ins_latched/cpu_recomp_blocks_latched, + cpu_recomp_flushes_latched, cpu_recomp_evicted_latched, + cpu_recomp_reuse_latched, cpu_recomp_removed_latched, + + ((double)cpu_recomp_ins_latched / 1000000.0) / ((double)main_time / timer_freq) +// ((double)cpu_recomp_full_ins_latched / (double)cpu_recomp_ins_latched) * 100.0 +// cpu_reps_latched, cpu_notreps_latched + ); + main_time = 0; +/*#ifndef DYNAREC + device_add_status_info(device_s, 4096); +#endif*/ + SendDlgItemMessage(hdlg, IDC_STEXT_DEVICE, WM_SETTEXT, (WPARAM)NULL, (LPARAM)device_s); + + device_s[0] = 0; + device_add_status_info(device_s, 4096); + SendDlgItemMessage(hdlg, IDC_STEXT1, WM_SETTEXT, (WPARAM)NULL, (LPARAM)device_s); + } + return TRUE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + case IDCANCEL: + status_is_open = 0; + EndDialog(hdlg, 0); + return TRUE; + } + break; + } + + return FALSE; +} + +void status_open(HWND hwnd) +{ + status_hwnd = CreateDialog(hinstance, TEXT("StatusDlg"), hwnd, status_dlgproc); + ShowWindow(status_hwnd, SW_SHOW); +} diff --git a/src/win-time.c b/src/win-time.c new file mode 100644 index 000000000..4075bbf12 --- /dev/null +++ b/src/win-time.c @@ -0,0 +1,48 @@ +#include +#include "ibm.h" +#include "nvr.h" + +void time_sleep(int count) +{ + Sleep(count); +} + +void time_get(char *nvrram) +{ + SYSTEMTIME systemtime; + int c, d; + uint8_t baknvr[10]; + + memcpy(baknvr,nvrram,10); + GetLocalTime(&systemtime); + + d = systemtime.wSecond % 10; + c = systemtime.wSecond / 10; + nvrram[0] = d | (c << 4); + d = systemtime.wMinute % 10; + c = systemtime.wMinute / 10; + nvrram[2] = d | (c << 4); + d = systemtime.wHour % 10; + c = systemtime.wHour / 10; + nvrram[4] = d | (c << 4); + d = systemtime.wDayOfWeek % 10; + c = systemtime.wDayOfWeek / 10; + nvrram[6] = d | (c << 4); + d = systemtime.wDay % 10; + c = systemtime.wDay / 10; + nvrram[7] = d | (c << 4); + d = systemtime.wMonth % 10; + c = systemtime.wMonth / 10; + nvrram[8] = d | (c << 4); + d = systemtime.wYear % 10; + c = (systemtime.wYear / 10) % 10; + nvrram[9] = d | (c << 4); + if (baknvr[0] != nvrram[0] || + baknvr[2] != nvrram[2] || + baknvr[4] != nvrram[4] || + baknvr[6] != nvrram[6] || + baknvr[7] != nvrram[7] || + baknvr[8] != nvrram[8] || + baknvr[9] != nvrram[9]) + nvrram[0xA]|=0x80; +} diff --git a/src/win-video.c b/src/win-video.c new file mode 100644 index 000000000..c1202d17a --- /dev/null +++ b/src/win-video.c @@ -0,0 +1,51 @@ +#include +#include +#include +#include "video.h" + +BITMAP *screen; + +void hline(BITMAP *b, int x1, int y, int x2, uint32_t col) +{ + if (y < 0 || y >= buffer->h) + return; + + if (b == buffer) + memset(&b->line[y][x1], col, x2 - x1); + else + memset(&((uint32_t *)b->line[y])[x1], col, (x2 - x1) * 4); +} + +void blit(BITMAP *src, BITMAP *dst, int x1, int y1, int x2, int y2, int xs, int ys) +{ +} + +void stretch_blit(BITMAP *src, BITMAP *dst, int x1, int y1, int xs1, int ys1, int x2, int y2, int xs2, int ys2) +{ +} + +void rectfill(BITMAP *b, int x1, int y1, int x2, int y2, uint32_t col) +{ +} + +void set_palette(PALETTE p) +{ +} + +void destroy_bitmap(BITMAP *b) +{ +} + +BITMAP *create_bitmap(int x, int y) +{ + BITMAP *b = malloc(sizeof(BITMAP) + (y * sizeof(uint8_t *))); + int c; + b->dat = malloc(x * y * 4); + for (c = 0; c < y; c++) + { + b->line[c] = b->dat + (c * x * 4); + } + b->w = x; + b->h = y; + return b; +} diff --git a/src/win.c b/src/win.c new file mode 100644 index 000000000..ef370606c --- /dev/null +++ b/src/win.c @@ -0,0 +1,1487 @@ +#define _WIN32_WINNT 0x0501 +#define BITMAP WINDOWS_BITMAP +#include +#include +#undef BITMAP + +#include +#include + +#include + +#include +#include +#include +#include +#include "ibm.h" +#include "cdrom-null.h" +#include "cdrom-ioctl.h" +#include "cdrom-iso.h" +#include "config.h" +#include "video.h" +#include "resources.h" +#include "cpu.h" +#include "ide.h" +#include "model.h" +#include "nethandler.h" +#include "nvr.h" +#include "sound.h" +#include "thread.h" +#include "disc.h" + +#include "plat-midi.h" +#include "plat-keyboard.h" + +#include "win.h" +#include "win-ddraw.h" +#include "win-ddraw-fs.h" +#include "win-d3d.h" +#include "win-d3d-fs.h" +//#include "win-opengl.h" + +#ifndef MAPVK_VK_TO_VSC +#define MAPVK_VK_TO_VSC 0 +#endif + +static int save_window_pos = 0; +uint64_t timer_freq; + +int rawinputkey[272]; + +static RAWINPUTDEVICE device; +static uint16_t scancode_map[65536]; + +static struct +{ + void (*init)(HWND h); + void (*close)(); + void (*resize)(int x, int y); +} vid_apis[2][2] = +{ + { + ddraw_init, ddraw_close, NULL, + d3d_init, d3d_close, d3d_resize + }, + { + ddraw_fs_init, ddraw_fs_close, NULL, + d3d_fs_init, d3d_fs_close, NULL + }, +}; + +#define TIMER_1SEC 1 + +int winsizex=640,winsizey=480; +int efwinsizey=480; +int gfx_present[GFX_MAX]; +#undef cs +CRITICAL_SECTION cs; + +HANDLE mainthreadh; + +int infocus=1; + +int drawits=0; + +int romspresent[ROM_MAX]; +int quited=0; + +RECT oldclip; +int mousecapture=0; + +/* Declare Windows procedure */ +LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); +LRESULT CALLBACK subWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); + +HWND ghwnd; + +HINSTANCE hinstance; + +HMENU menu; + +extern int updatestatus; + +int pause=0; + +static int win_doresize = 0; + +static int leave_fullscreen_flag = 0; + +void updatewindowsize(int x, int y) +{ + RECT r; + if (vid_resize) return; + + if (x < 160) x = 160; + if (y < 100) y = 100; + + winsizex=x; efwinsizey=y; + + if (force_43) + { + /* Account for possible overscan. */ + if (overscan_y == 16) + { + /* CGA */ + winsizey = ((int) (((double) (x - overscan_x) / 4.0) * 3.0)) + overscan_y; + } + else if (overscan_y < 16) + { + /* MDA/Hercules */ + winsizey = efwinsizey; + } + else + { + if (enable_overscan) + { + /* EGA/(S)VGA with overscan */ + winsizey = ((int) (((double) (x - overscan_x) / 4.0) * 3.0)) + overscan_y; + } + else + { + /* EGA/(S)VGA without overscan */ + winsizey = efwinsizey; + } + } + } + else + { + winsizey = efwinsizey; + } + + win_doresize = 1; +} + +void uws_natural() +{ + updatewindowsize(winsizex, efwinsizey); +} + +void releasemouse() +{ + if (mousecapture) + { + ClipCursor(&oldclip); + ShowCursor(TRUE); + mousecapture = 0; + } +} + +void startblit() +{ + EnterCriticalSection(&cs); +} + +void endblit() +{ + LeaveCriticalSection(&cs); +} + +void leave_fullscreen() +{ + leave_fullscreen_flag = 1; +} + +uint64_t main_time; + +void mainthread(LPVOID param) +{ + int t = 0; + int frames = 0; + DWORD old_time, new_time; + +// Sleep(500); + drawits=0; + old_time = GetTickCount(); + while (!quited) + { + if (updatestatus) + { + updatestatus = 0; + if (status_is_open) + SendMessage(status_hwnd, WM_USER, 0, 0); + } + new_time = GetTickCount(); + drawits += new_time - old_time; + old_time = new_time; + if (drawits > 0 && !pause) + { + uint64_t start_time = timer_read(); + uint64_t end_time; + drawits-=10; if (drawits>50) drawits=0; + runpc(); + frames++; + if (frames >= 200 && nvr_dosave) + { + frames = 0; + nvr_dosave = 0; + savenvr(); + } + end_time = timer_read(); + main_time += end_time - start_time; + } + else + Sleep(1); + + if (!video_fullscreen && win_doresize) + { + RECT r; + GetWindowRect(ghwnd, &r); + MoveWindow(ghwnd, r.left, r.top, + winsizex + (GetSystemMetrics(SM_CXFIXEDFRAME) * 2), + winsizey + (GetSystemMetrics(SM_CYFIXEDFRAME) * 2) + GetSystemMetrics(SM_CYMENUSIZE) + GetSystemMetrics(SM_CYCAPTION) + 1, + TRUE); + win_doresize = 0; + } + + if (leave_fullscreen_flag) + { + leave_fullscreen_flag = 0; + SendMessage(ghwnd, WM_LEAVEFULLSCREEN, 0, 0); + } + if (video_fullscreen && infocus) + { + SetCursorPos(9999, 9999); + } + } +} + +void *thread_create(void (*thread_rout)(void *param), void *param) +{ + return (void *)_beginthread(thread_rout, 0, param); +} + +void thread_kill(void *handle) +{ + TerminateThread(handle, 0); +} + +void thread_sleep(int t) +{ + Sleep(t); +} + +typedef struct win_event_t +{ + HANDLE handle; +} win_event_t; + +event_t *thread_create_event() +{ + win_event_t *event = malloc(sizeof(win_event_t)); + + event->handle = CreateEvent(NULL, FALSE, FALSE, NULL); + + return (event_t *)event; +} + +void thread_set_event(event_t *_event) +{ + win_event_t *event = (win_event_t *)_event; + + SetEvent(event->handle); +} + +void thread_reset_event(event_t *_event) +{ + win_event_t *event = (win_event_t *)_event; + + ResetEvent(event->handle); +} + +int thread_wait_event(event_t *_event, int timeout) +{ + win_event_t *event = (win_event_t *)_event; + + if (timeout == -1) + timeout = INFINITE; + + if (WaitForSingleObject(event->handle, timeout)) + return 1; + return 0; +} + +void thread_destroy_event(event_t *_event) +{ + win_event_t *event = (win_event_t *)_event; + + CloseHandle(event->handle); + + free(event); +} + +static void initmenu(void) +{ + int c; + HMENU m; + char s[32]; + m=GetSubMenu(menu,2); /*Settings*/ + m=GetSubMenu(m,1); /*CD-ROM*/ + + /* Loop through each Windows drive letter and test to see if + it's a CDROM */ + for (c='A';c<='Z';c++) + { + sprintf(s,"%c:\\",c); + if (GetDriveType(s)==DRIVE_CDROM) + { + sprintf(s, "Host CD/DVD Drive (%c:)", c); + AppendMenu(m,MF_STRING,IDM_CDROM_REAL+c,s); + } + } +} + +void get_executable_name(char *s, int size) +{ + GetModuleFileName(hinstance, s, size); +} + +void set_window_title(char *s) +{ + if (video_fullscreen) + return; + SetWindowText(ghwnd, s); +} + +uint64_t timer_read() +{ + LARGE_INTEGER qpc_time; + QueryPerformanceCounter(&qpc_time); + return qpc_time.QuadPart; +} + +/* This is so we can disambiguate scan codes that would otherwise conflict and get + passed on incorrectly. */ +UINT16 convert_scan_code(UINT16 scan_code) +{ + switch (scan_code) + { + case 0xE001: + return 0xF001; + case 0xE002: + return 0xF002; + case 0xE0AA: + return 0xF003; + case 0xE005: + return 0xF005; + case 0xE006: + return 0xF006; + case 0xE007: + return 0xF007; + case 0xE071: + return 0xF008; + case 0xE072: + return 0xF009; + case 0xE07F: + return 0xF00A; + case 0xE0E1: + return 0xF00B; + case 0xE0EE: + return 0xF00C; + case 0xE0F1: + return 0xF00D; + case 0xE0FE: + return 0xF00E; + case 0xE0EF: + return 0xF00F; + + default: + return scan_code; + } +} + +void get_registry_key_map() +{ + char *keyName = "SYSTEM\\CurrentControlSet\\Control\\Keyboard Layout"; + char *valueName = "Scancode Map"; + char buf[32768]; + DWORD bufSize; + HKEY hKey; + int j; + + /* First, prepare the default scan code map list which is 1:1. + Remappings will be inserted directly into it. + 65536 bytes so scan codes fit in easily and it's easy to find what each maps too, + since each array element is a scan code and provides for E0, etc. ones too. */ + for (j = 0; j < 65536; j++) + scancode_map[j] = convert_scan_code(j); + + bufSize = 32768; + /* Get the scan code remappings from: + HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout */ + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, keyName, 0, 1, &hKey) == ERROR_SUCCESS) + { + if(RegQueryValueEx(hKey, valueName, NULL, NULL, buf, &bufSize) == ERROR_SUCCESS) + { + UINT32 *bufEx2 = (UINT32 *) buf; + int scMapCount = bufEx2[2]; + if ((bufSize != 0) && (scMapCount != 0)) + { + UINT16 *bufEx = (UINT16 *) (buf + 12); + for (j = 0; j < scMapCount*2; j += 2) + { + /* Each scan code is 32-bit: 16 bits of remapped scan code, + and 16 bits of original scan code. */ + int scancode_unmapped = bufEx[j + 1]; + int scancode_mapped = bufEx[j]; + + scancode_mapped = convert_scan_code(scancode_mapped); + + /* Fixes scan code map logging. */ + scancode_map[scancode_unmapped] = scancode_mapped; + } + } + } + RegCloseKey(hKey); + } +} + +static char **argv; +static int argc; +static char *argbuf; + +static void process_command_line() +{ + char *cmdline; + int argc_max; + int i, q; + + cmdline = GetCommandLine(); + i = strlen(cmdline) + 1; + argbuf = malloc(i); + memcpy(argbuf, cmdline, i); + + argc = 0; + argc_max = 64; + argv = malloc(sizeof(char *) * argc_max); + if (!argv) + { + free(argbuf); + return; + } + + i = 0; + + /* parse commandline into argc/argv format */ + while (argbuf[i]) + { + while (argbuf[i] == ' ') + i++; + + if (argbuf[i]) + { + if ((argbuf[i] == '\'') || (argbuf[i] == '"')) + { + q = argbuf[i++]; + if (!argbuf[i]) + break; + } + else + q = 0; + + argv[argc++] = &argbuf[i]; + + if (argc >= argc_max) + { + argc_max += 64; + argv = realloc(argv, sizeof(char *) * argc_max); + if (!argv) + { + free(argbuf); + return; + } + } + + while ((argbuf[i]) && ((q) ? (argbuf[i] != q) : (argbuf[i] != ' '))) + i++; + + if (argbuf[i]) + { + argbuf[i] = 0; + i++; + } + // pclog("Arg %i - %s\n",argc-1,argv[argc-1]); + } + } + + argv[argc] = NULL; +} + +int WINAPI WinMain (HINSTANCE hThisInstance, + HINSTANCE hPrevInstance, + LPSTR lpszArgument, + int nFunsterStil) + +{ + HWND hwnd; /* This is the handle for our window */ + MSG messages; /* Here messages to the application are saved */ + WNDCLASSEX wincl; /* Data structure for the windowclass */ + int c, d; + LARGE_INTEGER qpc_freq; + + process_command_line(); + + hinstance=hThisInstance; + /* The Window structure */ + wincl.hInstance = hThisInstance; + wincl.lpszClassName = szClassName; + wincl.lpfnWndProc = WindowProcedure; /* This function is called by windows */ + wincl.style = CS_DBLCLKS; /* Catch double-clicks */ + wincl.cbSize = sizeof (WNDCLASSEX); + + /* Use default icon and mouse-pointer */ + wincl.hIcon = LoadIcon (hinstance, 100); + wincl.hIconSm = LoadIcon (hinstance, 100); + wincl.hCursor = NULL;//LoadCursor (NULL, IDC_ARROW); + wincl.lpszMenuName = NULL; /* No menu */ + wincl.cbClsExtra = 0; /* No extra bytes after the window class */ + wincl.cbWndExtra = 0; /* structure or the window instance */ + /* Use Windows's default color as the background of the window */ + wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND; + + /* Register the window class, and if it fails quit the program */ + if (!RegisterClassEx(&wincl)) + return 0; + + wincl.lpszClassName = szSubClassName; + wincl.lpfnWndProc = subWindowProcedure; /* This function is called by windows */ + + if (!RegisterClassEx(&wincl)) + return 0; + + menu = LoadMenu(hThisInstance, TEXT("MainMenu")); + initmenu(); + + /* The class is registered, let's create the program*/ + hwnd = CreateWindowEx ( + 0, /* Extended possibilites for variation */ + szClassName, /* Classname */ + "PCem v11 [Experimental]", /* Title Text */ + WS_OVERLAPPEDWINDOW&~WS_SIZEBOX, /* default window */ + CW_USEDEFAULT, /* Windows decides the position */ + CW_USEDEFAULT, /* where the window ends up on the screen */ + 640+(GetSystemMetrics(SM_CXFIXEDFRAME)*2), /* The programs width */ + 480+(GetSystemMetrics(SM_CYFIXEDFRAME)*2)+GetSystemMetrics(SM_CYMENUSIZE)+GetSystemMetrics(SM_CYCAPTION)+1, /* and height in pixels */ + HWND_DESKTOP, /* The window is a child-window to desktop */ + menu, /* Menu */ + hThisInstance, /* Program Instance handler */ + NULL /* No Window Creation data */ + ); + + /* Make the window visible on the screen */ + ShowWindow (hwnd, nFunsterStil); + +// win_set_window(hwnd); + + memset(rawinputkey, 0, sizeof(rawinputkey)); + device.usUsagePage = 0x01; + device.usUsage = 0x06; + device.dwFlags = RIDEV_NOHOTKEYS; + device.hwndTarget = hwnd; + + if (RegisterRawInputDevices(&device, 1, sizeof(device))) + pclog("Raw input registered!\n"); + else + pclog("Raw input registration failed!\n"); + + get_registry_key_map(); + + ghwnd=hwnd; + + initpc(argc, argv); + + // pclog("Setting video API...\n"); + vid_apis[0][vid_api].init(ghwnd); + + // pclog("Resizing window...\n"); + if (vid_resize) SetWindowLong(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW|WS_VISIBLE); + else SetWindowLong(hwnd, GWL_STYLE, (WS_OVERLAPPEDWINDOW&~WS_SIZEBOX&~WS_THICKFRAME&~WS_MAXIMIZEBOX)|WS_VISIBLE); + + // pclog("Checking CD-ROM menu item...\n"); + if (!cdrom_enabled) + CheckMenuItem(menu, IDM_CDROM_DISABLED, MF_CHECKED); + else + { + if (cdrom_drive == 200) + CheckMenuItem(menu, IDM_CDROM_ISO, MF_CHECKED); + else + CheckMenuItem(menu, IDM_CDROM_REAL + cdrom_drive, MF_CHECKED); + } + // pclog("Checking video resize menu item...\n"); + if (vid_resize) CheckMenuItem(menu, IDM_VID_RESIZE, MF_CHECKED); + // pclog("Checking video API menu item...\n"); + CheckMenuItem(menu, IDM_VID_DDRAW + vid_api, MF_CHECKED); + // pclog("Checking video fill screen menu item...\n"); + CheckMenuItem(menu, IDM_VID_FS_FULL + video_fullscreen_scale, MF_CHECKED); + CheckMenuItem(menu, IDM_VID_REMEMBER, window_remember ? MF_CHECKED : MF_UNCHECKED); +// set_display_switch_mode(SWITCH_BACKGROUND); + + // pclog("Preparing ROM sets...\n"); + d=romset; + for (c=0;c= 0; c--) + { + if (gfx_present[c]) + { + gfxcard = c; + saveconfig(); + resetpchard(); + break; + } + } + } + + loadbios(); + resetpchard(); + + timeBeginPeriod(1); + + atexit(releasemouse); + +// QueryPerformanceFrequency(&counter_base); +/// QueryPerformanceCounter(&counter_posold); +// counter_posold.QuadPart*=100; + + InitializeCriticalSection(&cs); + mainthreadh=(HANDLE)_beginthread(mainthread,0,NULL); + SetThreadPriority(mainthreadh, THREAD_PRIORITY_HIGHEST); + + + updatewindowsize(640, 480); + + QueryPerformanceFrequency(&qpc_freq); + timer_freq = qpc_freq.QuadPart; + +// focus=1; +// setrefresh(100); + +// ShowCursor(TRUE); + + if (start_in_fullscreen) + { + startblit(); + mouse_close(); + vid_apis[0][vid_api].close(); + video_fullscreen = 1; + vid_apis[1][vid_api].init(ghwnd); + mouse_init(); + leave_fullscreen_flag = 0; + endblit(); + device_force_redraw(); + } + if (window_remember) + { + MoveWindow(hwnd, window_x, window_y, + window_w, + window_h, + TRUE); + } + + /* Run the message loop. It will run until GetMessage() returns 0 */ + while (!quited) + { +/* if (infocus) + { + if (drawits) + { + drawits--; + if (drawits>10) drawits=0; + runpc(); + } +//; else +// sleep(0); + // if ((pcem_key[KEY_LCONTROL] || pcem_key[KEY_RCONTROL]) && pcem_key[KEY_END] && mousecapture) + // if ((pcem_key[KEY_LCONTROL] || pcem_key[KEY_RCONTROL]) && pcem_key[0x58] && mousecapture) + // if (pcem_key[0x58] && pcem_key[0x42] && mousecapture) + { + ClipCursor(&oldclip); + mousecapture=0; + } + }*/ + + while (GetMessage(&messages,NULL,0,0) && !quited) + { + if (messages.message==WM_QUIT) quited=1; + TranslateMessage(&messages); + DispatchMessage(&messages); + // if ((pcem_key[KEY_LCONTROL] || pcem_key[KEY_RCONTROL]) && pcem_key[KEY_END] && mousecapture) + if (pcem_key[0x58] && pcem_key[0x42] && mousecapture) + { + ClipCursor(&oldclip); + ShowCursor(TRUE); + mousecapture=0; + } + + if (pcem_key[0x58] && pcem_key[0x41]) + { + // pclog("Taking screenshot...\n"); + take_screenshot(); + } + + if (pcem_key[0x58] && pcem_key[0x44]) + { + pause=1; + Sleep(100); + resetpc_cad(); + pause=0; + } + + if (pcem_key[0x58] && pcem_key[0x43]) + { + pause=1; + Sleep(100); + resetpchard(); + pause=0; + } + +#ifndef RELEASE_BUILD + if (pcem_key[0x57] && pcem_key[0x58]) + { + pclog("Log breakpoint\n"); + } +#endif + + if ((pcem_key[0x1D] || pcem_key[0x9D]) && + (pcem_key[0x38] || pcem_key[0xB8]) && + (pcem_key[0x51] || pcem_key[0xD1]) && + video_fullscreen) + { + leave_fullscreen(); + } + } + + quited=1; +// else +// sleep(10); + } + + startblit(); +// pclog("Sleep 1000\n"); + Sleep(200); +// pclog("TerminateThread\n"); + TerminateThread(mainthreadh,0); +// pclog("Quited? %i\n",quited); +// pclog("Closepc\n"); + if (save_window_pos && window_remember) + saveconfig(); + closepc(); +// pclog("dumpregs\n"); + + vid_apis[video_fullscreen][vid_api].close(); + + timeEndPeriod(1); +// dumpregs(); + if (mousecapture) + { + ClipCursor(&oldclip); + ShowCursor(TRUE); + } + + UnregisterClass(szSubClassName, hinstance); + UnregisterClass(szClassName, hinstance); + +// pclog("Ending! %i %i\n",messages.wParam,quited); + return messages.wParam; +} + +char openfilestring[260]; +int getfile(HWND hwnd, char *f, char *fn) +{ + OPENFILENAME ofn; // common dialog box structure + BOOL r; + DWORD err; + + // Initialize OPENFILENAME + ZeroMemory(&ofn, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = hwnd; + ofn.lpstrFile = openfilestring; + // + // Set lpstrFile[0] to '\0' so that GetOpenFileName does not + // use the contents of szFile to initialize itself. + // +// ofn.lpstrFile[0] = '\0'; + strcpy(ofn.lpstrFile,fn); + ofn.nMaxFile = sizeof(openfilestring); + ofn.lpstrFilter = f;//"All\0*.*\0Text\0*.TXT\0"; + ofn.nFilterIndex = 1; + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = NULL; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; + + // Display the Open dialog box. + + pclog("GetOpenFileName - lpstrFile = %s\n", ofn.lpstrFile); + r = GetOpenFileName(&ofn); + if (r) + { + pclog("GetOpenFileName return true\n"); + return 0; + } + pclog("GetOpenFileName return false\n"); + err = CommDlgExtendedError(); + pclog("CommDlgExtendedError return %04X\n", err); + return 1; +} + +int getsfile(HWND hwnd, char *f, char *fn) +{ + OPENFILENAME ofn; // common dialog box structure + BOOL r; + DWORD err; + + // Initialize OPENFILENAME + ZeroMemory(&ofn, sizeof(ofn)); + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = hwnd; + ofn.lpstrFile = openfilestring; + // + // Set lpstrFile[0] to '\0' so that GetOpenFileName does not + // use the contents of szFile to initialize itself. + // +// ofn.lpstrFile[0] = '\0'; + strcpy(ofn.lpstrFile,fn); + ofn.nMaxFile = sizeof(openfilestring); + ofn.lpstrFilter = f;//"All\0*.*\0Text\0*.TXT\0"; + ofn.nFilterIndex = 1; + ofn.lpstrFileTitle = NULL; + ofn.nMaxFileTitle = 0; + ofn.lpstrInitialDir = NULL; + ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST; + + // Display the Open dialog box. + + pclog("GetSaveFileName - lpstrFile = %s\n", ofn.lpstrFile); + r = GetSaveFileName(&ofn); + if (r) + { + pclog("GetSaveFileName return true\n"); + return 0; + } + pclog("GetSaveFileName return false\n"); + err = CommDlgExtendedError(); + pclog("CommDlgExtendedError return %04X\n", err); + return 1; +} + + + + +HHOOK hKeyboardHook; + +LRESULT CALLBACK LowLevelKeyboardProc( int nCode, WPARAM wParam, LPARAM lParam ) +{ + if (nCode < 0 || nCode != HC_ACTION || (!mousecapture && !video_fullscreen)) + return CallNextHookEx( hKeyboardHook, nCode, wParam, lParam); + + KBDLLHOOKSTRUCT* p = (KBDLLHOOKSTRUCT*)lParam; + + if (p->vkCode == VK_TAB && p->flags & LLKHF_ALTDOWN) return 1; //disable alt-tab + if (p->vkCode == VK_SPACE && p->flags & LLKHF_ALTDOWN) return 1; //disable alt-tab + if((p->vkCode == VK_LWIN) || (p->vkCode == VK_RWIN)) return 1;//disable windows keys + if (p->vkCode == VK_ESCAPE && p->flags & LLKHF_ALTDOWN) return 1;//disable alt-escape + BOOL bControlKeyDown = GetAsyncKeyState (VK_CONTROL) >> ((sizeof(SHORT) * 8) - 1);//checks ctrl key pressed + if (p->vkCode == VK_ESCAPE && bControlKeyDown) return 1; //disable ctrl-escape + + return CallNextHookEx( hKeyboardHook, nCode, wParam, lParam ); +} + +void atapi_close(void) +{ + switch (cdrom_drive) + { + case 0: + null_close(); + break; + default: + ioctl_close(); + break; + case 200: + iso_close(); + break; + } +} + +LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + HMENU hmenu; + RECT rect; + uint32_t ri_size = 0; + char temp_iso_path[1024]; + int new_cdrom_drive; +// pclog("Message %i %08X\n",message,message); + switch (message) + { + case WM_CREATE: + SetTimer(hwnd, TIMER_1SEC, 1000, NULL); + hKeyboardHook = SetWindowsHookEx( WH_KEYBOARD_LL, LowLevelKeyboardProc, GetModuleHandle(NULL), 0 ); + break; + + case WM_COMMAND: +// pclog("WM_COMMAND %i\n",LOWORD(wParam)); + hmenu=GetMenu(hwnd); + switch (LOWORD(wParam)) + { +#if 0 + case IDM_FILE_RESET: + pause=1; + Sleep(100); + resetpc(); + pause=0; + break; +#endif + case IDM_FILE_HRESET: + pause=1; + Sleep(100); + resetpchard(); + pause=0; + break; + case IDM_FILE_RESET_CAD: + pause=1; + Sleep(100); + resetpc_cad(); + pause=0; + break; + case IDM_FILE_EXIT: + PostQuitMessage (0); /* send a WM_QUIT to the message queue */ + break; + case IDM_DISC_A: + if (!getfile(hwnd,"Disc image (*.IMG;*.IMA;*.FDI)\0*.IMG;*.IMA;*.FDI\0All files (*.*)\0*.*\0",discfns[0])) + { + disc_close(0); + disc_load(0, openfilestring); + saveconfig(); + } + break; + case IDM_DISC_B: + if (!getfile(hwnd,"Disc image (*.IMG;*.IMA;*.FDI)\0*.IMG;*.IMA;*.FDI\0All files (*.*)\0*.*\0",discfns[1])) + { + disc_close(1); + disc_load(1, openfilestring); + saveconfig(); + } + break; + case IDM_EJECT_A: + disc_close(0); + saveconfig(); + break; + case IDM_EJECT_B: + disc_close(1); + saveconfig(); + break; + case IDM_HDCONF: + hdconf_open(hwnd); + break; + case IDM_CONFIG: + config_open(hwnd); + break; + case IDM_STATUS: + status_open(hwnd); + break; + + case IDM_VID_RESIZE: + vid_resize=!vid_resize; + CheckMenuItem(hmenu, IDM_VID_RESIZE, (vid_resize)?MF_CHECKED:MF_UNCHECKED); + if (vid_resize) SetWindowLong(hwnd, GWL_STYLE, WS_OVERLAPPEDWINDOW|WS_VISIBLE); + else SetWindowLong(hwnd, GWL_STYLE, (WS_OVERLAPPEDWINDOW&~WS_SIZEBOX&~WS_THICKFRAME&~WS_MAXIMIZEBOX)|WS_VISIBLE); + GetWindowRect(hwnd,&rect); + SetWindowPos(hwnd, 0, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_FRAMECHANGED); + saveconfig(); + break; + case IDM_VID_REMEMBER: + window_remember = !window_remember; + CheckMenuItem(hmenu, IDM_VID_REMEMBER, window_remember ? MF_CHECKED : MF_UNCHECKED); + GetWindowRect(hwnd, &rect); + if (window_remember) + { + window_x = rect.left; + window_y = rect.top; + window_w = rect.right - rect.left; + window_h = rect.bottom - rect.top; + } + saveconfig(); + break; + + case IDM_VID_DDRAW: case IDM_VID_D3D: + startblit(); + CheckMenuItem(hmenu, IDM_VID_DDRAW + vid_api, MF_UNCHECKED); + vid_apis[0][vid_api].close(); + vid_api = LOWORD(wParam) - IDM_VID_DDRAW; + CheckMenuItem(hmenu, IDM_VID_DDRAW + vid_api, MF_CHECKED); + vid_apis[0][vid_api].init(ghwnd); + endblit(); + saveconfig(); + device_force_redraw(); + break; + + case IDM_VID_FULLSCREEN: + if (video_fullscreen_first) + { + video_fullscreen_first = 0; + MessageBox(hwnd, "Use CTRL + ALT + PAGE DOWN to return to windowed mode", "PCem", MB_OK); + } + startblit(); + mouse_close(); + vid_apis[0][vid_api].close(); + video_fullscreen = 1; + vid_apis[1][vid_api].init(ghwnd); + mouse_init(); + leave_fullscreen_flag = 0; + endblit(); + device_force_redraw(); + break; + + case IDM_VID_FS_FULL: + case IDM_VID_FS_43: + case IDM_VID_FS_SQ: + case IDM_VID_FS_INT: + CheckMenuItem(hmenu, IDM_VID_FS_FULL + video_fullscreen_scale, MF_UNCHECKED); + video_fullscreen_scale = LOWORD(wParam) - IDM_VID_FS_FULL; + CheckMenuItem(hmenu, IDM_VID_FS_FULL + video_fullscreen_scale, MF_CHECKED); + saveconfig(); + break; + + case IDM_CONFIG_LOAD: + pause = 1; + if (!getfile(hwnd, "Configuration (*.CFG)\0*.CFG\0All files (*.*)\0*.*\0", "")) + { + if (MessageBox(NULL, "This will reset PCem!\nOkay to continue?", "PCem", MB_OKCANCEL) == IDOK) + { + loadconfig(openfilestring); + config_save(config_file_default); + mem_resize(); + loadbios(); + resetpchard(); + } + } + pause = 0; + break; + + case IDM_CONFIG_SAVE: + pause = 1; + if (!getsfile(hwnd, "Configuration (*.CFG)\0*.CFG\0All files (*.*)\0*.*\0", "")) + config_save(openfilestring); + pause = 0; + break; + + case IDM_CDROM_DISABLED: + if (cdrom_enabled) + { + if (MessageBox(NULL,"This will reset PCem!\nOkay to continue?","PCem",MB_OKCANCEL) != IDOK) + break; + } + if (!cdrom_enabled) + { + /* Switching from disabled to disabled. Do nothing. */ + break; + } + atapi->exit(); + atapi_close(); + cdrom_null_open(0); + CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_CDROM_DISABLED, MF_CHECKED); + CheckMenuItem(hmenu, IDM_CDROM_ISO, MF_UNCHECKED); + old_cdrom_drive = cdrom_drive; + cdrom_drive=0; + CheckMenuItem(hmenu, IDM_CDROM_EMPTY, MF_UNCHECKED); + if (cdrom_enabled) + { + pause = 1; + Sleep(100); + cdrom_enabled = 0; + saveconfig(); + resetpchard(); + pause = 0; + } + break; + + case IDM_CDROM_EMPTY: + if (!cdrom_enabled) + { + if (MessageBox(NULL,"This will reset PCem!\nOkay to continue?","PCem",MB_OKCANCEL) != IDOK) + break; + } + if ((cdrom_drive == 0) && cdrom_enabled) + { + /* Switch from empty to empty. Do nothing. */ + break; + } + atapi->exit(); + atapi_close(); + cdrom_null_open(0); + if (cdrom_enabled) + { + /* Signal disc change to the emulated machine. */ + atapi_insert_cdrom(); + } + CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_CDROM_DISABLED, MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_CDROM_ISO, MF_UNCHECKED); + old_cdrom_drive = cdrom_drive; + cdrom_drive=0; + CheckMenuItem(hmenu, IDM_CDROM_EMPTY, MF_CHECKED); + saveconfig(); + if (!cdrom_enabled) + { + pause = 1; + Sleep(100); + cdrom_enabled = 1; + saveconfig(); + resetpchard(); + pause = 0; + } + break; + + case IDM_CDROM_ISO: + if (!getfile(hwnd,"CD-ROM image (*.ISO)\0*.ISO\0All files (*.*)\0*.*\0",iso_path)) + { + if (!cdrom_enabled) + { + if (MessageBox(NULL,"This will reset PCem!\nOkay to continue?","PCem",MB_OKCANCEL) != IDOK) + break; + } + old_cdrom_drive = cdrom_drive; + strcpy(temp_iso_path, openfilestring); + if ((strcmp(iso_path, temp_iso_path) == 0) && (cdrom_drive == 200) && cdrom_enabled) + { + /* Switching from ISO to the same ISO. Do nothing. */ + break; + } + atapi->exit(); + atapi_close(); + iso_open(temp_iso_path); + if (cdrom_enabled) + { + /* Signal disc change to the emulated machine. */ + atapi_insert_cdrom(); + } + CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_CDROM_DISABLED, MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_CDROM_ISO, MF_UNCHECKED); + cdrom_drive = 200; + CheckMenuItem(hmenu, IDM_CDROM_ISO, MF_CHECKED); + saveconfig(); + if (!cdrom_enabled) + { + pause = 1; + Sleep(100); + cdrom_enabled = 1; + saveconfig(); + resetpchard(); + pause = 0; + } + } + break; + + default: + if (LOWORD(wParam)>IDM_CDROM_REAL && LOWORD(wParam)<(IDM_CDROM_REAL+100)) + { + if (!cdrom_enabled) + { + if (MessageBox(NULL,"This will reset PCem!\nOkay to continue?","PCem",MB_OKCANCEL) != IDOK) + break; + } + new_cdrom_drive = LOWORD(wParam)-IDM_CDROM_REAL; + if ((cdrom_drive == new_cdrom_drive) && cdrom_enabled) + { + /* Switching to the same drive. Do nothing. */ + break; + } + old_cdrom_drive = cdrom_drive; + atapi->exit(); + atapi_close(); + ioctl_open(new_cdrom_drive); + if (cdrom_enabled) + { + /* Signal disc change to the emulated machine. */ + atapi_insert_cdrom(); + } + CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_CDROM_DISABLED, MF_UNCHECKED); + CheckMenuItem(hmenu, IDM_CDROM_ISO, MF_UNCHECKED); + cdrom_drive = new_cdrom_drive; + CheckMenuItem(hmenu, IDM_CDROM_REAL + cdrom_drive, MF_CHECKED); + saveconfig(); + if (!cdrom_enabled) + { + pause = 1; + Sleep(100); + cdrom_enabled = 1; + saveconfig(); + resetpchard(); + pause = 0; + } + } + break; + } + return 0; + + case WM_INPUT: + { + UINT size; + RAWINPUT *raw; + + if (!infocus) + break; + + GetRawInputData((HRAWINPUT)lParam, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER)); + + raw = malloc(size); + + if (raw == NULL) + { + return 0; + } + + /* Here we read the raw input data for the keyboard */ + ri_size = GetRawInputData((HRAWINPUT)(lParam), RID_INPUT, raw, &size, sizeof(RAWINPUTHEADER)); + + if(ri_size != size) + { + return 0; + } + + /* If the input is keyboard, we process it */ + if (raw->header.dwType == RIM_TYPEKEYBOARD) + { + const RAWKEYBOARD rawKB = raw->data.keyboard; + USHORT scancode = rawKB.MakeCode; + + // pclog("Keyboard input received: S:%X VK:%X F:%X\n", c, d, e); + + /* If it's not a scan code that starts with 0xE1 */ + if (!(rawKB.Flags & RI_KEY_E1)) + { + // pclog("Non-E1 triggered, make code is %04X\n", rawKB.MakeCode); + if (rawKB.Flags & RI_KEY_E0) + scancode |= (0xE0 << 8); + + /* Remap it according to the list from the Registry */ + scancode = scancode_map[scancode]; + + if ((scancode >> 8) == 0xF0) + scancode |= 0x100; /* Extended key code in disambiguated format */ + else if ((scancode >> 8) == 0xE0) + scancode |= 0x80; /* Normal extended key code */ + + /* If it's not 0 (therefore not 0xE1, 0xE2, etc), + then pass it on to the rawinputkey array */ + if (!(scancode & 0xf00)) + { + rawinputkey[scancode & 0x1ff] = !(rawKB.Flags & RI_KEY_BREAK); + pcem_key[scancode & 0x1ff] = rawinputkey[scancode & 0x1ff]; + } + } + else + { + // pclog("E1 triggered, make code is %04X\n", rawKB.MakeCode); + if (rawKB.MakeCode == 0x1D) + scancode = 0xFF; + if (!(scancode & 0xf00)) + { + rawinputkey[scancode & 0x1ff] = !(rawKB.Flags & RI_KEY_BREAK); + pcem_key[scancode & 0x1ff] = rawinputkey[scancode & 0x1ff]; + } + } + } + free(raw); + + } + break; + + case WM_SETFOCUS: + infocus=1; + // QueryPerformanceCounter(&counter_posold); +// pclog("Set focus!\n"); + break; + case WM_KILLFOCUS: + infocus=0; + if (mousecapture) + { + ClipCursor(&oldclip); + ShowCursor(TRUE); + mousecapture=0; + } +// pclog("Lost focus!\n"); + memset(rawinputkey, 0, sizeof(rawinputkey)); + if (video_fullscreen) + leave_fullscreen_flag = 1; + break; + + case WM_LBUTTONUP: + if (!mousecapture && !video_fullscreen) + { + RECT pcclip; + + GetClipCursor(&oldclip); + GetWindowRect(hwnd, &pcclip); + pcclip.left += GetSystemMetrics(SM_CXFIXEDFRAME) + 10; + pcclip.right -= GetSystemMetrics(SM_CXFIXEDFRAME) + 10; + pcclip.top += GetSystemMetrics(SM_CXFIXEDFRAME) + GetSystemMetrics(SM_CYMENUSIZE) + GetSystemMetrics(SM_CYCAPTION) + 10; + pcclip.bottom -= GetSystemMetrics(SM_CXFIXEDFRAME) + 10; + ClipCursor(&pcclip); + mousecapture = 1; +// ShowCursor(FALSE); + while (1) + { + if (ShowCursor(FALSE) < 0) break; + } + } + break; + + case WM_MBUTTONUP: + releasemouse(); + break; + + case WM_ENTERMENULOOP: +// if (key[KEY_ALT] || key[KEY_ALTGR]) return 0; + break; + + case WM_SIZE: + winsizex=lParam&0xFFFF; + winsizey=lParam>>16; + + if (vid_apis[video_fullscreen][vid_api].resize) + { + startblit(); + vid_apis[video_fullscreen][vid_api].resize(winsizex, winsizey); + endblit(); + } + + if (mousecapture) + { + RECT pcclip; + + GetWindowRect(hwnd, &pcclip); + pcclip.left += GetSystemMetrics(SM_CXFIXEDFRAME) + 10; + pcclip.right -= GetSystemMetrics(SM_CXFIXEDFRAME) + 10; + pcclip.top += GetSystemMetrics(SM_CXFIXEDFRAME) + GetSystemMetrics(SM_CYMENUSIZE) + GetSystemMetrics(SM_CYCAPTION) + 10; + pcclip.bottom -= GetSystemMetrics(SM_CXFIXEDFRAME) + 10; + ClipCursor(&pcclip); + } + if (window_remember) + { + GetWindowRect(hwnd, &rect); + window_x = rect.left; + window_y = rect.top; + window_w = rect.right - rect.left; + window_h = rect.bottom - rect.top; + save_window_pos = 1; + } + break; + + case WM_MOVE: + if (window_remember) + { + GetWindowRect(hwnd, &rect); + window_x = rect.left; + window_y = rect.top; + window_w = rect.right - rect.left; + window_h = rect.bottom - rect.top; + save_window_pos = 1; + } + break; + + case WM_TIMER: + if (wParam == TIMER_1SEC) + onesec(); + break; + + case WM_RESETD3D: + startblit(); + if (video_fullscreen) + d3d_fs_reset(); + else + d3d_reset(); + endblit(); + break; + + case WM_LEAVEFULLSCREEN: + startblit(); + mouse_close(); + vid_apis[1][vid_api].close(); + video_fullscreen = 0; + vid_apis[0][vid_api].init(ghwnd); + mouse_init(); + endblit(); + device_force_redraw(); + break; + + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + case WM_KEYUP: + case WM_SYSKEYUP: +// if (mousecapture) + return 0; +// return DefWindowProc (hwnd, message, wParam, lParam); + + + case WM_DESTROY: + UnhookWindowsHookEx( hKeyboardHook ); + KillTimer(hwnd, TIMER_1SEC); + PostQuitMessage (0); /* send a WM_QUIT to the message queue */ + break; + + case WM_SYSCOMMAND: + if (wParam == SC_KEYMENU && HIWORD(lParam) <= 0 && (video_fullscreen || mousecapture)) + return 0; /*disable ALT key for menu*/ + + default: +// pclog("Def %08X %i\n",message,message); + return DefWindowProc (hwnd, message, wParam, lParam); + } + return 0; +} + +LRESULT CALLBACK subWindowProcedure(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + default: + return DefWindowProc(hwnd, message, wParam, lParam); + } + return 0; +} diff --git a/src/win.h b/src/win.h new file mode 100644 index 000000000..4aff67266 --- /dev/null +++ b/src/win.h @@ -0,0 +1,35 @@ +extern HINSTANCE hinstance; +extern HWND ghwnd; +extern int mousecapture; + +#ifdef __cplusplus +extern "C" { +#endif + +#define szClassName "PCemMainWnd" +#define szSubClassName "PCemSubWnd" + +void leave_fullscreen(); + +#ifdef __cplusplus +} +#endif + + +void status_open(HWND hwnd); +extern HWND status_hwnd; +extern int status_is_open; + +void hdconf_open(HWND hwnd); + +void config_open(HWND hwnd); + +void deviceconfig_open(HWND hwnd, struct device_t *device); +void joystickconfig_open(HWND hwnd, int joy_nr, int type); + +extern char openfilestring[260]; + +int getfile(HWND hwnd, char *f, char *fn); +int getsfile(HWND hwnd, char *f, char *fn); + +extern int pause; diff --git a/src/x86.h b/src/x86.h new file mode 100644 index 000000000..ecd929faf --- /dev/null +++ b/src/x86.h @@ -0,0 +1,108 @@ +uint16_t oldcs; +uint32_t oldpc; +extern uint32_t rmdat32; +int oldcpl; + +extern int nmi_enable; + +int tempc; +int cycles,output; +int ssegs; +int firstrepcycle; + +uint32_t easeg,eaaddr,ealimit,ealimitw; +int rm,reg,mod,rmdat; + +int skipnextprint; +int inhlt; + +uint8_t opcode; +int ins,noint; + +uint16_t lastcs,lastpc; +int timetolive,keyboardtimer; + +#define setznp168 setznp16 + +#define getr8(r) ((r&4)?cpu_state.regs[r&3].b.h:cpu_state.regs[r&3].b.l) +#define getr16(r) cpu_state.regs[r].w +#define getr32(r) cpu_state.regs[r].l + +#define setr8(r,v) if (r&4) cpu_state.regs[r&3].b.h=v; \ + else cpu_state.regs[r&3].b.l=v; +#define setr16(r,v) cpu_state.regs[r].w=v +#define setr32(r,v) cpu_state.regs[r].l=v + +uint8_t znptable8[256]; +uint16_t znptable16[65536]; + +int use32; +int stack32; + +#define fetchea() { rmdat=readmemb(cs+pc); pc++; \ + reg=(rmdat>>3)&7; \ + mod=(rmdat>>6)&3; \ + rm=rmdat&7; \ + if (mod!=3) fetcheal(); } + + +int optype; +#define JMP 1 +#define CALL 2 +#define IRET 3 +#define OPTYPE_INT 4 + +uint32_t oxpc; + +extern uint16_t *mod1add[2][8]; +extern uint32_t *mod1seg[8]; + + +#define IRQTEST ((flags&I_FLAG) && (pic.pend&~pic.mask) && !noint) + +extern int cgate32; + + +extern uint32_t *eal_r, *eal_w; + + +extern uint32_t flags_zn; +extern uint8_t flags_p; +#define FLAG_N (flags_zn>>31) +#define FLAG_Z (flags_zn) +#define FLAG_P (znptable8[flags_p]&P_FLAG) + +extern int gpf; + + +enum +{ + ABRT_NONE = 0, + ABRT_GEN, + ABRT_TS = 0xA, + ABRT_NP = 0xB, + ABRT_SS = 0xC, + ABRT_GPF = 0xD, + ABRT_PF = 0xE +}; + +extern int abrt; +extern uint32_t abrt_error; + +void x86_doabrt(int x86_abrt); + +extern uint8_t opcode2; + +extern uint16_t rds; +extern uint32_t rmdat32; + +extern int inscounts[256]; + +void x86illegal(); + +void x86seg_reset(); +void x86gpf(char *s, uint16_t error); + +extern uint16_t zero; + +extern int x86_was_reset; diff --git a/src/x86_flags.h b/src/x86_flags.h new file mode 100644 index 000000000..d663fd464 --- /dev/null +++ b/src/x86_flags.h @@ -0,0 +1,507 @@ +enum +{ + FLAGS_UNKNOWN, + + FLAGS_ZN8, + FLAGS_ZN16, + FLAGS_ZN32, + + FLAGS_ADD8, + FLAGS_ADD16, + FLAGS_ADD32, + + FLAGS_SUB8, + FLAGS_SUB16, + FLAGS_SUB32, + + FLAGS_SHL8, + FLAGS_SHL16, + FLAGS_SHL32, + + FLAGS_SHR8, + FLAGS_SHR16, + FLAGS_SHR32, + + FLAGS_SAR8, + FLAGS_SAR16, + FLAGS_SAR32, + + FLAGS_INC8, + FLAGS_INC16, + FLAGS_INC32, + + FLAGS_DEC8, + FLAGS_DEC16, + FLAGS_DEC32, +}; + +static inline int ZF_SET() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + case FLAGS_ADD8: + case FLAGS_ADD16: + case FLAGS_ADD32: + case FLAGS_SUB8: + case FLAGS_SUB16: + case FLAGS_SUB32: + case FLAGS_SHL8: + case FLAGS_SHL16: + case FLAGS_SHL32: + case FLAGS_SHR8: + case FLAGS_SHR16: + case FLAGS_SHR32: + case FLAGS_SAR8: + case FLAGS_SAR16: + case FLAGS_SAR32: + case FLAGS_INC8: + case FLAGS_INC16: + case FLAGS_INC32: + case FLAGS_DEC8: + case FLAGS_DEC16: + case FLAGS_DEC32: + return !cpu_state.flags_res; + + case FLAGS_UNKNOWN: + return flags & Z_FLAG; + } +} + +static inline int NF_SET() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ADD8: + case FLAGS_SUB8: + case FLAGS_SHL8: + case FLAGS_SHR8: + case FLAGS_SAR8: + case FLAGS_INC8: + case FLAGS_DEC8: + return cpu_state.flags_res & 0x80; + + case FLAGS_ZN16: + case FLAGS_ADD16: + case FLAGS_SUB16: + case FLAGS_SHL16: + case FLAGS_SHR16: + case FLAGS_SAR16: + case FLAGS_INC16: + case FLAGS_DEC16: + return cpu_state.flags_res & 0x8000; + + case FLAGS_ZN32: + case FLAGS_ADD32: + case FLAGS_SUB32: + case FLAGS_SHL32: + case FLAGS_SHR32: + case FLAGS_SAR32: + case FLAGS_INC32: + case FLAGS_DEC32: + return cpu_state.flags_res & 0x80000000; + + case FLAGS_UNKNOWN: + return flags & N_FLAG; + } +} + +static inline int PF_SET() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + case FLAGS_ADD8: + case FLAGS_ADD16: + case FLAGS_ADD32: + case FLAGS_SUB8: + case FLAGS_SUB16: + case FLAGS_SUB32: + case FLAGS_SHL8: + case FLAGS_SHL16: + case FLAGS_SHL32: + case FLAGS_SHR8: + case FLAGS_SHR16: + case FLAGS_SHR32: + case FLAGS_SAR8: + case FLAGS_SAR16: + case FLAGS_SAR32: + case FLAGS_INC8: + case FLAGS_INC16: + case FLAGS_INC32: + case FLAGS_DEC8: + case FLAGS_DEC16: + case FLAGS_DEC32: + return znptable8[cpu_state.flags_res & 0xff] & P_FLAG; + + case FLAGS_UNKNOWN: + return flags & P_FLAG; + } +} + +static inline int VF_SET() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + case FLAGS_SAR8: + case FLAGS_SAR16: + case FLAGS_SAR32: + return 0; + + case FLAGS_ADD8: + case FLAGS_INC8: + return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x80) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80); + case FLAGS_ADD16: + case FLAGS_INC16: + return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x8000) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x8000); + case FLAGS_ADD32: + case FLAGS_INC32: + return !((cpu_state.flags_op1 ^ cpu_state.flags_op2) & 0x80000000) && ((cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80000000); + + case FLAGS_SUB8: + case FLAGS_DEC8: + return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80); + case FLAGS_SUB16: + case FLAGS_DEC16: + return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x8000); + case FLAGS_SUB32: + case FLAGS_DEC32: + return ((cpu_state.flags_op1 ^ cpu_state.flags_op2) & (cpu_state.flags_op1 ^ cpu_state.flags_res) & 0x80000000); + + case FLAGS_SHL8: + return (((cpu_state.flags_op1 << cpu_state.flags_op2) ^ (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1))) & 0x80); + case FLAGS_SHL16: + return (((cpu_state.flags_op1 << cpu_state.flags_op2) ^ (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1))) & 0x8000); + case FLAGS_SHL32: + return (((cpu_state.flags_op1 << cpu_state.flags_op2) ^ (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1))) & 0x80000000); + + case FLAGS_SHR8: + return ((cpu_state.flags_op2 == 1) && (cpu_state.flags_op1 & 0x80)); + case FLAGS_SHR16: + return ((cpu_state.flags_op2 == 1) && (cpu_state.flags_op1 & 0x8000)); + case FLAGS_SHR32: + return ((cpu_state.flags_op2 == 1) && (cpu_state.flags_op1 & 0x80000000)); + + case FLAGS_UNKNOWN: + return flags & V_FLAG; + } +} + +static inline int AF_SET() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + case FLAGS_SHL8: + case FLAGS_SHL16: + case FLAGS_SHL32: + case FLAGS_SHR8: + case FLAGS_SHR16: + case FLAGS_SHR32: + case FLAGS_SAR8: + case FLAGS_SAR16: + case FLAGS_SAR32: + return 0; + + case FLAGS_ADD8: + case FLAGS_ADD16: + case FLAGS_ADD32: + case FLAGS_INC8: + case FLAGS_INC16: + case FLAGS_INC32: + return ((cpu_state.flags_op1 & 0xF) + (cpu_state.flags_op2 & 0xF)) & 0x10; + + case FLAGS_SUB8: + case FLAGS_SUB16: + case FLAGS_SUB32: + case FLAGS_DEC8: + case FLAGS_DEC16: + case FLAGS_DEC32: + return ((cpu_state.flags_op1 & 0xF) - (cpu_state.flags_op2 & 0xF)) & 0x10; + + case FLAGS_UNKNOWN: + return flags & A_FLAG; + } +} + +static inline int CF_SET() +{ + switch (cpu_state.flags_op) + { + case FLAGS_ADD8: + return (cpu_state.flags_op1 + cpu_state.flags_op2) & 0x100; + case FLAGS_ADD16: + return (cpu_state.flags_op1 + cpu_state.flags_op2) & 0x10000; + case FLAGS_ADD32: + return (cpu_state.flags_res < cpu_state.flags_op1); + + case FLAGS_SUB8: + case FLAGS_SUB16: + case FLAGS_SUB32: + return (cpu_state.flags_op1 < cpu_state.flags_op2); + + case FLAGS_SHL8: + return (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x80; + case FLAGS_SHL16: + return (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x8000; + case FLAGS_SHL32: + return (cpu_state.flags_op1 << (cpu_state.flags_op2 - 1)) & 0x80000000; + + case FLAGS_SHR8: + case FLAGS_SHR16: + case FLAGS_SHR32: + return (cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; + + case FLAGS_SAR8: + return ((int8_t)cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; + case FLAGS_SAR16: + return ((int16_t)cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; + case FLAGS_SAR32: + return ((int32_t)cpu_state.flags_op1 >> (cpu_state.flags_op2 - 1)) & 1; + + case FLAGS_ZN8: + case FLAGS_ZN16: + case FLAGS_ZN32: + return 0; + + case FLAGS_DEC8: + case FLAGS_DEC16: + case FLAGS_DEC32: + case FLAGS_INC8: + case FLAGS_INC16: + case FLAGS_INC32: + case FLAGS_UNKNOWN: + return flags & C_FLAG; + } +} + +//#define ZF_SET() (flags & Z_FLAG) +//#define NF_SET() (flags & N_FLAG) +//#define PF_SET() (flags & P_FLAG) +//#define VF_SET() (flags & V_FLAG) +//#define CF_SET() (flags & C_FLAG) +//#define AF_SET() (flags & A_FLAG) + +static inline void flags_rebuild() +{ + if (cpu_state.flags_op != FLAGS_UNKNOWN) + { + uint16_t tempf = 0; + if (CF_SET()) tempf |= C_FLAG; + if (PF_SET()) tempf |= P_FLAG; + if (AF_SET()) tempf |= A_FLAG; + if (ZF_SET()) tempf |= Z_FLAG; + if (NF_SET()) tempf |= N_FLAG; + if (VF_SET()) tempf |= V_FLAG; + flags = (flags & ~0x8d5) | tempf; + cpu_state.flags_op = FLAGS_UNKNOWN; + } +} + +static inline void flags_extract() +{ + cpu_state.flags_op = FLAGS_UNKNOWN; +} + +static inline void flags_rebuild_c() +{ + if (cpu_state.flags_op != FLAGS_UNKNOWN) + { + if (CF_SET()) + flags |= C_FLAG; + else + flags &= ~C_FLAG; + } +} + +static inline void setznp8(uint8_t val) +{ + cpu_state.flags_op = FLAGS_ZN8; + cpu_state.flags_res = val; +} +static inline void setznp16(uint16_t val) +{ + cpu_state.flags_op = FLAGS_ZN16; + cpu_state.flags_res = val; +} +static inline void setznp32(uint32_t val) +{ + cpu_state.flags_op = FLAGS_ZN32; + cpu_state.flags_res = val; +} + +#define set_flags_shift(op, orig, shift, res) \ + cpu_state.flags_op = op; \ + cpu_state.flags_res = res; \ + cpu_state.flags_op1 = orig; \ + cpu_state.flags_op2 = shift; + +static inline void setadd8(uint8_t a, uint8_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a + b) & 0xff; + cpu_state.flags_op = FLAGS_ADD8; +} +static inline void setadd16(uint16_t a, uint16_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a + b) & 0xffff; + cpu_state.flags_op = FLAGS_ADD16; +} +static inline void setadd32(uint32_t a, uint32_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = a + b; + cpu_state.flags_op = FLAGS_ADD32; +} +static inline void setadd8nc(uint8_t a, uint8_t b) +{ + flags_rebuild_c(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a + b) & 0xff; + cpu_state.flags_op = FLAGS_INC8; +} +static inline void setadd16nc(uint16_t a, uint16_t b) +{ + flags_rebuild_c(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a + b) & 0xffff; + cpu_state.flags_op = FLAGS_INC16; +} +static inline void setadd32nc(uint32_t a, uint32_t b) +{ + flags_rebuild_c(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = a + b; + cpu_state.flags_op = FLAGS_INC32; +} + +static inline void setsub8(uint8_t a, uint8_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a - b) & 0xff; + cpu_state.flags_op = FLAGS_SUB8; +} +static inline void setsub16(uint16_t a, uint16_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a - b) & 0xffff; + cpu_state.flags_op = FLAGS_SUB16; +} +static inline void setsub32(uint32_t a, uint32_t b) +{ + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = a - b; + cpu_state.flags_op = FLAGS_SUB32; +} + +static inline void setsub8nc(uint8_t a, uint8_t b) +{ + flags_rebuild_c(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a - b) & 0xff; + cpu_state.flags_op = FLAGS_DEC8; +} +static inline void setsub16nc(uint16_t a, uint16_t b) +{ + flags_rebuild_c(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = (a - b) & 0xffff; + cpu_state.flags_op = FLAGS_DEC16; +} +static inline void setsub32nc(uint32_t a, uint32_t b) +{ + flags_rebuild_c(); + cpu_state.flags_op1 = a; + cpu_state.flags_op2 = b; + cpu_state.flags_res = a - b; + cpu_state.flags_op = FLAGS_DEC32; +} + +static inline void setadc8(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a+(uint16_t)b+tempc; + cpu_state.flags_op = FLAGS_UNKNOWN; + flags&=~0x8D5; + flags|=znptable8[c&0xFF]; + if (c&0x100) flags|=C_FLAG; + if (!((a^b)&0x80)&&((a^c)&0x80)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} +static inline void setadc16(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a+(uint32_t)b+tempc; + cpu_state.flags_op = FLAGS_UNKNOWN; + flags&=~0x8D5; + flags|=znptable16[c&0xFFFF]; + if (c&0x10000) flags|=C_FLAG; + if (!((a^b)&0x8000)&&((a^c)&0x8000)) flags|=V_FLAG; + if (((a&0xF)+(b&0xF))&0x10) flags|=A_FLAG; +} + +static inline void setsbc8(uint8_t a, uint8_t b) +{ + uint16_t c=(uint16_t)a-(((uint16_t)b)+tempc); + cpu_state.flags_op = FLAGS_UNKNOWN; + flags&=~0x8D5; + flags|=znptable8[c&0xFF]; + if (c&0x100) flags|=C_FLAG; + if ((a^b)&(a^c)&0x80) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} +static inline void setsbc16(uint16_t a, uint16_t b) +{ + uint32_t c=(uint32_t)a-(((uint32_t)b)+tempc); + cpu_state.flags_op = FLAGS_UNKNOWN; + flags&=~0x8D5; + flags|=(znptable16[c&0xFFFF]&~4); + flags|=(znptable8[c&0xFF]&4); + if (c&0x10000) flags|=C_FLAG; + if ((a^b)&(a^c)&0x8000) flags|=V_FLAG; + if (((a&0xF)-(b&0xF))&0x10) flags|=A_FLAG; +} + +static inline void setadc32(uint32_t a, uint32_t b) +{ + uint32_t c=(uint32_t)a+(uint32_t)b+tempc; + cpu_state.flags_op = FLAGS_UNKNOWN; + flags&=~0x8D5; + flags|=((c&0x80000000)?N_FLAG:((!c)?Z_FLAG:0)); + flags|=(znptable8[c&0xFF]&P_FLAG); + if ((ca) || (c==a && tempc)) flags|=C_FLAG; + if ((a^b)&(a^c)&0x80000000) flags|=V_FLAG; + if (((a&0xF)-((b&0xF)+tempc))&0x10) flags|=A_FLAG; +} + diff --git a/src/x86_ops.h b/src/x86_ops.h new file mode 100644 index 000000000..279f62bbf --- /dev/null +++ b/src/x86_ops.h @@ -0,0 +1,138 @@ +#ifndef _X86_OPS_H +#define _X86_OPS_H + +typedef int (*OpFn)(uint32_t fetchdat); + +void x86_setopcodes(OpFn *opcodes, OpFn *opcodes_0f, OpFn *dynarec_opcodes, OpFn *dynarec_opcodes_0f); + +extern OpFn *x86_dynarec_opcodes; +extern OpFn *x86_dynarec_opcodes_0f; +extern OpFn *x86_dynarec_opcodes_d8_a16; +extern OpFn *x86_dynarec_opcodes_d8_a32; +extern OpFn *x86_dynarec_opcodes_d9_a16; +extern OpFn *x86_dynarec_opcodes_d9_a32; +extern OpFn *x86_dynarec_opcodes_da_a16; +extern OpFn *x86_dynarec_opcodes_da_a32; +extern OpFn *x86_dynarec_opcodes_db_a16; +extern OpFn *x86_dynarec_opcodes_db_a32; +extern OpFn *x86_dynarec_opcodes_dc_a16; +extern OpFn *x86_dynarec_opcodes_dc_a32; +extern OpFn *x86_dynarec_opcodes_dd_a16; +extern OpFn *x86_dynarec_opcodes_dd_a32; +extern OpFn *x86_dynarec_opcodes_de_a16; +extern OpFn *x86_dynarec_opcodes_de_a32; +extern OpFn *x86_dynarec_opcodes_df_a16; +extern OpFn *x86_dynarec_opcodes_df_a32; + +extern OpFn dynarec_ops_286[1024]; +extern OpFn dynarec_ops_286_0f[1024]; + +extern OpFn dynarec_ops_386[1024]; +extern OpFn dynarec_ops_386_0f[1024]; + +extern OpFn dynarec_ops_486_0f[1024]; + +extern OpFn dynarec_ops_winchip_0f[1024]; + +extern OpFn dynarec_ops_pentium_0f[1024]; +extern OpFn dynarec_ops_pentiummmx_0f[1024]; + +extern OpFn dynarec_ops_k6_0f[1024]; + +extern OpFn dynarec_ops_c6x86mx_0f[1024]; +extern OpFn dynarec_ops_pentiumpro_0f[1024]; +extern OpFn dynarec_ops_pentium2_0f[1024]; +extern OpFn dynarec_ops_pentium2d_0f[1024]; + +extern OpFn dynarec_ops_fpu_d8_a16[32]; +extern OpFn dynarec_ops_fpu_d8_a32[32]; +extern OpFn dynarec_ops_fpu_d9_a16[256]; +extern OpFn dynarec_ops_fpu_d9_a32[256]; +extern OpFn dynarec_ops_fpu_da_a16[256]; +extern OpFn dynarec_ops_fpu_da_a32[256]; +extern OpFn dynarec_ops_fpu_db_a16[256]; +extern OpFn dynarec_ops_fpu_db_a32[256]; +extern OpFn dynarec_ops_fpu_dc_a16[32]; +extern OpFn dynarec_ops_fpu_dc_a32[32]; +extern OpFn dynarec_ops_fpu_dd_a16[256]; +extern OpFn dynarec_ops_fpu_dd_a32[256]; +extern OpFn dynarec_ops_fpu_de_a16[256]; +extern OpFn dynarec_ops_fpu_de_a32[256]; +extern OpFn dynarec_ops_fpu_df_a16[256]; +extern OpFn dynarec_ops_fpu_df_a32[256]; +extern OpFn dynarec_ops_nofpu_a16[256]; +extern OpFn dynarec_ops_nofpu_a32[256]; + +extern OpFn dynarec_ops_fpu_686_da_a16[256]; +extern OpFn dynarec_ops_fpu_686_da_a32[256]; +extern OpFn dynarec_ops_fpu_686_db_a16[256]; +extern OpFn dynarec_ops_fpu_686_db_a32[256]; +extern OpFn dynarec_ops_fpu_686_df_a16[256]; +extern OpFn dynarec_ops_fpu_686_df_a32[256]; + +extern OpFn *x86_opcodes; +extern OpFn *x86_opcodes_0f; +extern OpFn *x86_opcodes_d8_a16; +extern OpFn *x86_opcodes_d8_a32; +extern OpFn *x86_opcodes_d9_a16; +extern OpFn *x86_opcodes_d9_a32; +extern OpFn *x86_opcodes_da_a16; +extern OpFn *x86_opcodes_da_a32; +extern OpFn *x86_opcodes_db_a16; +extern OpFn *x86_opcodes_db_a32; +extern OpFn *x86_opcodes_dc_a16; +extern OpFn *x86_opcodes_dc_a32; +extern OpFn *x86_opcodes_dd_a16; +extern OpFn *x86_opcodes_dd_a32; +extern OpFn *x86_opcodes_de_a16; +extern OpFn *x86_opcodes_de_a32; +extern OpFn *x86_opcodes_df_a16; +extern OpFn *x86_opcodes_df_a32; + +extern OpFn ops_286[1024]; +extern OpFn ops_286_0f[1024]; + +extern OpFn ops_386[1024]; +extern OpFn ops_386_0f[1024]; + +extern OpFn ops_486_0f[1024]; + +extern OpFn ops_winchip_0f[1024]; + +extern OpFn ops_pentium_0f[1024]; +extern OpFn ops_pentiummmx_0f[1024]; + +extern OpFn ops_k6_0f[1024]; + +extern OpFn ops_c6x86mx_0f[1024]; +extern OpFn ops_pentiumpro_0f[1024]; +extern OpFn ops_pentium2_0f[1024]; +extern OpFn ops_pentium2d_0f[1024]; + +extern OpFn ops_fpu_d8_a16[32]; +extern OpFn ops_fpu_d8_a32[32]; +extern OpFn ops_fpu_d9_a16[256]; +extern OpFn ops_fpu_d9_a32[256]; +extern OpFn ops_fpu_da_a16[256]; +extern OpFn ops_fpu_da_a32[256]; +extern OpFn ops_fpu_db_a16[256]; +extern OpFn ops_fpu_db_a32[256]; +extern OpFn ops_fpu_dc_a16[32]; +extern OpFn ops_fpu_dc_a32[32]; +extern OpFn ops_fpu_dd_a16[256]; +extern OpFn ops_fpu_dd_a32[256]; +extern OpFn ops_fpu_de_a16[256]; +extern OpFn ops_fpu_de_a32[256]; +extern OpFn ops_fpu_df_a16[256]; +extern OpFn ops_fpu_df_a32[256]; +extern OpFn ops_nofpu_a16[256]; +extern OpFn ops_nofpu_a32[256]; + +extern OpFn ops_fpu_686_da_a16[256]; +extern OpFn ops_fpu_686_da_a32[256]; +extern OpFn ops_fpu_686_db_a16[256]; +extern OpFn ops_fpu_686_db_a32[256]; +extern OpFn ops_fpu_686_df_a16[256]; +extern OpFn ops_fpu_686_df_a32[256]; + +#endif /*_X86_OPS_H*/ diff --git a/src/x86_ops_arith.h b/src/x86_ops_arith.h new file mode 100644 index 000000000..e83638cb6 --- /dev/null +++ b/src/x86_ops_arith.h @@ -0,0 +1,647 @@ +#define OP_ARITH(name, operation, setflags, flagops, gettempc) \ + static int op ## name ## _b_rmw_a16(uint32_t fetchdat) \ + { \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + if (mod == 3) \ + { \ + uint8_t dst = getr8(rm); \ + uint8_t src = getr8(reg); \ + setflags ## 8 flagops; \ + setr8(rm, operation); \ + CLOCK_CYCLES(timing_rr); \ + } \ + else \ + { \ + uint8_t dst = geteab(); if (abrt) return 1; \ + uint8_t src = getr8(reg); \ + seteab(operation); if (abrt) return 1; \ + setflags ## 8 flagops; \ + CLOCK_CYCLES(timing_mr); \ + } \ + return 0; \ + } \ + static int op ## name ## _b_rmw_a32(uint32_t fetchdat) \ + { \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + if (mod == 3) \ + { \ + uint8_t dst = getr8(rm); \ + uint8_t src = getr8(reg); \ + setflags ## 8 flagops; \ + setr8(rm, operation); \ + CLOCK_CYCLES(timing_rr); \ + } \ + else \ + { \ + uint8_t dst = geteab(); if (abrt) return 1; \ + uint8_t src = getr8(reg); \ + seteab(operation); if (abrt) return 1; \ + setflags ## 8 flagops; \ + CLOCK_CYCLES(timing_mr); \ + } \ + return 0; \ + } \ + \ + static int op ## name ## _w_rmw_a16(uint32_t fetchdat) \ + { \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + if (mod == 3) \ + { \ + uint16_t dst = cpu_state.regs[rm].w; \ + uint16_t src = cpu_state.regs[reg].w; \ + setflags ## 16 flagops; \ + cpu_state.regs[rm].w = operation; \ + CLOCK_CYCLES(timing_rr); \ + } \ + else \ + { \ + uint16_t dst = geteaw(); if (abrt) return 1; \ + uint16_t src = cpu_state.regs[reg].w; \ + seteaw(operation); if (abrt) return 1; \ + setflags ## 16 flagops; \ + CLOCK_CYCLES(timing_mr); \ + } \ + return 0; \ + } \ + static int op ## name ## _w_rmw_a32(uint32_t fetchdat) \ + { \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + if (mod == 3) \ + { \ + uint16_t dst = cpu_state.regs[rm].w; \ + uint16_t src = cpu_state.regs[reg].w; \ + setflags ## 16 flagops; \ + cpu_state.regs[rm].w = operation; \ + CLOCK_CYCLES(timing_rr); \ + } \ + else \ + { \ + uint16_t dst = geteaw(); if (abrt) return 1; \ + uint16_t src = cpu_state.regs[reg].w; \ + seteaw(operation); if (abrt) return 1; \ + setflags ## 16 flagops; \ + CLOCK_CYCLES(timing_mr); \ + } \ + return 0; \ + } \ + \ + static int op ## name ## _l_rmw_a16(uint32_t fetchdat) \ + { \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + if (mod == 3) \ + { \ + uint32_t dst = cpu_state.regs[rm].l; \ + uint32_t src = cpu_state.regs[reg].l; \ + setflags ## 32 flagops; \ + cpu_state.regs[rm].l = operation; \ + CLOCK_CYCLES(timing_rr); \ + } \ + else \ + { \ + uint32_t dst = geteal(); if (abrt) return 1; \ + uint32_t src = cpu_state.regs[reg].l; \ + seteal(operation); if (abrt) return 1; \ + setflags ## 32 flagops; \ + CLOCK_CYCLES(timing_mrl); \ + } \ + return 0; \ + } \ + static int op ## name ## _l_rmw_a32(uint32_t fetchdat) \ + { \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + if (mod == 3) \ + { \ + uint32_t dst = cpu_state.regs[rm].l; \ + uint32_t src = cpu_state.regs[reg].l; \ + setflags ## 32 flagops; \ + cpu_state.regs[rm].l = operation; \ + CLOCK_CYCLES(timing_rr); \ + } \ + else \ + { \ + uint32_t dst = geteal(); if (abrt) return 1; \ + uint32_t src = cpu_state.regs[reg].l; \ + seteal(operation); if (abrt) return 1; \ + setflags ## 32 flagops; \ + CLOCK_CYCLES(timing_mrl); \ + } \ + return 0; \ + } \ + \ + static int op ## name ## _b_rm_a16(uint32_t fetchdat) \ + { \ + uint8_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + dst = getr8(reg); \ + src = geteab(); if (abrt) return 1; \ + setflags ## 8 flagops; \ + setr8(reg, operation); \ + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_rm); \ + return 0; \ + } \ + static int op ## name ## _b_rm_a32(uint32_t fetchdat) \ + { \ + uint8_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + dst = getr8(reg); \ + src = geteab(); if (abrt) return 1; \ + setflags ## 8 flagops; \ + setr8(reg, operation); \ + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_rm); \ + return 0; \ + } \ + \ + static int op ## name ## _w_rm_a16(uint32_t fetchdat) \ + { \ + uint16_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + dst = cpu_state.regs[reg].w; \ + src = geteaw(); if (abrt) return 1; \ + setflags ## 16 flagops; \ + cpu_state.regs[reg].w = operation; \ + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_rm); \ + return 0; \ + } \ + static int op ## name ## _w_rm_a32(uint32_t fetchdat) \ + { \ + uint16_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + dst = cpu_state.regs[reg].w; \ + src = geteaw(); if (abrt) return 1; \ + setflags ## 16 flagops; \ + cpu_state.regs[reg].w = operation; \ + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_rm); \ + return 0; \ + } \ + \ + static int op ## name ## _l_rm_a16(uint32_t fetchdat) \ + { \ + uint32_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_16(fetchdat); \ + dst = cpu_state.regs[reg].l; \ + src = geteal(); if (abrt) return 1; \ + setflags ## 32 flagops; \ + cpu_state.regs[reg].l = operation; \ + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_rml); \ + return 0; \ + } \ + static int op ## name ## _l_rm_a32(uint32_t fetchdat) \ + { \ + uint32_t dst, src; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + fetch_ea_32(fetchdat); \ + dst = cpu_state.regs[reg].l; \ + src = geteal(); if (abrt) return 1; \ + setflags ## 32 flagops; \ + cpu_state.regs[reg].l = operation; \ + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_rml); \ + return 0; \ + } \ + \ + static int op ## name ## _AL_imm(uint32_t fetchdat) \ + { \ + uint8_t dst = AL; \ + uint8_t src = getbytef(); \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + setflags ## 8 flagops; \ + AL = operation; \ + CLOCK_CYCLES(timing_rr); \ + return 0; \ + } \ + \ + static int op ## name ## _AX_imm(uint32_t fetchdat) \ + { \ + uint16_t dst = AX; \ + uint16_t src = getwordf(); \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + setflags ## 16 flagops; \ + AX = operation; \ + CLOCK_CYCLES(timing_rr); \ + return 0; \ + } \ + \ + static int op ## name ## _EAX_imm(uint32_t fetchdat) \ + { \ + uint32_t dst = EAX; \ + uint32_t src = getlong(); if (abrt) return 1; \ + if (gettempc) tempc = CF_SET() ? 1 : 0; \ + setflags ## 32 flagops; \ + EAX = operation; \ + CLOCK_CYCLES(timing_rr); \ + return 0; \ + } + +OP_ARITH(ADD, dst + src, setadd, (dst, src), 0) +OP_ARITH(ADC, dst + src + tempc, setadc, (dst, src), 1) +OP_ARITH(SUB, dst - src, setsub, (dst, src), 0) +OP_ARITH(SBB, dst - (src + tempc), setsbc, (dst, src), 1) +OP_ARITH(OR, dst | src, setznp, (dst | src), 0) +OP_ARITH(AND, dst & src, setznp, (dst & src), 0) +OP_ARITH(XOR, dst ^ src, setznp, (dst ^ src), 0) + +static int opCMP_b_rmw_a16(uint32_t fetchdat) +{ + uint8_t dst; + fetch_ea_16(fetchdat); + dst = geteab(); if (abrt) return 1; + setsub8(dst, getr8(reg)); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + return 0; +} +static int opCMP_b_rmw_a32(uint32_t fetchdat) +{ + uint8_t dst; + fetch_ea_32(fetchdat); + dst = geteab(); if (abrt) return 1; + setsub8(dst, getr8(reg)); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + return 0; +} + +static int opCMP_w_rmw_a16(uint32_t fetchdat) +{ + uint16_t dst; + fetch_ea_16(fetchdat); + dst = geteaw(); if (abrt) return 1; + setsub16(dst, cpu_state.regs[reg].w); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + return 0; +} +static int opCMP_w_rmw_a32(uint32_t fetchdat) +{ + uint16_t dst; + fetch_ea_32(fetchdat); + dst = geteaw(); if (abrt) return 1; + setsub16(dst, cpu_state.regs[reg].w); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + return 0; +} + +static int opCMP_l_rmw_a16(uint32_t fetchdat) +{ + uint32_t dst; + fetch_ea_16(fetchdat); + dst = geteal(); if (abrt) return 1; + setsub32(dst, cpu_state.regs[reg].l); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + return 0; +} +static int opCMP_l_rmw_a32(uint32_t fetchdat) +{ + uint32_t dst; + fetch_ea_32(fetchdat); + dst = geteal(); if (abrt) return 1; + setsub32(dst, cpu_state.regs[reg].l); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + return 0; +} + +static int opCMP_b_rm_a16(uint32_t fetchdat) +{ + uint8_t src; + fetch_ea_16(fetchdat); + src = geteab(); if (abrt) return 1; + setsub8(getr8(reg), src); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_rm); + return 0; +} +static int opCMP_b_rm_a32(uint32_t fetchdat) +{ + uint8_t src; + fetch_ea_32(fetchdat); + src = geteab(); if (abrt) return 1; + setsub8(getr8(reg), src); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_rm); + return 0; +} + +static int opCMP_w_rm_a16(uint32_t fetchdat) +{ + uint16_t src; + fetch_ea_16(fetchdat); + src = geteaw(); if (abrt) return 1; + setsub16(cpu_state.regs[reg].w, src); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_rm); + return 0; +} +static int opCMP_w_rm_a32(uint32_t fetchdat) +{ + uint16_t src; + fetch_ea_32(fetchdat); + src = geteaw(); if (abrt) return 1; + setsub16(cpu_state.regs[reg].w, src); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_rm); + return 0; +} + +static int opCMP_l_rm_a16(uint32_t fetchdat) +{ + uint32_t src; + fetch_ea_16(fetchdat); + src = geteal(); if (abrt) return 1; + setsub32(cpu_state.regs[reg].l, src); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_rml); + return 0; +} +static int opCMP_l_rm_a32(uint32_t fetchdat) +{ + uint32_t src; + fetch_ea_32(fetchdat); + src = geteal(); if (abrt) return 1; + setsub32(cpu_state.regs[reg].l, src); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_rml); + return 0; +} + +static int opCMP_AL_imm(uint32_t fetchdat) +{ + uint8_t src = getbytef(); + setsub8(AL, src); + CLOCK_CYCLES(timing_rr); + return 0; +} + +static int opCMP_AX_imm(uint32_t fetchdat) +{ + uint16_t src = getwordf(); + setsub16(AX, src); + CLOCK_CYCLES(timing_rr); + return 0; +} + +static int opCMP_EAX_imm(uint32_t fetchdat) +{ + uint32_t src = getlong(); if (abrt) return 1; + setsub32(EAX, src); + CLOCK_CYCLES(timing_rr); + return 0; +} + +static int opTEST_b_a16(uint32_t fetchdat) +{ + uint8_t temp, temp2; + fetch_ea_16(fetchdat); + temp = geteab(); if (abrt) return 1; + temp2 = getr8(reg); + setznp8(temp & temp2); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + return 0; +} +static int opTEST_b_a32(uint32_t fetchdat) +{ + uint8_t temp, temp2; + fetch_ea_32(fetchdat); + temp = geteab(); if (abrt) return 1; + temp2 = getr8(reg); + setznp8(temp & temp2); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + return 0; +} + +static int opTEST_w_a16(uint32_t fetchdat) +{ + uint16_t temp, temp2; + fetch_ea_16(fetchdat); + temp = geteaw(); if (abrt) return 1; + temp2 = cpu_state.regs[reg].w; + setznp16(temp & temp2); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + return 0; +} +static int opTEST_w_a32(uint32_t fetchdat) +{ + uint16_t temp, temp2; + fetch_ea_32(fetchdat); + temp = geteaw(); if (abrt) return 1; + temp2 = cpu_state.regs[reg].w; + setznp16(temp & temp2); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + return 0; +} + +static int opTEST_l_a16(uint32_t fetchdat) +{ + uint32_t temp, temp2; + fetch_ea_16(fetchdat); + temp = geteal(); if (abrt) return 1; + temp2 = cpu_state.regs[reg].l; + setznp32(temp & temp2); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + return 0; +} +static int opTEST_l_a32(uint32_t fetchdat) +{ + uint32_t temp, temp2; + fetch_ea_32(fetchdat); + temp = geteal(); if (abrt) return 1; + temp2 = cpu_state.regs[reg].l; + setznp32(temp & temp2); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + return 0; +} + +static int opTEST_AL(uint32_t fetchdat) +{ + uint8_t temp = getbytef(); + setznp8(AL & temp); + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opTEST_AX(uint32_t fetchdat) +{ + uint16_t temp = getwordf(); + setznp16(AX & temp); + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opTEST_EAX(uint32_t fetchdat) +{ + uint32_t temp = getlong(); if (abrt) return 1; + setznp32(EAX & temp); + CLOCK_CYCLES(timing_rr); + return 0; +} + + +#define ARITH_MULTI(ea_width, flag_width) \ + dst = getea ## ea_width(); if (abrt) return 1; \ + switch (rmdat&0x38) \ + { \ + case 0x00: /*ADD ea, #*/ \ + setea ## ea_width(dst + src); if (abrt) return 1; \ + setadd ## flag_width(dst, src); \ + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x08: /*OR ea, #*/ \ + dst |= src; \ + setea ## ea_width(dst); if (abrt) return 1; \ + setznp ## flag_width(dst); \ + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x10: /*ADC ea, #*/ \ + tempc = CF_SET() ? 1 : 0; \ + setea ## ea_width(dst + src + tempc); if (abrt) return 1; \ + setadc ## flag_width(dst, src); \ + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x18: /*SBB ea, #*/ \ + tempc = CF_SET() ? 1 : 0; \ + setea ## ea_width(dst - (src + tempc)); if (abrt) return 1; \ + setsbc ## flag_width(dst, src); \ + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x20: /*AND ea, #*/ \ + dst &= src; \ + setea ## ea_width(dst); if (abrt) return 1; \ + setznp ## flag_width(dst); \ + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x28: /*SUB ea, #*/ \ + setea ## ea_width(dst - src); if (abrt) return 1; \ + setsub ## flag_width(dst, src); \ + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x30: /*XOR ea, #*/ \ + dst ^= src; \ + setea ## ea_width(dst); if (abrt) return 1; \ + setznp ## flag_width(dst); \ + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mr); \ + break; \ + case 0x38: /*CMP ea, #*/ \ + setsub ## flag_width(dst, src); \ + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); \ + else CLOCK_CYCLES((mod == 3) ? 2 : 7); \ + break; \ + } + + +static int op80_a16(uint32_t fetchdat) +{ + uint8_t src, dst; + + fetch_ea_16(fetchdat); + src = getbyte(); if (abrt) return 1; + ARITH_MULTI(b, 8); + + return 0; +} +static int op80_a32(uint32_t fetchdat) +{ + uint8_t src, dst; + + fetch_ea_32(fetchdat); + src = getbyte(); if (abrt) return 1; + ARITH_MULTI(b, 8); + + return 0; +} +static int op81_w_a16(uint32_t fetchdat) +{ + uint16_t src, dst; + + fetch_ea_16(fetchdat); + src = getword(); if (abrt) return 1; + ARITH_MULTI(w, 16); + + return 0; +} +static int op81_w_a32(uint32_t fetchdat) +{ + uint16_t src, dst; + + fetch_ea_32(fetchdat); + src = getword(); if (abrt) return 1; + ARITH_MULTI(w, 16); + + return 0; +} +static int op81_l_a16(uint32_t fetchdat) +{ + uint32_t src, dst; + + fetch_ea_16(fetchdat); + src = getlong(); if (abrt) return 1; + ARITH_MULTI(l, 32); + + return 0; +} +static int op81_l_a32(uint32_t fetchdat) +{ + uint32_t src, dst; + + fetch_ea_32(fetchdat); + src = getlong(); if (abrt) return 1; + ARITH_MULTI(l, 32); + + return 0; +} + +static int op83_w_a16(uint32_t fetchdat) +{ + uint16_t src, dst; + + fetch_ea_16(fetchdat); + src = getbyte(); if (abrt) return 1; + if (src & 0x80) src |= 0xff00; + ARITH_MULTI(w, 16); + + return 0; +} +static int op83_w_a32(uint32_t fetchdat) +{ + uint16_t src, dst; + + fetch_ea_32(fetchdat); + src = getbyte(); if (abrt) return 1; + if (src & 0x80) src |= 0xff00; + ARITH_MULTI(w, 16); + + return 0; +} + +static int op83_l_a16(uint32_t fetchdat) +{ + uint32_t src, dst; + + fetch_ea_16(fetchdat); + src = getbyte(); if (abrt) return 1; + if (src & 0x80) src |= 0xffffff00; + ARITH_MULTI(l, 32); + + return 0; +} +static int op83_l_a32(uint32_t fetchdat) +{ + uint32_t src, dst; + + fetch_ea_32(fetchdat); + src = getbyte(); if (abrt) return 1; + if (src & 0x80) src |= 0xffffff00; + ARITH_MULTI(l, 32); + + return 0; +} + diff --git a/src/x86_ops_atomic.h b/src/x86_ops_atomic.h new file mode 100644 index 000000000..74b161909 --- /dev/null +++ b/src/x86_ops_atomic.h @@ -0,0 +1,278 @@ +static int opCMPXCHG_b_a16(uint32_t fetchdat) +{ + uint8_t temp, temp2 = AL; + if (!is486) + { + cpu_state.pc = oldpc; + x86illegal(); + return 1; + } + fetch_ea_16(fetchdat); + temp = geteab(); if (abrt) return 1; + if (AL == temp) seteab(getr8(reg)); + else AL = temp; + if (abrt) return 1; + setsub8(temp2, temp); + CLOCK_CYCLES((mod == 3) ? 6 : 10); + return 0; +} +static int opCMPXCHG_b_a32(uint32_t fetchdat) +{ + uint8_t temp, temp2 = AL; + if (!is486) + { + cpu_state.pc = oldpc; + x86illegal(); + return 1; + } + fetch_ea_32(fetchdat); + temp = geteab(); if (abrt) return 1; + if (AL == temp) seteab(getr8(reg)); + else AL = temp; + if (abrt) return 1; + setsub8(temp2, temp); + CLOCK_CYCLES((mod == 3) ? 6 : 10); + return 0; +} + +static int opCMPXCHG_w_a16(uint32_t fetchdat) +{ + uint16_t temp, temp2 = AX; + if (!is486) + { + cpu_state.pc = oldpc; + x86illegal(); + return 1; + } + fetch_ea_16(fetchdat); + temp = geteaw(); if (abrt) return 1; + if (AX == temp) seteaw(cpu_state.regs[reg].w); + else AX = temp; + if (abrt) return 1; + setsub16(temp2, temp); + CLOCK_CYCLES((mod == 3) ? 6 : 10); + return 0; +} +static int opCMPXCHG_w_a32(uint32_t fetchdat) +{ + uint16_t temp, temp2 = AX; + if (!is486) + { + cpu_state.pc = oldpc; + x86illegal(); + return 1; + } + fetch_ea_32(fetchdat); + temp = geteaw(); if (abrt) return 1; + if (AX == temp) seteaw(cpu_state.regs[reg].w); + else AX = temp; + if (abrt) return 1; + setsub16(temp2, temp); + CLOCK_CYCLES((mod == 3) ? 6 : 10); + return 0; +} + +static int opCMPXCHG_l_a16(uint32_t fetchdat) +{ + uint32_t temp, temp2 = EAX; + if (!is486) + { + cpu_state.pc = oldpc; + x86illegal(); + return 1; + } + fetch_ea_16(fetchdat); + temp = geteal(); if (abrt) return 1; + if (EAX == temp) seteal(cpu_state.regs[reg].l); + else EAX = temp; + if (abrt) return 1; + setsub32(temp2, temp); + CLOCK_CYCLES((mod == 3) ? 6 : 10); + return 0; +} +static int opCMPXCHG_l_a32(uint32_t fetchdat) +{ + uint32_t temp, temp2 = EAX; + if (!is486) + { + cpu_state.pc = oldpc; + x86illegal(); + return 1; + } + fetch_ea_32(fetchdat); + temp = geteal(); if (abrt) return 1; + if (EAX == temp) seteal(cpu_state.regs[reg].l); + else EAX = temp; + if (abrt) return 1; + setsub32(temp2, temp); + CLOCK_CYCLES((mod == 3) ? 6 : 10); + return 0; +} + +static int opCMPXCHG8B_a16(uint32_t fetchdat) +{ + uint32_t temp, temp_hi, temp2 = EAX, temp2_hi = EDX; + if (!is486) + { + cpu_state.pc = oldpc; + x86illegal(); + return 0; + } + fetch_ea_16(fetchdat); + temp = geteal(); + temp_hi = readmeml(easeg, eaaddr + 4); if (abrt) return 0; + if (EAX == temp && EDX == temp_hi) + { + seteal(EBX); + writememl(easeg, eaaddr+4, ECX); + } + else + { + EAX = temp; + EDX = temp_hi; + } + if (abrt) return 0; + flags_rebuild(); + if (temp == temp2 && temp_hi == temp2_hi) + flags |= Z_FLAG; + else + flags &= ~Z_FLAG; + cycles -= (mod == 3) ? 6 : 10; + return 0; +} +static int opCMPXCHG8B_a32(uint32_t fetchdat) +{ + uint32_t temp, temp_hi, temp2 = EAX, temp2_hi = EDX; + if (!is486) + { + cpu_state.pc = oldpc; + x86illegal(); + return 0; + } + fetch_ea_32(fetchdat); + temp = geteal(); + temp_hi = readmeml(easeg, eaaddr + 4); if (abrt) return 0; + if (EAX == temp && EDX == temp_hi) + { + seteal(EBX); + writememl(easeg, eaaddr+4, ECX); + } + else + { + EAX = temp; + EDX = temp_hi; + } + if (abrt) return 0; + flags_rebuild(); + if (temp == temp2 && temp_hi == temp2_hi) + flags |= Z_FLAG; + else + flags &= ~Z_FLAG; + cycles -= (mod == 3) ? 6 : 10; + return 0; +} + +static int opXADD_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + if (!is486) + { + cpu_state.pc = oldpc; + x86illegal(); + return 1; + } + fetch_ea_16(fetchdat); + temp = geteab(); if (abrt) return 1; + seteab(temp + getr8(reg)); if (abrt) return 1; + setadd8(temp, getr8(reg)); + setr8(reg, temp); + CLOCK_CYCLES((mod == 3) ? 3 : 4); + return 0; +} +static int opXADD_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + if (!is486) + { + cpu_state.pc = oldpc; + x86illegal(); + return 1; + } + fetch_ea_32(fetchdat); + temp = geteab(); if (abrt) return 1; + seteab(temp + getr8(reg)); if (abrt) return 1; + setadd8(temp, getr8(reg)); + setr8(reg, temp); + CLOCK_CYCLES((mod == 3) ? 3 : 4); + return 0; +} + +static int opXADD_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + if (!is486) + { + cpu_state.pc = oldpc; + x86illegal(); + return 1; + } + fetch_ea_16(fetchdat); + temp = geteaw(); if (abrt) return 1; + seteaw(temp + cpu_state.regs[reg].w); if (abrt) return 1; + setadd16(temp, cpu_state.regs[reg].w); + cpu_state.regs[reg].w = temp; + CLOCK_CYCLES((mod == 3) ? 3 : 4); + return 0; +} +static int opXADD_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + if (!is486) + { + cpu_state.pc = oldpc; + x86illegal(); + return 1; + } + fetch_ea_32(fetchdat); + temp = geteaw(); if (abrt) return 1; + seteaw(temp + cpu_state.regs[reg].w); if (abrt) return 1; + setadd16(temp, cpu_state.regs[reg].w); + cpu_state.regs[reg].w = temp; + CLOCK_CYCLES((mod == 3) ? 3 : 4); + return 0; +} + +static int opXADD_l_a16(uint32_t fetchdat) +{ + uint32_t temp; + if (!is486) + { + cpu_state.pc = oldpc; + x86illegal(); + return 1; + } + fetch_ea_16(fetchdat); + temp = geteal(); if (abrt) return 1; + seteal(temp + cpu_state.regs[reg].l); if (abrt) return 1; + setadd32(temp, cpu_state.regs[reg].l); + cpu_state.regs[reg].l = temp; + CLOCK_CYCLES((mod == 3) ? 3 : 4); + return 0; +} +static int opXADD_l_a32(uint32_t fetchdat) +{ + uint32_t temp; + if (!is486) + { + cpu_state.pc = oldpc; + x86illegal(); + return 1; + } + fetch_ea_32(fetchdat); + temp = geteal(); if (abrt) return 1; + seteal(temp + cpu_state.regs[reg].l); if (abrt) return 1; + setadd32(temp, cpu_state.regs[reg].l); + cpu_state.regs[reg].l = temp; + CLOCK_CYCLES((mod == 3) ? 3 : 4); + return 0; +} diff --git a/src/x86_ops_bcd.h b/src/x86_ops_bcd.h new file mode 100644 index 000000000..37647005b --- /dev/null +++ b/src/x86_ops_bcd.h @@ -0,0 +1,107 @@ +static int opAAA(uint32_t fetchdat) +{ + flags_rebuild(); + if ((flags & A_FLAG) || ((AL & 0xF) > 9)) + { + AL += 6; + AH++; + flags |= (A_FLAG | C_FLAG); + } + else + flags &= ~(A_FLAG | C_FLAG); + AL &= 0xF; + CLOCK_CYCLES(is486 ? 3 : 4); + return 0; +} + +static int opAAD(uint32_t fetchdat) +{ + int base = getbytef(); + if (cpu_manufacturer != MANU_INTEL) base = 10; + AL = (AH * base) + AL; + AH = 0; + setznp16(AX); + CLOCK_CYCLES((is486) ? 14 : 19); + return 0; +} + +static int opAAM(uint32_t fetchdat) +{ + int base = getbytef(); + if (!base || cpu_manufacturer != MANU_INTEL) base = 10; + AH = AL / base; + AL %= base; + setznp16(AX); + CLOCK_CYCLES((is486) ? 15 : 17); + return 0; +} + +static int opAAS(uint32_t fetchdat) +{ + flags_rebuild(); + if ((flags & A_FLAG) || ((AL & 0xF) > 9)) + { + AL -= 6; + AH--; + flags |= (A_FLAG | C_FLAG); + } + else + flags &= ~(A_FLAG | C_FLAG); + AL &= 0xF; + CLOCK_CYCLES(is486 ? 3 : 4); + return 0; +} + +static int opDAA(uint32_t fetchdat) +{ + uint16_t tempw; + + flags_rebuild(); + if ((flags & A_FLAG) || ((AL & 0xf) > 9)) + { + int tempi = ((uint16_t)AL) + 6; + AL += 6; + flags |= A_FLAG; + if (tempi & 0x100) flags |= C_FLAG; + } + if ((flags & C_FLAG) || (AL > 0x9f)) + { + AL += 0x60; + flags |= C_FLAG; + } + + tempw = flags & (C_FLAG | A_FLAG); + setznp8(AL); + flags_rebuild(); + flags |= tempw; + CLOCK_CYCLES(4); + + return 0; +} + +static int opDAS(uint32_t fetchdat) +{ + uint16_t tempw; + + flags_rebuild(); + if ((flags & A_FLAG) || ((AL & 0xf) > 9)) + { + int tempi = ((uint16_t)AL) - 6; + AL -= 6; + flags |= A_FLAG; + if (tempi & 0x100) flags |= C_FLAG; + } + if ((flags & C_FLAG) || (AL > 0x9f)) + { + AL -= 0x60; + flags |= C_FLAG; + } + + tempw = flags & (C_FLAG | A_FLAG); + setznp8(AL); + flags_rebuild(); + flags |= tempw; + CLOCK_CYCLES(4); + + return 0; +} diff --git a/src/x86_ops_bit.h b/src/x86_ops_bit.h new file mode 100644 index 000000000..c5da6967c --- /dev/null +++ b/src/x86_ops_bit.h @@ -0,0 +1,297 @@ +static int opBT_w_r_a16(uint32_t fetchdat) +{ + int tempc; + uint16_t temp; + + fetch_ea_16(fetchdat); + eaaddr += ((cpu_state.regs[reg].w / 16) * 2); eal_r = 0; + temp = geteaw(); if (abrt) return 1; + flags_rebuild(); + if (temp & (1 << (cpu_state.regs[reg].w & 15))) flags |= C_FLAG; + else flags &= ~C_FLAG; + + CLOCK_CYCLES(3); + return 0; +} +static int opBT_w_r_a32(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_32(fetchdat); + eaaddr += ((cpu_state.regs[reg].w / 16) * 2); eal_r = 0; + temp = geteaw(); if (abrt) return 1; + flags_rebuild(); + if (temp & (1 << (cpu_state.regs[reg].w & 15))) flags |= C_FLAG; + else flags &= ~C_FLAG; + + CLOCK_CYCLES(3); + return 0; +} +static int opBT_l_r_a16(uint32_t fetchdat) +{ + uint32_t temp; + + fetch_ea_16(fetchdat); + eaaddr += ((cpu_state.regs[reg].l / 32) * 4); eal_r = 0; + temp = geteal(); if (abrt) return 1; + flags_rebuild(); + if (temp & (1 << (cpu_state.regs[reg].l & 31))) flags |= C_FLAG; + else flags &= ~C_FLAG; + + CLOCK_CYCLES(3); + return 0; +} +static int opBT_l_r_a32(uint32_t fetchdat) +{ + uint32_t temp; + + fetch_ea_32(fetchdat); + eaaddr += ((cpu_state.regs[reg].l / 32) * 4); eal_r = 0; + temp = geteal(); if (abrt) return 1; + flags_rebuild(); + if (temp & (1 << (cpu_state.regs[reg].l & 31))) flags |= C_FLAG; + else flags &= ~C_FLAG; + + CLOCK_CYCLES(3); + return 0; +} + +#define opBT(name, operation) \ + static int opBT ## name ## _w_r_a16(uint32_t fetchdat) \ + { \ + int tempc; \ + uint16_t temp; \ + \ + fetch_ea_16(fetchdat); \ + eaaddr += ((cpu_state.regs[reg].w / 16) * 2); eal_r = eal_w = 0; \ + temp = geteaw(); if (abrt) return 1; \ + tempc = (temp & (1 << (cpu_state.regs[reg].w & 15))) ? 1 : 0; \ + temp operation (1 << (cpu_state.regs[reg].w & 15)); \ + seteaw(temp); if (abrt) return 1; \ + flags_rebuild(); \ + if (tempc) flags |= C_FLAG; \ + else flags &= ~C_FLAG; \ + \ + CLOCK_CYCLES(6); \ + return 0; \ + } \ + static int opBT ## name ## _w_r_a32(uint32_t fetchdat) \ + { \ + int tempc; \ + uint16_t temp; \ + \ + fetch_ea_32(fetchdat); \ + eaaddr += ((cpu_state.regs[reg].w / 16) * 2); eal_r = eal_w = 0; \ + temp = geteaw(); if (abrt) return 1; \ + tempc = (temp & (1 << (cpu_state.regs[reg].w & 15))) ? 1 : 0; \ + temp operation (1 << (cpu_state.regs[reg].w & 15)); \ + seteaw(temp); if (abrt) return 1; \ + flags_rebuild(); \ + if (tempc) flags |= C_FLAG; \ + else flags &= ~C_FLAG; \ + \ + CLOCK_CYCLES(6); \ + return 0; \ + } \ + static int opBT ## name ## _l_r_a16(uint32_t fetchdat) \ + { \ + int tempc; \ + uint32_t temp; \ + \ + fetch_ea_16(fetchdat); \ + eaaddr += ((cpu_state.regs[reg].l / 32) * 4); eal_r = eal_w = 0; \ + temp = geteal(); if (abrt) return 1; \ + tempc = (temp & (1 << (cpu_state.regs[reg].l & 31))) ? 1 : 0; \ + temp operation (1 << (cpu_state.regs[reg].l & 31)); \ + seteal(temp); if (abrt) return 1; \ + flags_rebuild(); \ + if (tempc) flags |= C_FLAG; \ + else flags &= ~C_FLAG; \ + \ + CLOCK_CYCLES(6); \ + return 0; \ + } \ + static int opBT ## name ## _l_r_a32(uint32_t fetchdat) \ + { \ + int tempc; \ + uint32_t temp; \ + \ + fetch_ea_32(fetchdat); \ + eaaddr += ((cpu_state.regs[reg].l / 32) * 4); eal_r = eal_w = 0; \ + temp = geteal(); if (abrt) return 1; \ + tempc = (temp & (1 << (cpu_state.regs[reg].l & 31))) ? 1 : 0; \ + temp operation (1 << (cpu_state.regs[reg].l & 31)); \ + seteal(temp); if (abrt) return 1; \ + flags_rebuild(); \ + if (tempc) flags |= C_FLAG; \ + else flags &= ~C_FLAG; \ + \ + CLOCK_CYCLES(6); \ + return 0; \ + } + +opBT(C, ^=) +opBT(R, &=~) +opBT(S, |=) + +static int opBA_w_a16(uint32_t fetchdat) +{ + int tempc, count; + uint16_t temp; + + fetch_ea_16(fetchdat); + + temp = geteaw(); + count = getbyte(); if (abrt) return 1; + tempc = temp & (1 << count); + flags_rebuild(); + switch (rmdat & 0x38) + { + case 0x20: /*BT w,imm*/ + if (tempc) flags |= C_FLAG; + else flags &= ~C_FLAG; + CLOCK_CYCLES(3); + return 0; + case 0x28: /*BTS w,imm*/ + temp |= (1 << count); + break; + case 0x30: /*BTR w,imm*/ + temp &= ~(1 << count); + break; + case 0x38: /*BTC w,imm*/ + temp ^= (1 << count); + break; + + default: + pclog("Bad 0F BA opcode %02X\n", rmdat & 0x38); + cpu_state.pc = oldpc; + x86illegal(); + break; + } + seteaw(temp); if (abrt) return 1; + if (tempc) flags |= C_FLAG; + else flags &= ~C_FLAG; + CLOCK_CYCLES(6); + return 0; +} +static int opBA_w_a32(uint32_t fetchdat) +{ + int tempc, count; + uint16_t temp; + + fetch_ea_32(fetchdat); + + temp = geteaw(); + count = getbyte(); if (abrt) return 1; + tempc = temp & (1 << count); + flags_rebuild(); + switch (rmdat & 0x38) + { + case 0x20: /*BT w,imm*/ + if (tempc) flags |= C_FLAG; + else flags &= ~C_FLAG; + CLOCK_CYCLES(3); + return 0; + case 0x28: /*BTS w,imm*/ + temp |= (1 << count); + break; + case 0x30: /*BTR w,imm*/ + temp &= ~(1 << count); + break; + case 0x38: /*BTC w,imm*/ + temp ^= (1 << count); + break; + + default: + pclog("Bad 0F BA opcode %02X\n", rmdat & 0x38); + cpu_state.pc = oldpc; + x86illegal(); + break; + } + seteaw(temp); if (abrt) return 1; + if (tempc) flags |= C_FLAG; + else flags &= ~C_FLAG; + CLOCK_CYCLES(6); + return 0; +} + +static int opBA_l_a16(uint32_t fetchdat) +{ + int tempc, count; + uint32_t temp; + + fetch_ea_16(fetchdat); + + temp = geteal(); + count = getbyte(); if (abrt) return 1; + tempc = temp & (1 << count); + flags_rebuild(); + switch (rmdat & 0x38) + { + case 0x20: /*BT w,imm*/ + if (tempc) flags |= C_FLAG; + else flags &= ~C_FLAG; + CLOCK_CYCLES(3); + return 0; + case 0x28: /*BTS w,imm*/ + temp |= (1 << count); + break; + case 0x30: /*BTR w,imm*/ + temp &= ~(1 << count); + break; + case 0x38: /*BTC w,imm*/ + temp ^= (1 << count); + break; + + default: + pclog("Bad 0F BA opcode %02X\n", rmdat & 0x38); + cpu_state.pc = oldpc; + x86illegal(); + break; + } + seteal(temp); if (abrt) return 1; + if (tempc) flags |= C_FLAG; + else flags &= ~C_FLAG; + CLOCK_CYCLES(6); + return 0; +} +static int opBA_l_a32(uint32_t fetchdat) +{ + int tempc, count; + uint32_t temp; + + fetch_ea_32(fetchdat); + + temp = geteal(); + count = getbyte(); if (abrt) return 1; + tempc = temp & (1 << count); + flags_rebuild(); + switch (rmdat & 0x38) + { + case 0x20: /*BT w,imm*/ + if (tempc) flags |= C_FLAG; + else flags &= ~C_FLAG; + CLOCK_CYCLES(3); + return 0; + case 0x28: /*BTS w,imm*/ + temp |= (1 << count); + break; + case 0x30: /*BTR w,imm*/ + temp &= ~(1 << count); + break; + case 0x38: /*BTC w,imm*/ + temp ^= (1 << count); + break; + + default: + pclog("Bad 0F BA opcode %02X\n", rmdat & 0x38); + cpu_state.pc = oldpc; + x86illegal(); + break; + } + seteal(temp); if (abrt) return 1; + if (tempc) flags |= C_FLAG; + else flags &= ~C_FLAG; + CLOCK_CYCLES(6); + return 0; +} diff --git a/src/x86_ops_bitscan.h b/src/x86_ops_bitscan.h new file mode 100644 index 000000000..90dc6e8bf --- /dev/null +++ b/src/x86_ops_bitscan.h @@ -0,0 +1,117 @@ +#define BS_common(start, end, dir, dest, time) \ + flags_rebuild(); \ + if (temp) \ + { \ + int c; \ + flags &= ~Z_FLAG; \ + for (c = start; c != end; c += dir) \ + { \ + CLOCK_CYCLES(time); \ + if (temp & (1 << c)) \ + { \ + dest = c; \ + break; \ + } \ + } \ + } \ + else \ + flags |= Z_FLAG; + +static int opBSF_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_16(fetchdat); + temp = geteaw(); if (abrt) return 1; + + BS_common(0, 16, 1, cpu_state.regs[reg].w, (is486) ? 1 : 3); + + CLOCK_CYCLES((is486) ? 6 : 10); + return 0; +} +static int opBSF_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_32(fetchdat); + temp = geteaw(); if (abrt) return 1; + + BS_common(0, 16, 1, cpu_state.regs[reg].w, (is486) ? 1 : 3); + + CLOCK_CYCLES((is486) ? 6 : 10); + return 0; +} +static int opBSF_l_a16(uint32_t fetchdat) +{ + uint32_t temp; + + fetch_ea_16(fetchdat); + temp = geteal(); if (abrt) return 1; + + BS_common(0, 32, 1, cpu_state.regs[reg].l, (is486) ? 1 : 3); + + CLOCK_CYCLES((is486) ? 6 : 10); + return 0; +} +static int opBSF_l_a32(uint32_t fetchdat) +{ + uint32_t temp; + + fetch_ea_32(fetchdat); + temp = geteal(); if (abrt) return 1; + + BS_common(0, 32, 1, cpu_state.regs[reg].l, (is486) ? 1 : 3); + + CLOCK_CYCLES((is486) ? 6 : 10); + return 0; +} + +static int opBSR_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_16(fetchdat); + temp = geteaw(); if (abrt) return 1; + + BS_common(15, -1, -1, cpu_state.regs[reg].w, 3); + + CLOCK_CYCLES((is486) ? 6 : 10); + return 0; +} +static int opBSR_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_32(fetchdat); + temp = geteaw(); if (abrt) return 1; + + BS_common(15, -1, -1, cpu_state.regs[reg].w, 3); + + CLOCK_CYCLES((is486) ? 6 : 10); + return 0; +} +static int opBSR_l_a16(uint32_t fetchdat) +{ + uint32_t temp; + + fetch_ea_16(fetchdat); + temp = geteal(); if (abrt) return 1; + + BS_common(31, -1, -1, cpu_state.regs[reg].l, 3); + + CLOCK_CYCLES((is486) ? 6 : 10); + return 0; +} +static int opBSR_l_a32(uint32_t fetchdat) +{ + uint32_t temp; + + fetch_ea_32(fetchdat); + temp = geteal(); if (abrt) return 1; + + BS_common(31, -1, -1, cpu_state.regs[reg].l, 3); + + CLOCK_CYCLES((is486) ? 6 : 10); + return 0; +} + diff --git a/src/x86_ops_call.h b/src/x86_ops_call.h new file mode 100644 index 000000000..ecc0a303b --- /dev/null +++ b/src/x86_ops_call.h @@ -0,0 +1,348 @@ +#define CALL_FAR_w(new_seg, new_pc) \ + old_cs = CS; \ + old_pc = cpu_state.pc; \ + oxpc = cpu_state.pc; \ + cpu_state.pc = new_pc; \ + optype = CALL; \ + cgate16 = cgate32 = 0; \ + if (msw & 1) loadcscall(new_seg); \ + else \ + { \ + loadcs(new_seg); \ + cycles -= timing_call_rm; \ + } \ + optype = 0; \ + if (abrt) { cgate16 = cgate32 = 0; return 1; } \ + oldss = ss; \ + if (cgate32) \ + { \ + uint32_t old_esp = ESP; \ + PUSH_L(old_cs); if (abrt) { cgate16 = cgate32 = 0; return 1; } \ + PUSH_L(old_pc); if (abrt) { ESP = old_esp; return 1; } \ + } \ + else \ + { \ + uint32_t old_esp = ESP; \ + PUSH_W(old_cs); if (abrt) { cgate16 = cgate32 = 0; return 1; } \ + PUSH_W(old_pc); if (abrt) { ESP = old_esp; return 1; } \ + } + +#define CALL_FAR_l(new_seg, new_pc) \ + old_cs = CS; \ + old_pc = cpu_state.pc; \ + oxpc = cpu_state.pc; \ + cpu_state.pc = new_pc; \ + optype = CALL; \ + cgate16 = cgate32 = 0; \ + if (msw & 1) loadcscall(new_seg); \ + else \ + { \ + loadcs(new_seg); \ + cycles -= timing_call_rm; \ + } \ + optype = 0; \ + if (abrt) { cgate16 = cgate32 = 0; return 1; } \ + oldss = ss; \ + if (cgate16) \ + { \ + uint32_t old_esp = ESP; \ + PUSH_W(old_cs); if (abrt) { cgate16 = cgate32 = 0; return 1; } \ + PUSH_W(old_pc); if (abrt) { ESP = old_esp; return 1; } \ + } \ + else \ + { \ + uint32_t old_esp = ESP; \ + PUSH_L(old_cs); if (abrt) { cgate16 = cgate32 = 0; return 1; } \ + PUSH_L(old_pc); if (abrt) { ESP = old_esp; return 1; } \ + } + + +static int opCALL_far_w(uint32_t fetchdat) +{ + uint32_t old_cs, old_pc; + uint16_t new_cs, new_pc; + + new_pc = getwordf(); + new_cs = getword(); if (abrt) return 1; + + CALL_FAR_w(new_cs, new_pc); + CPU_BLOCK_END(); + + return 0; +} +static int opCALL_far_l(uint32_t fetchdat) +{ + uint32_t old_cs, old_pc; + uint32_t new_cs, new_pc; + + new_pc = getlong(); + new_cs = getword(); if (abrt) return 1; + + CALL_FAR_l(new_cs, new_pc); + CPU_BLOCK_END(); + + return 0; +} + + +static int opFF_w_a16(uint32_t fetchdat) +{ + uint16_t old_cs, new_cs; + uint32_t old_pc, new_pc; + + uint16_t temp; + + fetch_ea_16(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*INC w*/ + temp = geteaw(); if (abrt) return 1; + seteaw(temp + 1); if (abrt) return 1; + setadd16nc(temp, 1); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + break; + case 0x08: /*DEC w*/ + temp = geteaw(); if (abrt) return 1; + seteaw(temp - 1); if (abrt) return 1; + setsub16nc(temp, 1); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + break; + case 0x10: /*CALL*/ + new_pc = geteaw(); if (abrt) return 1; + PUSH_W(cpu_state.pc); + cpu_state.pc = new_pc; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((mod == 3) ? 7 : 10); + break; + case 0x18: /*CALL far*/ + new_pc = readmemw(easeg, eaaddr); + new_cs = readmemw(easeg, (eaaddr + 2)); if (abrt) return 1; + + CALL_FAR_w(new_cs, new_pc); + CPU_BLOCK_END(); + break; + case 0x20: /*JMP*/ + new_pc = geteaw(); if (abrt) return 1; + cpu_state.pc = new_pc; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((mod == 3) ? 7 : 10); + break; + case 0x28: /*JMP far*/ + oxpc = cpu_state.pc; + new_pc = readmemw(easeg, eaaddr); + new_cs = readmemw(easeg, eaaddr + 2); if (abrt) return 1; + cpu_state.pc = new_pc; + loadcsjmp(new_cs, oxpc); if (abrt) return 1; + CPU_BLOCK_END(); + break; + case 0x30: /*PUSH w*/ + temp = geteaw(); if (abrt) return 1; + PUSH_W(temp); + CLOCK_CYCLES((mod == 3) ? 2 : 5); + break; + + default: +// fatal("Bad FF opcode %02X\n",rmdat&0x38); + x86illegal(); + } + return abrt; +} +static int opFF_w_a32(uint32_t fetchdat) +{ + uint16_t old_cs, new_cs; + uint32_t old_pc, new_pc; + + uint16_t temp; + + fetch_ea_32(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*INC w*/ + temp = geteaw(); if (abrt) return 1; + seteaw(temp + 1); if (abrt) return 1; + setadd16nc(temp, 1); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + break; + case 0x08: /*DEC w*/ + temp = geteaw(); if (abrt) return 1; + seteaw(temp - 1); if (abrt) return 1; + setsub16nc(temp, 1); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + break; + case 0x10: /*CALL*/ + new_pc = geteaw(); if (abrt) return 1; + PUSH_W(cpu_state.pc); + cpu_state.pc = new_pc; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((mod == 3) ? 7 : 10); + break; + case 0x18: /*CALL far*/ + new_pc = readmemw(easeg, eaaddr); + new_cs = readmemw(easeg, (eaaddr + 2)); if (abrt) return 1; + + CALL_FAR_w(new_cs, new_pc); + CPU_BLOCK_END(); + break; + case 0x20: /*JMP*/ + new_pc = geteaw(); if (abrt) return 1; + cpu_state.pc = new_pc; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((mod == 3) ? 7 : 10); + break; + case 0x28: /*JMP far*/ + oxpc = cpu_state.pc; + new_pc = readmemw(easeg, eaaddr); + new_cs = readmemw(easeg, eaaddr + 2); if (abrt) return 1; + cpu_state.pc = new_pc; + loadcsjmp(new_cs, oxpc); if (abrt) return 1; + CPU_BLOCK_END(); + break; + case 0x30: /*PUSH w*/ + temp = geteaw(); if (abrt) return 1; + PUSH_W(temp); + CLOCK_CYCLES((mod == 3) ? 2 : 5); + break; + + default: +// fatal("Bad FF opcode %02X\n",rmdat&0x38); + x86illegal(); + } + return abrt; +} + +static int opFF_l_a16(uint32_t fetchdat) +{ + uint16_t old_cs, new_cs; + uint32_t old_pc, new_pc; + + uint32_t temp; + + fetch_ea_16(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*INC l*/ + temp = geteal(); if (abrt) return 1; + seteal(temp + 1); if (abrt) return 1; + setadd32nc(temp, 1); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + break; + case 0x08: /*DEC l*/ + temp = geteal(); if (abrt) return 1; + seteal(temp - 1); if (abrt) return 1; + setsub32nc(temp, 1); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + break; + case 0x10: /*CALL*/ + new_pc = geteal(); if (abrt) return 1; + PUSH_L(cpu_state.pc); + cpu_state.pc = new_pc; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((mod == 3) ? 7 : 10); + break; + case 0x18: /*CALL far*/ + new_pc = readmeml(easeg, eaaddr); + new_cs = readmemw(easeg, (eaaddr + 4)); if (abrt) return 1; + + CALL_FAR_l(new_cs, new_pc); + CPU_BLOCK_END(); + break; + case 0x20: /*JMP*/ + new_pc = geteal(); if (abrt) return 1; + cpu_state.pc = new_pc; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((mod == 3) ? 7 : 10); + break; + case 0x28: /*JMP far*/ + oxpc = cpu_state.pc; + new_pc = readmeml(easeg, eaaddr); + new_cs = readmemw(easeg, eaaddr + 4); if (abrt) return 1; + cpu_state.pc = new_pc; + loadcsjmp(new_cs, oxpc); if (abrt) return 1; + CPU_BLOCK_END(); + break; + case 0x30: /*PUSH l*/ + temp = geteal(); if (abrt) return 1; + PUSH_L(temp); + CLOCK_CYCLES((mod == 3) ? 2 : 5); + break; + + default: +// fatal("Bad FF opcode %02X\n",rmdat&0x38); + x86illegal(); + } + return abrt; +} +static int opFF_l_a32(uint32_t fetchdat) +{ + uint16_t old_cs, new_cs; + uint32_t old_pc, new_pc; + + uint32_t temp; + + fetch_ea_32(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*INC l*/ + temp = geteal(); if (abrt) return 1; + seteal(temp + 1); if (abrt) return 1; + setadd32nc(temp, 1); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + break; + case 0x08: /*DEC l*/ + temp = geteal(); if (abrt) return 1; + seteal(temp - 1); if (abrt) return 1; + setsub32nc(temp, 1); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + break; + case 0x10: /*CALL*/ + new_pc = geteal(); if (abrt) return 1; + PUSH_L(cpu_state.pc); if (abrt) return 1; + cpu_state.pc = new_pc; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((mod == 3) ? 7 : 10); + break; + case 0x18: /*CALL far*/ + new_pc = readmeml(easeg, eaaddr); + new_cs = readmemw(easeg, (eaaddr + 4)); if (abrt) return 1; + + CALL_FAR_l(new_cs, new_pc); + CPU_BLOCK_END(); + break; + case 0x20: /*JMP*/ + new_pc = geteal(); if (abrt) return 1; + cpu_state.pc = new_pc; + CPU_BLOCK_END(); + if (is486) CLOCK_CYCLES(5); + else CLOCK_CYCLES((mod == 3) ? 7 : 10); + break; + case 0x28: /*JMP far*/ + oxpc = cpu_state.pc; + new_pc = readmeml(easeg, eaaddr); + new_cs = readmemw(easeg, eaaddr + 4); if (abrt) return 1; + cpu_state.pc = new_pc; + loadcsjmp(new_cs, oxpc); if (abrt) return 1; + CPU_BLOCK_END(); + break; + case 0x30: /*PUSH l*/ + temp = geteal(); if (abrt) return 1; + PUSH_L(temp); + CLOCK_CYCLES((mod == 3) ? 2 : 5); + break; + + default: +// fatal("Bad FF opcode %02X\n",rmdat&0x38); + x86illegal(); + } + return abrt; +} diff --git a/src/x86_ops_flag.h b/src/x86_ops_flag.h new file mode 100644 index 000000000..6f4a2e800 --- /dev/null +++ b/src/x86_ops_flag.h @@ -0,0 +1,190 @@ +static int opCMC(uint32_t fetchdat) +{ + flags_rebuild(); + flags ^= C_FLAG; + CLOCK_CYCLES(2); + return 0; +} + + +static int opCLC(uint32_t fetchdat) +{ + flags_rebuild(); + flags &= ~C_FLAG; + CLOCK_CYCLES(2); + return 0; +} +static int opCLD(uint32_t fetchdat) +{ + flags &= ~D_FLAG; + CLOCK_CYCLES(2); + return 0; +} +static int opCLI(uint32_t fetchdat) +{ + if (!IOPLp) + { + x86gpf(NULL,0); + return 1; + } + else + flags &= ~I_FLAG; + + CPU_BLOCK_END(); + + CLOCK_CYCLES(3); + return 0; +} + +static int opSTC(uint32_t fetchdat) +{ + flags_rebuild(); + flags |= C_FLAG; + CLOCK_CYCLES(2); + return 0; +} +static int opSTD(uint32_t fetchdat) +{ + flags |= D_FLAG; + CLOCK_CYCLES(2); + return 0; +} +static int opSTI(uint32_t fetchdat) +{ + if (!IOPLp) + { + x86gpf(NULL,0); + return 1; + } + else + flags |= I_FLAG; + + CPU_BLOCK_END(); + + CLOCK_CYCLES(2); + return 0; +} + +static int opSAHF(uint32_t fetchdat) +{ + flags_rebuild(); + flags = (flags & 0xff00) | (AH & 0xd5) | 2; + CLOCK_CYCLES(3); + + codegen_flags_changed = 0; + + return 0; +} +static int opLAHF(uint32_t fetchdat) +{ + flags_rebuild(); + AH = flags & 0xff; + CLOCK_CYCLES(3); + return 0; +} + +static int opPUSHF(uint32_t fetchdat) +{ + if ((eflags & VM_FLAG) && (IOPL < 3)) + { + x86gpf(NULL,0); + return 1; + } + flags_rebuild(); + PUSH_W(flags); + CLOCK_CYCLES(4); + return abrt; +} +static int opPUSHFD(uint32_t fetchdat) +{ + uint16_t tempw; + if ((eflags & VM_FLAG) && (IOPL < 3)) + { + x86gpf(NULL, 0); + return 1; + } + if (CPUID) tempw = eflags & 0x24; + else tempw = eflags & 4; + flags_rebuild(); + PUSH_L(flags | (tempw << 16)); + CLOCK_CYCLES(4); + return abrt; +} + +static int opPOPF_286(uint32_t fetchdat) +{ + uint16_t tempw; + + if ((eflags & VM_FLAG) && (IOPL < 3)) + { + x86gpf(NULL, 0); + return 1; + } + + tempw = POP_W(); if (abrt) return 1; + + if (!(msw & 1)) flags = (flags & 0x7000) | (tempw & 0x0fd5) | 2; + else if (!(CPL)) flags = (tempw & 0x7fd5) | 2; + else if (IOPLp) flags = (flags & 0x3000) | (tempw & 0x4fd5) | 2; + else flags = (flags & 0x3200) | (tempw & 0x4dd5) | 2; + flags_extract(); + + CLOCK_CYCLES(5); + + codegen_flags_changed = 0; + + return 0; +} +static int opPOPF(uint32_t fetchdat) +{ + uint16_t tempw; + + if ((eflags & VM_FLAG) && (IOPL < 3)) + { + x86gpf(NULL, 0); + return 1; + } + + tempw = POP_W(); if (abrt) return 1; + + if (!(CPL) || !(msw & 1)) flags = (tempw & 0x7fd5) | 2; + else if (IOPLp) flags = (flags & 0x3000) | (tempw & 0x4fd5) | 2; + else flags = (flags & 0x3200) | (tempw & 0x4dd5) | 2; + flags_extract(); + + CLOCK_CYCLES(5); + + codegen_flags_changed = 0; + + return 0; +} +static int opPOPFD(uint32_t fetchdat) +{ + uint32_t templ; + + if ((eflags & VM_FLAG) && (IOPL < 3)) + { + x86gpf(NULL, 0); + return 1; + } + + templ = POP_L(); if (abrt) return 1; + + if (!(CPL) || !(msw & 1)) flags = (templ & 0x7fd5) | 2; + else if (IOPLp) flags = (flags & 0x3000) | (templ & 0x4fd5) | 2; + else flags = (flags & 0x3200) | (templ & 0x4dd5) | 2; + + templ &= is486 ? 0x240000 : 0; + templ |= ((eflags&3) << 16); + if (CPUID) eflags = (templ >> 16) & 0x27; + else if (is486) eflags = (templ >> 16) & 7; + else eflags = (templ >> 16) & 3; + + flags_extract(); + + CLOCK_CYCLES(5); + + codegen_flags_changed = 0; + + return 0; +} diff --git a/src/x86_ops_fpu.h b/src/x86_ops_fpu.h new file mode 100644 index 000000000..8c264374f --- /dev/null +++ b/src/x86_ops_fpu.h @@ -0,0 +1,82 @@ +static int opESCAPE_d8_a16(uint32_t fetchdat) +{ + return x86_opcodes_d8_a16[(fetchdat >> 3) & 0x1f](fetchdat); +} +static int opESCAPE_d8_a32(uint32_t fetchdat) +{ + return x86_opcodes_d8_a32[(fetchdat >> 3) & 0x1f](fetchdat); +} + +static int opESCAPE_d9_a16(uint32_t fetchdat) +{ + return x86_opcodes_d9_a16[fetchdat & 0xff](fetchdat); +} +static int opESCAPE_d9_a32(uint32_t fetchdat) +{ + return x86_opcodes_d9_a32[fetchdat & 0xff](fetchdat); +} + +static int opESCAPE_da_a16(uint32_t fetchdat) +{ + return x86_opcodes_da_a16[fetchdat & 0xff](fetchdat); +} +static int opESCAPE_da_a32(uint32_t fetchdat) +{ + return x86_opcodes_da_a32[fetchdat & 0xff](fetchdat); +} + +static int opESCAPE_db_a16(uint32_t fetchdat) +{ + return x86_opcodes_db_a16[fetchdat & 0xff](fetchdat); +} +static int opESCAPE_db_a32(uint32_t fetchdat) +{ + return x86_opcodes_db_a32[fetchdat & 0xff](fetchdat); +} + +static int opESCAPE_dc_a16(uint32_t fetchdat) +{ + return x86_opcodes_dc_a16[(fetchdat >> 3) & 0x1f](fetchdat); +} +static int opESCAPE_dc_a32(uint32_t fetchdat) +{ + return x86_opcodes_dc_a32[(fetchdat >> 3) & 0x1f](fetchdat); +} + +static int opESCAPE_dd_a16(uint32_t fetchdat) +{ + return x86_opcodes_dd_a16[fetchdat & 0xff](fetchdat); +} +static int opESCAPE_dd_a32(uint32_t fetchdat) +{ + return x86_opcodes_dd_a32[fetchdat & 0xff](fetchdat); +} + +static int opESCAPE_de_a16(uint32_t fetchdat) +{ + return x86_opcodes_de_a16[fetchdat & 0xff](fetchdat); +} +static int opESCAPE_de_a32(uint32_t fetchdat) +{ + return x86_opcodes_de_a32[fetchdat & 0xff](fetchdat); +} + +static int opESCAPE_df_a16(uint32_t fetchdat) +{ + return x86_opcodes_df_a16[fetchdat & 0xff](fetchdat); +} +static int opESCAPE_df_a32(uint32_t fetchdat) +{ + return x86_opcodes_df_a32[fetchdat & 0xff](fetchdat); +} + +static int opWAIT(uint32_t fetchdat) +{ + if ((cr0 & 0xa) == 0xa) + { + x86_int(7); + return 1; + } + CLOCK_CYCLES(4); + return 0; +} diff --git a/src/x86_ops_i686.h b/src/x86_ops_i686.h new file mode 100644 index 000000000..5888b1d66 --- /dev/null +++ b/src/x86_ops_i686.h @@ -0,0 +1,651 @@ +static int internal_illegal() +{ + cpu_state.pc = oldpc; + x86gpf(NULL, 0); + return 1; +} + +/* 0 = Limit 0-15 + 1 = Base 0-15 + 2 = Base 16-23 (bits 0-7), Access rights + 8-11 Type + 12 S + 13, 14 DPL + 15 P + 3 = Limit 16-19 (bits 0-3), Base 24-31 (bits 8-15), granularity, etc. + 4 A + 6 DB + 7 G */ + +static void make_seg_data(uint16_t *seg_data, uint32_t base, uint32_t limit, uint8_t type, uint8_t s, uint8_t dpl, uint8_t p, uint8_t g, uint8_t db, uint8_t a) +{ + seg_data[0] = limit & 0xFFFF; + seg_data[1] = base & 0xFFFF; + seg_data[2] = ((base >> 16) & 0xFF) | (type << 8) | (p << 15) | (dpl << 13) | (s << 12); + seg_data[3] = ((limit >> 16) & 0xF) | (a << 4) | (db << 6) | (g << 7) | ((base >> 16) & 0xFF00); +} + +static int opSYSENTER(uint32_t fetchdat) +{ + uint16_t sysenter_cs_seg_data[4]; + uint16_t sysenter_ss_seg_data[4]; + + pclog("SYSENTER called\n"); + + if (!(cr0 & 1)) return internal_illegal(); + if (!(cs_msr & 0xFFFC)) return internal_illegal(); + + pclog("SYSENTER started:\n"); + pclog("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, _cs.base, _cs.limit, _cs.access, _cs.seg, _cs.limit_low, _cs.limit_high, _cs.checked); + pclog("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, _ss.base, _ss.limit, _ss.access, _ss.seg, _ss.limit_low, _ss.limit_high, _ss.checked); + pclog("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); + pclog("Other information: eip=%08X esp=%08X eflags=%04X flags=%04X use32=%04X stack32=%i\n", cpu_state.pc, ESP, eflags, flags, use32, stack32); + + ESP = esp_msr; + cpu_state.pc = eip_msr; + + /* Set VM, RF, and IF to 0. */ + eflags &= ~0x0003; + flags &= ~0x0200; + + CS = (cs_msr & 0xFFFC); + make_seg_data(sysenter_cs_seg_data, 0, 0xFFFFF, 11, 1, 0, 1, 1, 1, 0); + do_seg_load(&_cs, sysenter_cs_seg_data); + use32 = 0x300; + + SS = ((cs_msr + 8) & 0xFFFC); + make_seg_data(sysenter_ss_seg_data, 0, 0xFFFFF, 3, 1, 0, 1, 1, 1, 0); + do_seg_load(&_ss, sysenter_ss_seg_data); + stack32 = 1; + + cycles -= timing_jmp_pm; + + CPU_BLOCK_END(); + + pclog("SYSENTER completed:\n"); + pclog("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, _cs.base, _cs.limit, _cs.access, _cs.seg, _cs.limit_low, _cs.limit_high, _cs.checked); + pclog("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, _ss.base, _ss.limit, _ss.access, _ss.seg, _ss.limit_low, _ss.limit_high, _ss.checked); + pclog("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); + pclog("Other information: eip=%08X esp=%08X eflags=%04X flags=%04X use32=%04X stack32=%i\n", cpu_state.pc, ESP, eflags, flags, use32, stack32); + + return 0; +} + +static int opSYSEXIT(uint32_t fetchdat) +{ + uint16_t sysexit_cs_seg_data[4]; + uint16_t sysexit_ss_seg_data[4]; + + pclog("SYSEXIT called\n"); + + if (!(cs_msr & 0xFFFC)) return internal_illegal(); + if (!(cr0 & 1)) return internal_illegal(); + if (CS & 3) return internal_illegal(); + + pclog("SYSEXIT completed:\n"); + pclog("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, _cs.base, _cs.limit, _cs.access, _cs.seg, _cs.limit_low, _cs.limit_high, _cs.checked); + pclog("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, _ss.base, _ss.limit, _ss.access, _ss.seg, _ss.limit_low, _ss.limit_high, _ss.checked); + pclog("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); + pclog("Other information: eip=%08X esp=%08X eflags=%04X flags=%04X use32=%04X stack32=%i ECX=%08X EDX=%08X\n", cpu_state.pc, ESP, eflags, flags, use32, stack32, ECX, EDX); + + ESP = ECX; + cpu_state.pc = EDX; + + CS = ((cs_msr + 16) & 0xFFFC) | 3; + make_seg_data(sysexit_cs_seg_data, 0, 0xFFFFF, 11, 1, 3, 1, 1, 1, 0); + do_seg_load(&_cs, sysexit_cs_seg_data); + use32 = 0x300; + + SS = CS + 8; + make_seg_data(sysexit_ss_seg_data, 0, 0xFFFFF, 3, 1, 3, 1, 1, 1, 0); + do_seg_load(&_ss, sysexit_ss_seg_data); + stack32 = 1; + + flushmmucache_cr3(); + + cycles -= timing_jmp_pm; + + CPU_BLOCK_END(); + + pclog("SYSEXIT completed:\n"); + pclog("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, _cs.base, _cs.limit, _cs.access, _cs.seg, _cs.limit_low, _cs.limit_high, _cs.checked); + pclog("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, _ss.base, _ss.limit, _ss.access, _ss.seg, _ss.limit_low, _ss.limit_high, _ss.checked); + pclog("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); + pclog("Other information: eip=%08X esp=%08X eflags=%04X flags=%04X use32=%04X stack32=%i ECX=%08X EDX=%08X\n", cpu_state.pc, ESP, eflags, flags, use32, stack32, ECX, EDX); + + return 0; +} + +static int opFXSAVESTOR_a16(uint32_t fetchdat) +{ + uint8_t fxinst = 0; + uint16_t twd = x87_gettag(); + uint16_t old_eaaddr = 0; + int old_ismmx = ismmx; + uint8_t ftwb = 0; + uint16_t rec_ftw = 0; + uint16_t fpus = 0; + + if (CPUID < 0x650) return ILLEGAL(fetchdat); + + FP_ENTER(); + + fetch_ea_16(fetchdat); + + if (eaaddr & 0xf) + { + pclog("Effective address %04X not on 16-byte boundary\n", eaaddr); + x86gpf(NULL, 0); + return 1; + } + + fxinst = (rmdat >> 3) & 7; + + if ((fxinst > 1) || (mod == 3)) + { + if (fxinst > 1) pclog("FX instruction is: %02X\n", fxinst); + if (mod == 3) pclog("MOD is 3\n"); + + cpu_state.pc = oldpc; + + x86illegal(); + return 0; + } + + FP_ENTER(); + + old_eaaddr = eaaddr; + + if (fxinst == 1) + { + /* FXRSTOR */ + // pclog("FXRSTOR issued\n"); + + npxc = readmemw(easeg, eaaddr); + fpus = readmemw(easeg, eaaddr + 2); + npxc = (npxc & ~FPU_CW_Reserved_Bits) | 0x0040; + TOP = (fpus >> 11) & 7; + npxs &= fpus & ~0x3800; + + /* foo = readmemw(easeg, eaaddr + 6) & 0x7FF; */ + + x87_pc_off = readmeml(easeg, eaaddr+8); + x87_pc_seg = readmemw(easeg, eaaddr+12); + /* if (cr0 & 1) + { + x87_pc_seg &= 0xFFFC; + x87_pc_seg |= ((_cs.access >> 5) & 3); + } */ + + ftwb = readmemb(easeg, eaaddr + 4); + + if (ftwb & 0x01) rec_ftw |= 0x0003; + if (ftwb & 0x02) rec_ftw |= 0x000C; + if (ftwb & 0x04) rec_ftw |= 0x0030; + if (ftwb & 0x08) rec_ftw |= 0x00C0; + if (ftwb & 0x10) rec_ftw |= 0x0300; + if (ftwb & 0x20) rec_ftw |= 0x0C00; + if (ftwb & 0x40) rec_ftw |= 0x3000; + if (ftwb & 0x80) rec_ftw |= 0xC000; + + x87_op_off = readmeml(easeg, eaaddr+16); + x87_op_off |= (readmemw(easeg, eaaddr + 6) >> 12) << 16; + x87_op_seg = readmemw(easeg, eaaddr+20); + /* if (cr0 & 1) + { + x87_op_seg &= 0xFFFC; + x87_op_seg |= ((_ds.access >> 5) & 3); + } */ + + eaaddr = old_eaaddr + 32; + x87_ldmmx(&MM[0]); x87_ld_frstor(0); + + eaaddr = old_eaaddr + 48; + x87_ldmmx(&MM[1]); x87_ld_frstor(1); + + eaaddr = old_eaaddr + 64; + x87_ldmmx(&MM[2]); x87_ld_frstor(2); + + eaaddr = old_eaaddr + 80; + x87_ldmmx(&MM[3]); x87_ld_frstor(3); + + eaaddr = old_eaaddr + 96; + x87_ldmmx(&MM[4]); x87_ld_frstor(4); + + eaaddr = old_eaaddr + 112; + x87_ldmmx(&MM[5]); x87_ld_frstor(5); + + eaaddr = old_eaaddr + 128; + x87_ldmmx(&MM[6]); x87_ld_frstor(6); + + eaaddr = old_eaaddr + 144; + x87_ldmmx(&MM[7]); x87_ld_frstor(7); + + ismmx = 0; + /*Horrible hack, but as PCem doesn't keep the FPU stack in 80-bit precision at all times + something like this is needed*/ + if (MM[0].w[4] == 0xffff && MM[1].w[4] == 0xffff && MM[2].w[4] == 0xffff && MM[3].w[4] == 0xffff && + MM[4].w[4] == 0xffff && MM[5].w[4] == 0xffff && MM[6].w[4] == 0xffff && MM[7].w[4] == 0xffff && + !TOP && !(*(uint64_t *)tag)) + ismmx = old_ismmx; + + x87_settag(rec_ftw); + + CLOCK_CYCLES((cr0 & 1) ? 34 : 44); + + if(abrt) pclog("FXRSTOR: abrt != 0\n"); + } + else + { + /* FXSAVE */ + // pclog("FXSAVE issued\n"); + + if (twd & 0x0003 == 0x0003) ftwb |= 0x01; + if (twd & 0x000C == 0x000C) ftwb |= 0x02; + if (twd & 0x0030 == 0x0030) ftwb |= 0x04; + if (twd & 0x00C0 == 0x00C0) ftwb |= 0x08; + if (twd & 0x0300 == 0x0300) ftwb |= 0x10; + if (twd & 0x0C00 == 0x0C00) ftwb |= 0x20; + if (twd & 0x3000 == 0x3000) ftwb |= 0x40; + if (twd & 0xC000 == 0xC000) ftwb |= 0x80; + + writememw(easeg,eaaddr,npxc); + writememw(easeg,eaaddr+2,npxs); + writememb(easeg,eaaddr+4,ftwb); + + writememw(easeg,eaaddr+6,(x87_op_off>>16)<<12); + writememl(easeg,eaaddr+8,x87_pc_off); + writememw(easeg,eaaddr+12,x87_pc_seg); + + writememl(easeg,eaaddr+16,x87_op_off); + writememw(easeg,eaaddr+20,x87_op_seg); + + eaaddr = old_eaaddr + 32; + ismmx ? x87_stmmx(MM[0]) : x87_st_fsave(0); + + eaaddr = old_eaaddr + 48; + ismmx ? x87_stmmx(MM[1]) : x87_st_fsave(1); + + eaaddr = old_eaaddr + 64; + ismmx ? x87_stmmx(MM[2]) : x87_st_fsave(2); + + eaaddr = old_eaaddr + 80; + ismmx ? x87_stmmx(MM[3]) : x87_st_fsave(3); + + eaaddr = old_eaaddr + 96; + ismmx ? x87_stmmx(MM[4]) : x87_st_fsave(4); + + eaaddr = old_eaaddr + 112; + ismmx ? x87_stmmx(MM[5]) : x87_st_fsave(5); + + eaaddr = old_eaaddr + 128; + ismmx ? x87_stmmx(MM[6]) : x87_st_fsave(6); + + eaaddr = old_eaaddr + 144; + ismmx ? x87_stmmx(MM[7]) : x87_st_fsave(7); + + eaaddr = old_eaaddr; + + CLOCK_CYCLES((cr0 & 1) ? 56 : 67); + + if(abrt) pclog("FXSAVE: abrt != 0\n"); + } + + return abrt; +} + +static int opFXSAVESTOR_a32(uint32_t fetchdat) +{ + uint8_t fxinst = 0; + uint16_t twd = x87_gettag(); + uint32_t old_eaaddr = 0; + int old_ismmx = ismmx; + uint8_t ftwb = 0; + uint16_t rec_ftw = 0; + uint16_t fpus = 0; + + if (CPUID < 0x650) return ILLEGAL(fetchdat); + + FP_ENTER(); + + fetch_ea_32(fetchdat); + + if (eaaddr & 0xf) + { + pclog("Effective address %08X not on 16-byte boundary\n", eaaddr); + x86gpf(NULL, 0); + return 1; + } + + fxinst = (rmdat >> 3) & 7; + + if ((fxinst > 1) || (mod == 3)) + { + if (fxinst > 1) pclog("FX instruction is: %02X\n", fxinst); + if (mod == 3) pclog("MOD is 3\n"); + + cpu_state.pc = oldpc; + + x86illegal(); + return 0; + } + + FP_ENTER(); + + old_eaaddr = eaaddr; + + if (fxinst == 1) + { + /* FXRSTOR */ + // pclog("FXRSTOR issued\n"); + + npxc = readmemw(easeg, eaaddr); + fpus = readmemw(easeg, eaaddr + 2); + npxc = (npxc & ~FPU_CW_Reserved_Bits) | 0x0040; + TOP = (fpus >> 11) & 7; + npxs &= fpus & ~0x3800; + + /* foo = readmemw(easeg, eaaddr + 6) & 0x7FF; */ + + x87_pc_off = readmeml(easeg, eaaddr+8); + x87_pc_seg = readmemw(easeg, eaaddr+12); + /* if (cr0 & 1) + { + x87_pc_seg &= 0xFFFC; + x87_pc_seg |= ((_cs.access >> 5) & 3); + } */ + + ftwb = readmemb(easeg, eaaddr + 4); + + if (ftwb & 0x01) rec_ftw |= 0x0003; + if (ftwb & 0x02) rec_ftw |= 0x000C; + if (ftwb & 0x04) rec_ftw |= 0x0030; + if (ftwb & 0x08) rec_ftw |= 0x00C0; + if (ftwb & 0x10) rec_ftw |= 0x0300; + if (ftwb & 0x20) rec_ftw |= 0x0C00; + if (ftwb & 0x40) rec_ftw |= 0x3000; + if (ftwb & 0x80) rec_ftw |= 0xC000; + + x87_op_off = readmeml(easeg, eaaddr+16); + x87_op_off |= (readmemw(easeg, eaaddr + 6) >> 12) << 16; + x87_op_seg = readmemw(easeg, eaaddr+20); + /* if (cr0 & 1) + { + x87_op_seg &= 0xFFFC; + x87_op_seg |= ((_ds.access >> 5) & 3); + } */ + + eaaddr = old_eaaddr + 32; + x87_ldmmx(&MM[0]); x87_ld_frstor(0); + + eaaddr = old_eaaddr + 48; + x87_ldmmx(&MM[1]); x87_ld_frstor(1); + + eaaddr = old_eaaddr + 64; + x87_ldmmx(&MM[2]); x87_ld_frstor(2); + + eaaddr = old_eaaddr + 80; + x87_ldmmx(&MM[3]); x87_ld_frstor(3); + + eaaddr = old_eaaddr + 96; + x87_ldmmx(&MM[4]); x87_ld_frstor(4); + + eaaddr = old_eaaddr + 112; + x87_ldmmx(&MM[5]); x87_ld_frstor(5); + + eaaddr = old_eaaddr + 128; + x87_ldmmx(&MM[6]); x87_ld_frstor(6); + + eaaddr = old_eaaddr + 144; + x87_ldmmx(&MM[7]); x87_ld_frstor(7); + + ismmx = 0; + /*Horrible hack, but as PCem doesn't keep the FPU stack in 80-bit precision at all times + something like this is needed*/ + if (MM[0].w[4] == 0xffff && MM[1].w[4] == 0xffff && MM[2].w[4] == 0xffff && MM[3].w[4] == 0xffff && + MM[4].w[4] == 0xffff && MM[5].w[4] == 0xffff && MM[6].w[4] == 0xffff && MM[7].w[4] == 0xffff && + !TOP && !(*(uint64_t *)tag)) + ismmx = old_ismmx; + + x87_settag(rec_ftw); + + CLOCK_CYCLES((cr0 & 1) ? 34 : 44); + + if(abrt) pclog("FXRSTOR: abrt != 0\n"); + } + else + { + /* FXSAVE */ + // pclog("FXSAVE issued\n"); + + if (twd & 0x0003 == 0x0003) ftwb |= 0x01; + if (twd & 0x000C == 0x000C) ftwb |= 0x02; + if (twd & 0x0030 == 0x0030) ftwb |= 0x04; + if (twd & 0x00C0 == 0x00C0) ftwb |= 0x08; + if (twd & 0x0300 == 0x0300) ftwb |= 0x10; + if (twd & 0x0C00 == 0x0C00) ftwb |= 0x20; + if (twd & 0x3000 == 0x3000) ftwb |= 0x40; + if (twd & 0xC000 == 0xC000) ftwb |= 0x80; + + writememw(easeg,eaaddr,npxc); + writememw(easeg,eaaddr+2,npxs); + writememb(easeg,eaaddr+4,ftwb); + + writememw(easeg,eaaddr+6,(x87_op_off>>16)<<12); + writememl(easeg,eaaddr+8,x87_pc_off); + writememw(easeg,eaaddr+12,x87_pc_seg); + + writememl(easeg,eaaddr+16,x87_op_off); + writememw(easeg,eaaddr+20,x87_op_seg); + + eaaddr = old_eaaddr + 32; + ismmx ? x87_stmmx(MM[0]) : x87_st_fsave(0); + + eaaddr = old_eaaddr + 48; + ismmx ? x87_stmmx(MM[1]) : x87_st_fsave(1); + + eaaddr = old_eaaddr + 64; + ismmx ? x87_stmmx(MM[2]) : x87_st_fsave(2); + + eaaddr = old_eaaddr + 80; + ismmx ? x87_stmmx(MM[3]) : x87_st_fsave(3); + + eaaddr = old_eaaddr + 96; + ismmx ? x87_stmmx(MM[4]) : x87_st_fsave(4); + + eaaddr = old_eaaddr + 112; + ismmx ? x87_stmmx(MM[5]) : x87_st_fsave(5); + + eaaddr = old_eaaddr + 128; + ismmx ? x87_stmmx(MM[6]) : x87_st_fsave(6); + + eaaddr = old_eaaddr + 144; + ismmx ? x87_stmmx(MM[7]) : x87_st_fsave(7); + + eaaddr = old_eaaddr; + + CLOCK_CYCLES((cr0 & 1) ? 56 : 67); + + if(abrt) pclog("FXSAVE: abrt != 0\n"); + } + + return abrt; +} + +#define AMD_SYSCALL_EIP (star & 0xFFFFFFFF) +#define AMD_SYSCALL_SB ((star >> 32) & 0xFFFF) +#define AMD_SYSRET_SB ((star >> 48) & 0xFFFF) + +/* 0F 05 */ +static int opSYSCALL(uint32_t fetchdat) +{ + uint16_t syscall_cs_seg_data[4] = {0, 0, 0, 0}; + uint16_t syscall_ss_seg_data[4] = {0, 0, 0, 0}; + + if (!(cr0 & 1)) return internal_illegal(); + if (!AMD_SYSCALL_SB) return internal_illegal(); + + /* Set VM, IF, RF to 0. */ + /* eflags &= ~0x00030200; + flags &= ~0x0200; */ + + /* Let's do this by the AMD spec. */ + ECX = cpu_state.pc; + cpu_state.pc = AMD_SYSCALL_EIP; + + eflags &= ~0x0002; + flags &= ~0x0200; + + /* CS */ + _cs.seg = AMD_SYSCALL_SB & ~7; + if (cs_msr & 4) + { + if (_cs.seg >= ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X CS\n",cs_msr,ldt.limit); + x86gpf(NULL, cs_msr & ~3); + return 1; + } + _cs.seg +=ldt.base; + } + else + { + if (_cs.seg >= gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X CS\n",cs_msr,gdt.limit); + x86gpf(NULL, cs_msr & ~3); + return 1; + } + _cs.seg += gdt.base; + } + cpl_override = 1; + + syscall_cs_seg_data[0] = 0xFFFF; + syscall_cs_seg_data[1] = 0; + syscall_cs_seg_data[2] = 0x9B00; + syscall_cs_seg_data[3] = 0xC0; + + cpl_override = 0; + + use32 = 0x300; + CS = (AMD_SYSCALL_SB & ~3) | 0; + + do_seg_load(&_cs, syscall_cs_seg_data); + use32 = 0x300; + + CS = (CS & 0xFFFC) | 0; + + _cs.limit = 0xFFFFFFFF; + _cs.limit_high = 0xFFFFFFFF; + + /* SS */ + syscall_ss_seg_data[0] = 0xFFFF; + syscall_ss_seg_data[1] = 0; + syscall_ss_seg_data[2] = 0x9300; + syscall_ss_seg_data[3] = 0xC0; + do_seg_load(&_ss, syscall_ss_seg_data); + _ss.seg = (AMD_SYSCALL_SB + 8) & 0xFFFC; + stack32 = 1; + + _ss.limit = 0xFFFFFFFF; + _ss.limit_high = 0xFFFFFFFF; + + _ss.checked = 0; + + cpu_state.pc = eip_msr; + + CLOCK_CYCLES(20); + + CPU_BLOCK_END(); + + /* pclog("SYSCALL completed:\n"); + pclog("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, _cs.base, _cs.limit, _cs.access, _cs.seg, _cs.limit_low, _cs.limit_high, _cs.checked); + pclog("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, _ss.base, _ss.limit, _ss.access, _ss.seg, _ss.limit_low, _ss.limit_high, _ss.checked); + pclog("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); + pclog("Other information: eflags=%04X flags=%04X use32=%04X stack32=%i\n", eflags, flags, use32, stack32); */ + + return 0; +} + +/* 0F 07 */ +static int opSYSRET(uint32_t fetchdat) +{ + uint16_t sysret_cs_seg_data[4] = {0, 0, 0, 0}; + uint16_t sysret_ss_seg_data[4] = {0, 0, 0, 0}; + + if (!cs_msr) return internal_illegal(); + if (!(cr0 & 1)) return internal_illegal(); + + cpu_state.pc = ECX; + + eflags |= (1 << 1); + + /* CS */ + _cs.seg = AMD_SYSRET_SB & ~7; + if (cs_msr & 4) + { + if (_cs.seg >= ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X CS\n",cs_msr,ldt.limit); + x86gpf(NULL, cs_msr & ~3); + return 1; + } + _cs.seg +=ldt.base; + } + else + { + if (_cs.seg >= gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X CS\n",cs_msr,gdt.limit); + x86gpf(NULL, cs_msr & ~3); + return 1; + } + _cs.seg += gdt.base; + } + cpl_override = 1; + + sysret_cs_seg_data[0] = 0xFFFF; + sysret_cs_seg_data[1] = 0; + sysret_cs_seg_data[2] = 0xFB00; + sysret_cs_seg_data[3] = 0xC0; + + cpl_override = 0; + + use32 = 0x300; + CS = (AMD_SYSRET_SB & ~3) | 3; + + do_seg_load(&_cs, sysret_cs_seg_data); + flushmmucache_cr3(); + use32 = 0x300; + + CS = (CS & 0xFFFC) | 3; + + _cs.limit = 0xFFFFFFFF; + _cs.limit_high = 0xFFFFFFFF; + + /* SS */ + sysret_ss_seg_data[0] = 0xFFFF; + sysret_ss_seg_data[1] = 0; + sysret_ss_seg_data[2] = 0xF300; + sysret_ss_seg_data[3] = 0xC0; + do_seg_load(&_ss, sysret_ss_seg_data); + _ss.seg = ((AMD_SYSRET_SB + 8) & 0xFFFC) | 3; + stack32 = 1; + + _ss.limit = 0xFFFFFFFF; + _ss.limit_high = 0xFFFFFFFF; + + _ss.checked = 0; + + CLOCK_CYCLES(20); + + CPU_BLOCK_END(); + + /* pclog("SYSRET completed:\n"); + pclog("CS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", CS, _cs.base, _cs.limit, _cs.access, _cs.seg, _cs.limit_low, _cs.limit_high, _cs.checked); + pclog("SS (%04X): base=%08X, limit=%08X, access=%02X, seg=%04X, limit_low=%08X, limit_high=%08X, checked=%i\n", SS, _ss.base, _ss.limit, _ss.access, _ss.seg, _ss.limit_low, _ss.limit_high, _ss.checked); + pclog("Model specific registers: cs_msr=%04X, esp_msr=%08X, eip_msr=%08X\n", cs_msr, esp_msr, eip_msr); + pclog("Other information: eflags=%04X flags=%04X use32=%04X stack32=%i ECX=%08X EDX=%08X\n", eflags, flags, use32, stack32, ECX, EDX); */ + + return 0; +} diff --git a/src/x86_ops_inc_dec.h b/src/x86_ops_inc_dec.h new file mode 100644 index 000000000..be4017bf2 --- /dev/null +++ b/src/x86_ops_inc_dec.h @@ -0,0 +1,86 @@ +#define INC_DEC_OP(name, reg, inc, setflags) \ + static int op ## name (uint32_t fetchdat) \ + { \ + setflags(reg, 1); \ + reg += inc; \ + CLOCK_CYCLES(timing_rr); \ + return 0; \ + } + +INC_DEC_OP(INC_AX, AX, 1, setadd16nc) +INC_DEC_OP(INC_BX, BX, 1, setadd16nc) +INC_DEC_OP(INC_CX, CX, 1, setadd16nc) +INC_DEC_OP(INC_DX, DX, 1, setadd16nc) +INC_DEC_OP(INC_SI, SI, 1, setadd16nc) +INC_DEC_OP(INC_DI, DI, 1, setadd16nc) +INC_DEC_OP(INC_BP, BP, 1, setadd16nc) +INC_DEC_OP(INC_SP, SP, 1, setadd16nc) + +INC_DEC_OP(INC_EAX, EAX, 1, setadd32nc) +INC_DEC_OP(INC_EBX, EBX, 1, setadd32nc) +INC_DEC_OP(INC_ECX, ECX, 1, setadd32nc) +INC_DEC_OP(INC_EDX, EDX, 1, setadd32nc) +INC_DEC_OP(INC_ESI, ESI, 1, setadd32nc) +INC_DEC_OP(INC_EDI, EDI, 1, setadd32nc) +INC_DEC_OP(INC_EBP, EBP, 1, setadd32nc) +INC_DEC_OP(INC_ESP, ESP, 1, setadd32nc) + +INC_DEC_OP(DEC_AX, AX, -1, setsub16nc) +INC_DEC_OP(DEC_BX, BX, -1, setsub16nc) +INC_DEC_OP(DEC_CX, CX, -1, setsub16nc) +INC_DEC_OP(DEC_DX, DX, -1, setsub16nc) +INC_DEC_OP(DEC_SI, SI, -1, setsub16nc) +INC_DEC_OP(DEC_DI, DI, -1, setsub16nc) +INC_DEC_OP(DEC_BP, BP, -1, setsub16nc) +INC_DEC_OP(DEC_SP, SP, -1, setsub16nc) + +INC_DEC_OP(DEC_EAX, EAX, -1, setsub32nc) +INC_DEC_OP(DEC_EBX, EBX, -1, setsub32nc) +INC_DEC_OP(DEC_ECX, ECX, -1, setsub32nc) +INC_DEC_OP(DEC_EDX, EDX, -1, setsub32nc) +INC_DEC_OP(DEC_ESI, ESI, -1, setsub32nc) +INC_DEC_OP(DEC_EDI, EDI, -1, setsub32nc) +INC_DEC_OP(DEC_EBP, EBP, -1, setsub32nc) +INC_DEC_OP(DEC_ESP, ESP, -1, setsub32nc) + + +static int opINCDEC_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_16(fetchdat); + temp=geteab(); if (abrt) return 1; + + if (rmdat&0x38) + { + seteab(temp - 1); if (abrt) return 1; + setsub8nc(temp, 1); + } + else + { + seteab(temp + 1); if (abrt) return 1; + setadd8nc(temp, 1); + } + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + return 0; +} +static int opINCDEC_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_32(fetchdat); + temp=geteab(); if (abrt) return 1; + + if (rmdat&0x38) + { + seteab(temp - 1); if (abrt) return 1; + setsub8nc(temp, 1); + } + else + { + seteab(temp + 1); if (abrt) return 1; + setadd8nc(temp, 1); + } + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + return 0; +} diff --git a/src/x86_ops_int - Cópia.h b/src/x86_ops_int - Cópia.h new file mode 100644 index 000000000..0cfb959dd --- /dev/null +++ b/src/x86_ops_int - Cópia.h @@ -0,0 +1,77 @@ +static int opINT3(uint32_t fetchdat) +{ + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + x86_int_sw(3); + CLOCK_CYCLES((is486) ? 44 : 59); + return 1; +} + +static int opINT(uint32_t fetchdat) +{ + uint8_t temp; + + /*if (msw&1) pclog("INT %i %i %i\n",cr0&1,eflags&VM_FLAG,IOPL);*/ + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + temp = getbytef(); +// /*if (temp == 0x10 && AH == 0xe) */pclog("INT %02X : %04X %04X %04X %04X %c %04X:%04X\n", temp, AX, BX, CX, DX, (AL < 32) ? ' ' : AL, CS, pc); +// if (CS == 0x0028 && pc == 0xC03813C0) +// output = 3; +/* if (pc == 0x8028009A) + output = 3; + if (pc == 0x80282B6F) + { + __times++; + if (__times == 2) + fatal("WRONG\n"); + } + if (pc == 0x802809CE) + fatal("RIGHT\n");*/ +// if (CS == 0x0028 && pc == 0x80037FE9) +// output = 3; +//if (CS == 0x9087 && pc == 0x3763) +// fatal("Here\n"); +//if (CS==0x9087 && pc == 0x0850) +// output = 1; + +/* if (output && pc == 0x80033008) + { + __times++; + if (__times == 2) + fatal("WRONG\n"); + }*/ +/* if (output && pc == 0x80D8) + { + __times++; + if (__times == 2) + fatal("RIGHT\n"); + }*/ + + x86_int_sw(temp); + return 1; +} + +static int opINTO(uint32_t fetchdat) +{ + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + if (VF_SET()) + { + oldpc = pc; + x86_int_sw(4); + return 1; + } + CLOCK_CYCLES(3); + return 0; +} + diff --git a/src/x86_ops_int.h b/src/x86_ops_int.h new file mode 100644 index 000000000..83bcc91d8 --- /dev/null +++ b/src/x86_ops_int.h @@ -0,0 +1,77 @@ +static int opINT3(uint32_t fetchdat) +{ + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + x86_int_sw(3); + CLOCK_CYCLES((is486) ? 44 : 59); + return 1; +} + +static int opINT(uint32_t fetchdat) +{ + uint8_t temp; + + /*if (msw&1) pclog("INT %i %i %i\n",cr0&1,eflags&VM_FLAG,IOPL);*/ + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + temp = getbytef(); +// /*if (temp == 0x10 && AH == 0xe) */pclog("INT %02X : %04X %04X %04X %04X %c %04X:%04X\n", temp, AX, BX, CX, DX, (AL < 32) ? ' ' : AL, CS, pc); +// if (CS == 0x0028 && pc == 0xC03813C0) +// output = 3; +/* if (pc == 0x8028009A) + output = 3; + if (pc == 0x80282B6F) + { + __times++; + if (__times == 2) + fatal("WRONG\n"); + } + if (pc == 0x802809CE) + fatal("RIGHT\n");*/ +// if (CS == 0x0028 && pc == 0x80037FE9) +// output = 3; +//if (CS == 0x9087 && pc == 0x3763) +// fatal("Here\n"); +//if (CS==0x9087 && pc == 0x0850) +// output = 1; + +/* if (output && pc == 0x80033008) + { + __times++; + if (__times == 2) + fatal("WRONG\n"); + }*/ +/* if (output && pc == 0x80D8) + { + __times++; + if (__times == 2) + fatal("RIGHT\n"); + }*/ + + x86_int_sw(temp); + return 1; +} + +static int opINTO(uint32_t fetchdat) +{ + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + if (VF_SET()) + { + oldpc = cpu_state.pc; + x86_int_sw(4); + return 1; + } + CLOCK_CYCLES(3); + return 0; +} + diff --git a/src/x86_ops_io - Cópia.h b/src/x86_ops_io - Cópia.h new file mode 100644 index 000000000..c7bde30aa --- /dev/null +++ b/src/x86_ops_io - Cópia.h @@ -0,0 +1,112 @@ +static int opIN_AL_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + AL = inb(port); + CLOCK_CYCLES(12); + return 0; +} +static int opIN_AX_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + check_io_perm(port + 1); + AX = inw(port); + CLOCK_CYCLES(12); + return 0; +} +static int opIN_EAX_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + check_io_perm(port + 1); + check_io_perm(port + 2); + check_io_perm(port + 3); + EAX = inl(port); + CLOCK_CYCLES(12); + return 0; +} + +static int opOUT_AL_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + outb(port, AL); + CLOCK_CYCLES(10); + if (port == 0x64) + return x86_was_reset; + return 0; +} +static int opOUT_AX_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + check_io_perm(port + 1); + outw(port, AX); + CLOCK_CYCLES(10); + return 0; +} +static int opOUT_EAX_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + check_io_perm(port + 1); + check_io_perm(port + 2); + check_io_perm(port + 3); + outl(port, EAX); + CLOCK_CYCLES(10); + return 0; +} + +static int opIN_AL_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + AL = inb(DX); + CLOCK_CYCLES(12); + return 0; +} +static int opIN_AX_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + check_io_perm(DX + 1); + AX = inw(DX); + CLOCK_CYCLES(12); + return 0; +} +static int opIN_EAX_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + EAX = inl(DX); + CLOCK_CYCLES(12); + return 0; +} + +static int opOUT_AL_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + outb(DX, AL); + CLOCK_CYCLES(11); + return x86_was_reset; +} +static int opOUT_AX_DX(uint32_t fetchdat) +{ + //pclog("OUT_AX_DX %04X %04X\n", DX, AX); + check_io_perm(DX); + check_io_perm(DX + 1); + outw(DX, AX); + CLOCK_CYCLES(11); + return 0; +} +static int opOUT_EAX_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + outl(DX, EAX); + CLOCK_CYCLES(11); + return 0; +} diff --git a/src/x86_ops_io.h b/src/x86_ops_io.h new file mode 100644 index 000000000..c7bde30aa --- /dev/null +++ b/src/x86_ops_io.h @@ -0,0 +1,112 @@ +static int opIN_AL_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + AL = inb(port); + CLOCK_CYCLES(12); + return 0; +} +static int opIN_AX_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + check_io_perm(port + 1); + AX = inw(port); + CLOCK_CYCLES(12); + return 0; +} +static int opIN_EAX_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + check_io_perm(port + 1); + check_io_perm(port + 2); + check_io_perm(port + 3); + EAX = inl(port); + CLOCK_CYCLES(12); + return 0; +} + +static int opOUT_AL_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + outb(port, AL); + CLOCK_CYCLES(10); + if (port == 0x64) + return x86_was_reset; + return 0; +} +static int opOUT_AX_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + check_io_perm(port + 1); + outw(port, AX); + CLOCK_CYCLES(10); + return 0; +} +static int opOUT_EAX_imm(uint32_t fetchdat) +{ + uint16_t port = (uint16_t)getbytef(); + check_io_perm(port); + check_io_perm(port + 1); + check_io_perm(port + 2); + check_io_perm(port + 3); + outl(port, EAX); + CLOCK_CYCLES(10); + return 0; +} + +static int opIN_AL_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + AL = inb(DX); + CLOCK_CYCLES(12); + return 0; +} +static int opIN_AX_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + check_io_perm(DX + 1); + AX = inw(DX); + CLOCK_CYCLES(12); + return 0; +} +static int opIN_EAX_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + EAX = inl(DX); + CLOCK_CYCLES(12); + return 0; +} + +static int opOUT_AL_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + outb(DX, AL); + CLOCK_CYCLES(11); + return x86_was_reset; +} +static int opOUT_AX_DX(uint32_t fetchdat) +{ + //pclog("OUT_AX_DX %04X %04X\n", DX, AX); + check_io_perm(DX); + check_io_perm(DX + 1); + outw(DX, AX); + CLOCK_CYCLES(11); + return 0; +} +static int opOUT_EAX_DX(uint32_t fetchdat) +{ + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + outl(DX, EAX); + CLOCK_CYCLES(11); + return 0; +} diff --git a/src/x86_ops_jump.h b/src/x86_ops_jump.h new file mode 100644 index 000000000..c2bc1e1ad --- /dev/null +++ b/src/x86_ops_jump.h @@ -0,0 +1,305 @@ +#define cond_O ( VF_SET()) +#define cond_NO (!VF_SET()) +#define cond_B ( CF_SET()) +#define cond_NB (!CF_SET()) +#define cond_E ( ZF_SET()) +#define cond_NE (!ZF_SET()) +#define cond_BE ( CF_SET() || ZF_SET()) +#define cond_NBE (!CF_SET() && !ZF_SET()) +#define cond_S ( NF_SET()) +#define cond_NS (!NF_SET()) +#define cond_P ( PF_SET()) +#define cond_NP (!PF_SET()) +#define cond_L (((NF_SET()) ? 1 : 0) != ((VF_SET()) ? 1 : 0)) +#define cond_NL (((NF_SET()) ? 1 : 0) == ((VF_SET()) ? 1 : 0)) +#define cond_LE (((NF_SET()) ? 1 : 0) != ((VF_SET()) ? 1 : 0) || (ZF_SET())) +#define cond_NLE (((NF_SET()) ? 1 : 0) == ((VF_SET()) ? 1 : 0) && (!ZF_SET())) + +#define opJ(condition) \ + static int opJ ## condition(uint32_t fetchdat) \ + { \ + int8_t offset = (int8_t)getbytef(); \ + CLOCK_CYCLES(timing_bnt); \ + if (cond_ ## condition) \ + { \ + cpu_state.pc += offset; \ + CLOCK_CYCLES_ALWAYS(timing_bt); \ + CPU_BLOCK_END(); \ + return 1; \ + } \ + return 0; \ + } \ + \ + static int opJ ## condition ## _w(uint32_t fetchdat) \ + { \ + int16_t offset = (int16_t)getwordf(); \ + CLOCK_CYCLES(timing_bnt); \ + if (cond_ ## condition) \ + { \ + cpu_state.pc += offset; \ + CLOCK_CYCLES_ALWAYS(timing_bt); \ + CPU_BLOCK_END(); \ + return 1; \ + } \ + return 0; \ + } \ + \ + static int opJ ## condition ## _l(uint32_t fetchdat) \ + { \ + uint32_t offset = getlong(); if (abrt) return 1; \ + CLOCK_CYCLES(timing_bnt); \ + if (cond_ ## condition) \ + { \ + cpu_state.pc += offset; \ + CLOCK_CYCLES_ALWAYS(timing_bt); \ + CPU_BLOCK_END(); \ + return 1; \ + } \ + return 0; \ + } \ + +opJ(O) +opJ(NO) +opJ(B) +opJ(NB) +opJ(E) +opJ(NE) +opJ(BE) +opJ(NBE) +opJ(S) +opJ(NS) +opJ(P) +opJ(NP) +opJ(L) +opJ(NL) +opJ(LE) +opJ(NLE) + + + +static int opLOOPNE_w(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + CX--; + CLOCK_CYCLES((is486) ? 7 : 11); + if (CX && !ZF_SET()) + { + cpu_state.pc += offset; + CPU_BLOCK_END(); + return 1; + } + return 0; +} +static int opLOOPNE_l(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + ECX--; + CLOCK_CYCLES((is486) ? 7 : 11); + if (ECX && !ZF_SET()) + { + cpu_state.pc += offset; + CPU_BLOCK_END(); + return 1; + } + return 0; +} + +static int opLOOPE_w(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + CX--; + CLOCK_CYCLES((is486) ? 7 : 11); + if (CX && ZF_SET()) + { + cpu_state.pc += offset; + CPU_BLOCK_END(); + return 1; + } + return 0; +} +static int opLOOPE_l(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + ECX--; + CLOCK_CYCLES((is486) ? 7 : 11); + if (ECX && ZF_SET()) + { + cpu_state.pc += offset; + CPU_BLOCK_END(); + return 1; + } + return 0; +} + +static int opLOOP_w(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + CX--; + CLOCK_CYCLES((is486) ? 7 : 11); + if (CX) + { + cpu_state.pc += offset; + CPU_BLOCK_END(); + return 1; + } + return 0; +} +static int opLOOP_l(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + ECX--; + CLOCK_CYCLES((is486) ? 7 : 11); + if (ECX) + { + cpu_state.pc += offset; + CPU_BLOCK_END(); + return 1; + } + return 0; +} + +static int opJCXZ(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + CLOCK_CYCLES(5); + if (!CX) + { + cpu_state.pc += offset; + CLOCK_CYCLES(4); + CPU_BLOCK_END(); + return 1; + } + return 0; +} +static int opJECXZ(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + CLOCK_CYCLES(5); + if (!ECX) + { + cpu_state.pc += offset; + CLOCK_CYCLES(4); + CPU_BLOCK_END(); + return 1; + } + return 0; +} + + +static int opJMP_r8(uint32_t fetchdat) +{ + int8_t offset = (int8_t)getbytef(); + cpu_state.pc += offset; + CPU_BLOCK_END(); + CLOCK_CYCLES((is486) ? 3 : 7); + return 0; +} +static int opJMP_r16(uint32_t fetchdat) +{ + int16_t offset = (int16_t)getwordf(); + cpu_state.pc += offset; + CPU_BLOCK_END(); + CLOCK_CYCLES((is486) ? 3 : 7); + return 0; +} +static int opJMP_r32(uint32_t fetchdat) +{ + int32_t offset = (int32_t)getlong(); if (abrt) return 1; + cpu_state.pc += offset; + CPU_BLOCK_END(); + CLOCK_CYCLES((is486) ? 3 : 7); + return 0; +} + +static int opJMP_far_a16(uint32_t fetchdat) +{ + uint16_t addr = getwordf(); + uint16_t seg = getword(); if (abrt) return 1; + uint32_t oxpc = cpu_state.pc; + cpu_state.pc = addr; + loadcsjmp(seg, oxpc); + CPU_BLOCK_END(); + return 0; +} +static int opJMP_far_a32(uint32_t fetchdat) +{ + uint32_t addr = getlong(); + uint16_t seg = getword(); if (abrt) return 1; + uint32_t oxpc = cpu_state.pc; + cpu_state.pc = addr; + loadcsjmp(seg, oxpc); + CPU_BLOCK_END(); + return 0; +} + +static int opCALL_r16(uint32_t fetchdat) +{ + int16_t addr = (int16_t)getwordf(); + PUSH_W(cpu_state.pc); + cpu_state.pc += addr; + CPU_BLOCK_END(); + CLOCK_CYCLES((is486) ? 3 : 7); + return 0; +} +static int opCALL_r32(uint32_t fetchdat) +{ + int32_t addr = getlong(); if (abrt) return 1; + PUSH_L(cpu_state.pc); + cpu_state.pc += addr; + CPU_BLOCK_END(); + CLOCK_CYCLES((is486) ? 3 : 7); + return 0; +} + +static int opRET_w(uint32_t fetchdat) +{ + uint16_t ret; + + ret = POP_W(); if (abrt) return 1; + cpu_state.pc = ret; + CPU_BLOCK_END(); + + CLOCK_CYCLES((is486) ? 5 : 10); + return 0; +} +static int opRET_l(uint32_t fetchdat) +{ + uint32_t ret; + + ret = POP_L(); if (abrt) return 1; + cpu_state.pc = ret; + CPU_BLOCK_END(); + + CLOCK_CYCLES((is486) ? 5 : 10); + return 0; +} + +static int opRET_w_imm(uint32_t fetchdat) +{ + uint16_t offset = getwordf(); + uint16_t ret; + + ret = POP_W(); if (abrt) return 1; + if (stack32) ESP += offset; + else SP += offset; + cpu_state.pc = ret; + CPU_BLOCK_END(); + + CLOCK_CYCLES((is486) ? 5 : 10); + return 0; +} +static int opRET_l_imm(uint32_t fetchdat) +{ + uint16_t offset = getwordf(); + uint32_t ret; + + ret = POP_L(); if (abrt) return 1; + if (stack32) ESP += offset; + else SP += offset; + cpu_state.pc = ret; + CPU_BLOCK_END(); + + CLOCK_CYCLES((is486) ? 5 : 10); + return 0; +} + diff --git a/src/x86_ops_misc.h b/src/x86_ops_misc.h new file mode 100644 index 000000000..d23421b89 --- /dev/null +++ b/src/x86_ops_misc.h @@ -0,0 +1,805 @@ +static int opCBW(uint32_t fetchdat) +{ + AH = (AL & 0x80) ? 0xff : 0; + CLOCK_CYCLES(3); + return 0; +} +static int opCWDE(uint32_t fetchdat) +{ + EAX = (AX & 0x8000) ? (0xffff0000 | AX) : AX; + CLOCK_CYCLES(3); + return 0; +} +static int opCWD(uint32_t fetchdat) +{ + DX = (AX & 0x8000) ? 0xFFFF : 0; + CLOCK_CYCLES(2); + return 0; +} +static int opCDQ(uint32_t fetchdat) +{ + EDX = (EAX & 0x80000000) ? 0xffffffff : 0; + CLOCK_CYCLES(2); + return 0; +} + +static int opNOP(uint32_t fetchdat) +{ + CLOCK_CYCLES((is486) ? 1 : 3); + return 0; +} + +static int opSETALC(uint32_t fetchdat) +{ + AL = (CF_SET()) ? 0xff : 0; + CLOCK_CYCLES(timing_rr); + return 0; +} + + + +static int opF6_a16(uint32_t fetchdat) +{ + int tempws, tempws2; + uint16_t tempw, src16; + uint8_t src, dst; + int8_t temps; + + fetch_ea_16(fetchdat); + dst = geteab(); if (abrt) return 1; + switch (rmdat & 0x38) + { + case 0x00: /*TEST b,#8*/ + src = readmemb(cs, cpu_state.pc); cpu_state.pc++; if (abrt) return 1; + setznp8(src & dst); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + break; + case 0x10: /*NOT b*/ + seteab(~dst); if (abrt) return 1; + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + break; + case 0x18: /*NEG b*/ + seteab(0 - dst); if (abrt) return 1; + setsub8(0, dst); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + break; + case 0x20: /*MUL AL,b*/ + AX = AL * dst; + flags_rebuild(); + if (AH) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(13); + break; + case 0x28: /*IMUL AL,b*/ + tempws = (int)((int8_t)AL) * (int)((int8_t)dst); + AX = tempws & 0xffff; + flags_rebuild(); + if (((int16_t)AX >> 7) != 0 && ((int16_t)AX >> 7) != -1) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(14); + break; + case 0x30: /*DIV AL,b*/ + src16 = AX; + if (dst) tempw = src16 / dst; + if (dst && !(tempw & 0xff00)) + { + AH = src16 % dst; + AL = (src16 / dst) &0xff; + if (!cpu_iscyrix) + { + flags_rebuild(); + flags |= 0x8D5; /*Not a Cyrix*/ + } + } + else + { + x86_int(0); + return 1; + } + CLOCK_CYCLES(is486 ? 16 : 14); + break; + case 0x38: /*IDIV AL,b*/ + tempws = (int)(int16_t)AX; + if (dst != 0) tempws2 = tempws / (int)((int8_t)dst); + temps = tempws2 & 0xff; + if (dst && ((int)temps == tempws2)) + { + AH = (tempws % (int)((int8_t)dst)) & 0xff; + AL = tempws2 & 0xff; + if (!cpu_iscyrix) + { + flags_rebuild(); + flags|=0x8D5; /*Not a Cyrix*/ + } + } + else + { +// pclog("IDIVb exception - %X / %08X = %X\n", tempws, dst, tempws2); + x86_int(0); + return 1; + } + CLOCK_CYCLES(19); + break; + + default: + pclog("Bad F6 opcode %02X\n", rmdat & 0x38); + x86illegal(); + } + return 0; +} +static int opF6_a32(uint32_t fetchdat) +{ + int tempws, tempws2; + uint16_t tempw, src16; + uint8_t src, dst; + int8_t temps; + + fetch_ea_32(fetchdat); + dst = geteab(); if (abrt) return 1; + switch (rmdat & 0x38) + { + case 0x00: /*TEST b,#8*/ + src = readmemb(cs, cpu_state.pc); cpu_state.pc++; if (abrt) return 1; + setznp8(src & dst); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + break; + case 0x10: /*NOT b*/ + seteab(~dst); if (abrt) return 1; + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + break; + case 0x18: /*NEG b*/ + seteab(0 - dst); if (abrt) return 1; + setsub8(0, dst); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + break; + case 0x20: /*MUL AL,b*/ + AX = AL * dst; + flags_rebuild(); + if (AH) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(13); + break; + case 0x28: /*IMUL AL,b*/ + tempws = (int)((int8_t)AL) * (int)((int8_t)dst); + AX = tempws & 0xffff; + flags_rebuild(); + if (((int16_t)AX >> 7) != 0 && ((int16_t)AX >> 7) != -1) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(14); + break; + case 0x30: /*DIV AL,b*/ + src16 = AX; + if (dst) tempw = src16 / dst; + if (dst && !(tempw & 0xff00)) + { + AH = src16 % dst; + AL = (src16 / dst) &0xff; + if (!cpu_iscyrix) + { + flags_rebuild(); + flags |= 0x8D5; /*Not a Cyrix*/ + } + } + else + { + x86_int(0); + return 1; + } + CLOCK_CYCLES(is486 ? 16 : 14); + break; + case 0x38: /*IDIV AL,b*/ + tempws = (int)(int16_t)AX; + if (dst != 0) tempws2 = tempws / (int)((int8_t)dst); + temps = tempws2 & 0xff; + if (dst && ((int)temps == tempws2)) + { + AH = (tempws % (int)((int8_t)dst)) & 0xff; + AL = tempws2 & 0xff; + if (!cpu_iscyrix) + { + flags_rebuild(); + flags|=0x8D5; /*Not a Cyrix*/ + } + } + else + { +// pclog("IDIVb exception - %X / %08X = %X\n", tempws, dst, tempws2); + x86_int(0); + return 1; + } + CLOCK_CYCLES(19); + break; + + default: + pclog("Bad F6 opcode %02X\n", rmdat & 0x38); + x86illegal(); + } + return 0; +} + + + +static int opF7_w_a16(uint32_t fetchdat) +{ + uint32_t templ, templ2; + int tempws, tempws2; + int16_t temps16; + uint16_t src, dst; + + fetch_ea_16(fetchdat); + dst = geteaw(); if (abrt) return 1; + switch (rmdat & 0x38) + { + case 0x00: /*TEST w*/ + src = getword(); if (abrt) return 1; + setznp16(src & dst); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + break; + case 0x10: /*NOT w*/ + seteaw(~dst); if (abrt) return 1; + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + break; + case 0x18: /*NEG w*/ + seteaw(0 - dst); if (abrt) return 1; + setsub16(0, dst); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + break; + case 0x20: /*MUL AX,w*/ + templ = AX * dst; + AX = templ & 0xFFFF; + DX = templ >> 16; + flags_rebuild(); + if (DX) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(21); + break; + case 0x28: /*IMUL AX,w*/ + templ = (int)((int16_t)AX) * (int)((int16_t)dst); + AX = templ & 0xFFFF; + DX = templ >> 16; + flags_rebuild(); + if (((int32_t)templ >> 15) != 0 && ((int32_t)templ >> 15) != -1) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(22); + break; + case 0x30: /*DIV AX,w*/ + templ = (DX << 16) | AX; + if (dst) templ2 = templ / dst; + if (dst && !(templ2 & 0xffff0000)) + { + DX = templ % dst; + AX = (templ / dst) & 0xffff; + if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ + } + else + { +// fatal("DIVw BY 0 %04X:%04X %i\n",cs>>4,pc,ins); + x86_int(0); + return 1; + } + CLOCK_CYCLES(is486 ? 24 : 22); + break; + case 0x38: /*IDIV AX,w*/ + tempws = (int)((DX << 16)|AX); + if (dst) tempws2 = tempws / (int)((int16_t)dst); + temps16 = tempws2 & 0xffff; + if ((dst != 0) && ((int)temps16 == tempws2)) + { + DX = tempws % (int)((int16_t)dst); + AX = tempws2 & 0xffff; + if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ + } + else + { +// pclog("IDIVw exception - %X / %08X = %X\n",tempws, dst, tempws2); + x86_int(0); + return 1; + } + CLOCK_CYCLES(27); + break; + + default: + pclog("Bad F7 opcode %02X\n", rmdat & 0x38); + x86illegal(); + } + return 0; +} +static int opF7_w_a32(uint32_t fetchdat) +{ + uint32_t templ, templ2; + int tempws, tempws2; + int16_t temps16; + uint16_t src, dst; + + fetch_ea_32(fetchdat); + dst = geteaw(); if (abrt) return 1; + switch (rmdat & 0x38) + { + case 0x00: /*TEST w*/ + src = getword(); if (abrt) return 1; + setznp16(src & dst); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + break; + case 0x10: /*NOT w*/ + seteaw(~dst); if (abrt) return 1; + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + break; + case 0x18: /*NEG w*/ + seteaw(0 - dst); if (abrt) return 1; + setsub16(0, dst); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mm); + break; + case 0x20: /*MUL AX,w*/ + templ = AX * dst; + AX = templ & 0xFFFF; + DX = templ >> 16; + flags_rebuild(); + if (DX) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(21); + break; + case 0x28: /*IMUL AX,w*/ + templ = (int)((int16_t)AX) * (int)((int16_t)dst); + AX = templ & 0xFFFF; + DX = templ >> 16; + flags_rebuild(); + if (((int32_t)templ >> 15) != 0 && ((int32_t)templ >> 15) != -1) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(22); + break; + case 0x30: /*DIV AX,w*/ + templ = (DX << 16) | AX; + if (dst) templ2 = templ / dst; + if (dst && !(templ2 & 0xffff0000)) + { + DX = templ % dst; + AX = (templ / dst) & 0xffff; + if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ + } + else + { +// fatal("DIVw BY 0 %04X:%04X %i\n",cs>>4,pc,ins); + x86_int(0); + return 1; + } + CLOCK_CYCLES(is486 ? 24 : 22); + break; + case 0x38: /*IDIV AX,w*/ + tempws = (int)((DX << 16)|AX); + if (dst) tempws2 = tempws / (int)((int16_t)dst); + temps16 = tempws2 & 0xffff; + if ((dst != 0) && ((int)temps16 == tempws2)) + { + DX = tempws % (int)((int16_t)dst); + AX = tempws2 & 0xffff; + if (!cpu_iscyrix) setznp16(AX); /*Not a Cyrix*/ + } + else + { +// pclog("IDIVw exception - %X / %08X = %X\n", tempws, dst, tempws2); + x86_int(0); + return 1; + } + CLOCK_CYCLES(27); + break; + + default: + pclog("Bad F7 opcode %02X\n", rmdat & 0x38); + x86illegal(); + } + return 0; +} + +static int opF7_l_a16(uint32_t fetchdat) +{ + uint64_t temp64; + uint32_t src, dst; + + fetch_ea_16(fetchdat); + dst = geteal(); if (abrt) return 1; + + switch (rmdat & 0x38) + { + case 0x00: /*TEST l*/ + src = getlong(); if (abrt) return 1; + setznp32(src & dst); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + break; + case 0x10: /*NOT l*/ + seteal(~dst); if (abrt) return 1; + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mml); + break; + case 0x18: /*NEG l*/ + seteal(0 - dst); if (abrt) return 1; + setsub32(0, dst); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mml); + break; + case 0x20: /*MUL EAX,l*/ + temp64 = (uint64_t)EAX * (uint64_t)dst; + EAX = temp64 & 0xffffffff; + EDX = temp64 >> 32; + flags_rebuild(); + if (EDX) flags |= (C_FLAG|V_FLAG); + else flags &= ~(C_FLAG|V_FLAG); + CLOCK_CYCLES(21); + break; + case 0x28: /*IMUL EAX,l*/ + temp64 = (int64_t)(int32_t)EAX * (int64_t)(int32_t)dst; + EAX = temp64 & 0xffffffff; + EDX = temp64 >> 32; + flags_rebuild(); + if (((int64_t)temp64 >> 31) != 0 && ((int64_t)temp64 >> 31) != -1) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(38); + break; + case 0x30: /*DIV EAX,l*/ + if (divl(dst)) + return 1; + if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/ + CLOCK_CYCLES((is486) ? 40 : 38); + break; + case 0x38: /*IDIV EAX,l*/ + if (idivl((int32_t)dst)) + return 1; + if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/ + CLOCK_CYCLES(43); + break; + + default: + pclog("Bad F7 opcode %02X\n", rmdat & 0x38); + x86illegal(); + } + return 0; +} +static int opF7_l_a32(uint32_t fetchdat) +{ + uint64_t temp64; + uint32_t src, dst; + + fetch_ea_32(fetchdat); + dst = geteal(); if (abrt) return 1; + + switch (rmdat & 0x38) + { + case 0x00: /*TEST l*/ + src = getlong(); if (abrt) return 1; + setznp32(src & dst); + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 2); + else CLOCK_CYCLES((mod == 3) ? 2 : 5); + break; + case 0x10: /*NOT l*/ + seteal(~dst); if (abrt) return 1; + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mml); + break; + case 0x18: /*NEG l*/ + seteal(0 - dst); if (abrt) return 1; + setsub32(0, dst); + CLOCK_CYCLES((mod == 3) ? timing_rr : timing_mml); + break; + case 0x20: /*MUL EAX,l*/ + temp64 = (uint64_t)EAX * (uint64_t)dst; + EAX = temp64 & 0xffffffff; + EDX = temp64 >> 32; + flags_rebuild(); + if (EDX) flags |= (C_FLAG|V_FLAG); + else flags &= ~(C_FLAG|V_FLAG); + CLOCK_CYCLES(21); + break; + case 0x28: /*IMUL EAX,l*/ + temp64 = (int64_t)(int32_t)EAX * (int64_t)(int32_t)dst; + EAX = temp64 & 0xffffffff; + EDX = temp64 >> 32; + flags_rebuild(); + if (((int64_t)temp64 >> 31) != 0 && ((int64_t)temp64 >> 31) != -1) flags |= (C_FLAG | V_FLAG); + else flags &= ~(C_FLAG | V_FLAG); + CLOCK_CYCLES(38); + break; + case 0x30: /*DIV EAX,l*/ + if (divl(dst)) + return 1; + if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/ + CLOCK_CYCLES((is486) ? 40 : 38); + break; + case 0x38: /*IDIV EAX,l*/ + if (idivl((int32_t)dst)) + return 1; + if (!cpu_iscyrix) setznp32(EAX); /*Not a Cyrix*/ + CLOCK_CYCLES(43); + break; + + default: + pclog("Bad F7 opcode %02X\n", rmdat & 0x38); + x86illegal(); + } + return 0; +} + + +static int opHLT(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + x86gpf(NULL,0); + return 1; + } + if (!((flags&I_FLAG) && pic_intpending)) + { + CLOCK_CYCLES_ALWAYS(100); + cpu_state.pc--; + } + else + CLOCK_CYCLES(5); + + CPU_BLOCK_END(); + + return 0; +} + + +static int opLOCK(uint32_t fetchdat) +{ + fetchdat = fastreadl(cs + cpu_state.pc); + if (abrt) return 0; + cpu_state.pc++; + + CLOCK_CYCLES(4); + return x86_opcodes[(fetchdat & 0xff) | op32](fetchdat >> 8); +} + + + +static int opBOUND_w_a16(uint32_t fetchdat) +{ + int16_t low, high; + + fetch_ea_16(fetchdat); + ILLEGAL_ON(mod == 3); + low = geteaw(); + high = readmemw(easeg, eaaddr + 2); if (abrt) return 1; + + if (((int16_t)cpu_state.regs[reg].w < low) || ((int16_t)cpu_state.regs[reg].w > high)) + { + x86_int(5); + return 1; + } + + CLOCK_CYCLES(is486 ? 7 : 10); + return 0; +} +static int opBOUND_w_a32(uint32_t fetchdat) +{ + int16_t low, high; + + fetch_ea_32(fetchdat); + ILLEGAL_ON(mod == 3); + low = geteaw(); + high = readmemw(easeg, eaaddr + 2); if (abrt) return 1; + + if (((int16_t)cpu_state.regs[reg].w < low) || ((int16_t)cpu_state.regs[reg].w > high)) + { + x86_int(5); + return 1; + } + + CLOCK_CYCLES(is486 ? 7 : 10); + return 0; +} + +static int opBOUND_l_a16(uint32_t fetchdat) +{ + int32_t low, high; + + fetch_ea_16(fetchdat); + ILLEGAL_ON(mod == 3); + low = geteal(); + high = readmeml(easeg, eaaddr + 4); if (abrt) return 1; + + if (((int32_t)cpu_state.regs[reg].l < low) || ((int32_t)cpu_state.regs[reg].l > high)) + { + x86_int(5); + return 1; + } + + CLOCK_CYCLES(is486 ? 7 : 10); + return 0; +} +static int opBOUND_l_a32(uint32_t fetchdat) +{ + int32_t low, high; + + fetch_ea_32(fetchdat); + ILLEGAL_ON(mod == 3); + low = geteal(); + high = readmeml(easeg, eaaddr + 4); if (abrt) return 1; + + if (((int32_t)cpu_state.regs[reg].l < low) || ((int32_t)cpu_state.regs[reg].l > high)) + { + x86_int(5); + return 1; + } + + CLOCK_CYCLES(is486 ? 7 : 10); + return 0; +} + + +static int opCLTS(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't CLTS\n"); + x86gpf(NULL,0); + return 1; + } + cr0 &= ~8; + CLOCK_CYCLES(5); + return 0; +} + +static int opINVD(uint32_t fetchdat) +{ + if (!is486) + { + x86illegal(); + return 1; + } + CLOCK_CYCLES(1000); + CPU_BLOCK_END(); + return 0; +} +static int opWBINVD(uint32_t fetchdat) +{ + if (!is486) + { + x86illegal(); + return 1; + } + CLOCK_CYCLES(10000); + CPU_BLOCK_END(); + return 0; +} + + + +static int opLOADALL(uint32_t fetchdat) +{ + flags = (readmemw(0, 0x818) & 0xffd5) | 2; + flags_extract(); + cpu_state.pc = readmemw(0, 0x81A); + DS = readmemw(0, 0x81E); + SS = readmemw(0, 0x820); + CS = readmemw(0, 0x822); + ES = readmemw(0, 0x824); + DI = readmemw(0, 0x826); + SI = readmemw(0, 0x828); + BP = readmemw(0, 0x82A); + SP = readmemw(0, 0x82C); + BX = readmemw(0, 0x82E); + DX = readmemw(0, 0x830); + CX = readmemw(0, 0x832); + AX = readmemw(0, 0x834); + es = readmemw(0, 0x836) | (readmemb(0, 0x838) << 16); + cs = readmemw(0, 0x83C) | (readmemb(0, 0x83E) << 16); + ss = readmemw(0, 0x842) | (readmemb(0, 0x844) << 16); + ds = readmemw(0, 0x848) | (readmemb(0, 0x84A) << 16); + CLOCK_CYCLES(195); + return 0; +} + +static int set_segment_limit(x86seg *s, uint8_t segdat3) +{ + if ((s->access & 0x18) != 0x10 || !(s->access & (1 << 2))) /*expand-down*/ + { + s->limit_high = s->limit; + s->limit_low = 0; + } + else + { + s->limit_high = (segdat3 & 0x40) ? 0xffffffff : 0xffff; + s->limit_low = s->limit + 1; + } +} + +static int loadall_load_segment(uint32_t addr, x86seg *s) +{ + uint32_t attrib = readmeml(0, addr); + uint32_t segdat3 = (attrib >> 16) & 0xff; + s->access = (attrib >> 8) & 0xff; + s->base = readmeml(0, addr + 4); + s->limit = readmeml(0, addr + 8); + + if (s == &_cs) use32 = (segdat3 & 0x40) ? 0x300 : 0; + if (s == &_ss) stack32 = (segdat3 & 0x40) ? 1 : 0; + + set_segment_limit(s, segdat3); +} + +static int opLOADALL386(uint32_t fetchdat) +{ + uint32_t la_addr = es + EDI; + + cr0 = readmeml(0, la_addr); + flags = readmemw(0, la_addr + 4); + eflags = readmemw(0, la_addr + 6); + flags_extract(); + cpu_state.pc = readmeml(0, la_addr + 8); + EDI = readmeml(0, la_addr + 0xC); + ESI = readmeml(0, la_addr + 0x10); + EBP = readmeml(0, la_addr + 0x14); + ESP = readmeml(0, la_addr + 0x18); + EBX = readmeml(0, la_addr + 0x1C); + EDX = readmeml(0, la_addr + 0x20); + ECX = readmeml(0, la_addr + 0x24); + EAX = readmeml(0, la_addr + 0x28); + dr[6] = readmeml(0, la_addr + 0x2C); + dr[7] = readmeml(0, la_addr + 0x30); + tr.seg = readmemw(0, la_addr + 0x34); + ldt.seg = readmemw(0, la_addr + 0x38); + GS = readmemw(0, la_addr + 0x3C); + FS = readmemw(0, la_addr + 0x40); + DS = readmemw(0, la_addr + 0x44); + SS = readmemw(0, la_addr + 0x48); + CS = readmemw(0, la_addr + 0x4C); + ES = readmemw(0, la_addr + 0x50); + + loadall_load_segment(la_addr + 0x54, &tr); + loadall_load_segment(la_addr + 0x60, &idt); + loadall_load_segment(la_addr + 0x6c, &gdt); + loadall_load_segment(la_addr + 0x78, &ldt); + loadall_load_segment(la_addr + 0x84, &_gs); + loadall_load_segment(la_addr + 0x90, &_fs); + loadall_load_segment(la_addr + 0x9c, &_ds); + loadall_load_segment(la_addr + 0xa8, &_ss); + loadall_load_segment(la_addr + 0xb4, &_cs); + loadall_load_segment(la_addr + 0xc0, &_es); + + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + + CLOCK_CYCLES(350); + return 0; +} + +static int opCPUID(uint32_t fetchdat) +{ + if (CPUID) + { + cpu_CPUID(); + CLOCK_CYCLES(9); + return 0; + } + cpu_state.pc = oldpc; + x86illegal(); + return 1; +} + +static int opRDMSR(uint32_t fetchdat) +{ + if (cpu_hasMSR) + { + cpu_RDMSR(); + CLOCK_CYCLES(9); + return 0; + } + cpu_state.pc = oldpc; + x86illegal(); + return 1; +} + +static int opWRMSR(uint32_t fetchdat) +{ + if (cpu_hasMSR) + { + cpu_WRMSR(); + CLOCK_CYCLES(9); + return 0; + } + cpu_state.pc = oldpc; + x86illegal(); + return 1; +} + diff --git a/src/x86_ops_mmx.h b/src/x86_ops_mmx.h new file mode 100644 index 000000000..c83c0a145 --- /dev/null +++ b/src/x86_ops_mmx.h @@ -0,0 +1,48 @@ +#define SSATB(val) (((val) < -128) ? -128 : (((val) > 127) ? 127 : (val))) +#define SSATW(val) (((val) < -32768) ? -32768 : (((val) > 32767) ? 32767 : (val))) +#define USATB(val) (((val) < 0) ? 0 : (((val) > 255) ? 255 : (val))) +#define USATW(val) (((val) < 0) ? 0 : (((val) > 65535) ? 65535 : (val))) + +#define MMX_GETSRC() \ + if (mod == 3) \ + { \ + src = MM[rm]; \ + CLOCK_CYCLES(1); \ + } \ + else \ + { \ + src.q = readmemq(easeg, eaaddr); if (abrt) return 1; \ + CLOCK_CYCLES(2); \ + } + +#define MMX_ENTER() \ + if (!cpu_hasMMX) \ + { \ + cpu_state.pc = oldpc; \ + x86illegal(); \ + return 1; \ + } \ + if (cr0 & 0xc) \ + { \ + x86_int(7); \ + return 1; \ + } \ + x87_set_mmx() + +static int opEMMS(uint32_t fetchdat) +{ + if (!cpu_hasMMX) + { + cpu_state.pc = oldpc; + x86illegal(); + return 1; + } + if (cr0 & 4) + { + x86_int(7); + return 1; + } + x87_emms(); + CLOCK_CYCLES(100); /*Guess*/ + return 0; +} diff --git a/src/x86_ops_mmx_arith.h b/src/x86_ops_mmx_arith.h new file mode 100644 index 000000000..14299621b --- /dev/null +++ b/src/x86_ops_mmx_arith.h @@ -0,0 +1,625 @@ +static int opPADDB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] += src.b[0]; + MM[reg].b[1] += src.b[1]; + MM[reg].b[2] += src.b[2]; + MM[reg].b[3] += src.b[3]; + MM[reg].b[4] += src.b[4]; + MM[reg].b[5] += src.b[5]; + MM[reg].b[6] += src.b[6]; + MM[reg].b[7] += src.b[7]; + + return 0; +} +static int opPADDB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] += src.b[0]; + MM[reg].b[1] += src.b[1]; + MM[reg].b[2] += src.b[2]; + MM[reg].b[3] += src.b[3]; + MM[reg].b[4] += src.b[4]; + MM[reg].b[5] += src.b[5]; + MM[reg].b[6] += src.b[6]; + MM[reg].b[7] += src.b[7]; + + return 0; +} + +static int opPADDW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] += src.w[0]; + MM[reg].w[1] += src.w[1]; + MM[reg].w[2] += src.w[2]; + MM[reg].w[3] += src.w[3]; + + return 0; +} +static int opPADDW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] += src.w[0]; + MM[reg].w[1] += src.w[1]; + MM[reg].w[2] += src.w[2]; + MM[reg].w[3] += src.w[3]; + + return 0; +} + +static int opPADDD_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].l[0] += src.l[0]; + MM[reg].l[1] += src.l[1]; + + return 0; +} +static int opPADDD_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].l[0] += src.l[0]; + MM[reg].l[1] += src.l[1]; + + return 0; +} + +static int opPADDSB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].sb[0] = SSATB(MM[reg].sb[0] + src.sb[0]); + MM[reg].sb[1] = SSATB(MM[reg].sb[1] + src.sb[1]); + MM[reg].sb[2] = SSATB(MM[reg].sb[2] + src.sb[2]); + MM[reg].sb[3] = SSATB(MM[reg].sb[3] + src.sb[3]); + MM[reg].sb[4] = SSATB(MM[reg].sb[4] + src.sb[4]); + MM[reg].sb[5] = SSATB(MM[reg].sb[5] + src.sb[5]); + MM[reg].sb[6] = SSATB(MM[reg].sb[6] + src.sb[6]); + MM[reg].sb[7] = SSATB(MM[reg].sb[7] + src.sb[7]); + + return 0; +} +static int opPADDSB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].sb[0] = SSATB(MM[reg].sb[0] + src.sb[0]); + MM[reg].sb[1] = SSATB(MM[reg].sb[1] + src.sb[1]); + MM[reg].sb[2] = SSATB(MM[reg].sb[2] + src.sb[2]); + MM[reg].sb[3] = SSATB(MM[reg].sb[3] + src.sb[3]); + MM[reg].sb[4] = SSATB(MM[reg].sb[4] + src.sb[4]); + MM[reg].sb[5] = SSATB(MM[reg].sb[5] + src.sb[5]); + MM[reg].sb[6] = SSATB(MM[reg].sb[6] + src.sb[6]); + MM[reg].sb[7] = SSATB(MM[reg].sb[7] + src.sb[7]); + + return 0; +} + +static int opPADDUSB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] = USATB(MM[reg].b[0] + src.b[0]); + MM[reg].b[1] = USATB(MM[reg].b[1] + src.b[1]); + MM[reg].b[2] = USATB(MM[reg].b[2] + src.b[2]); + MM[reg].b[3] = USATB(MM[reg].b[3] + src.b[3]); + MM[reg].b[4] = USATB(MM[reg].b[4] + src.b[4]); + MM[reg].b[5] = USATB(MM[reg].b[5] + src.b[5]); + MM[reg].b[6] = USATB(MM[reg].b[6] + src.b[6]); + MM[reg].b[7] = USATB(MM[reg].b[7] + src.b[7]); + + return 0; +} +static int opPADDUSB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] = USATB(MM[reg].b[0] + src.b[0]); + MM[reg].b[1] = USATB(MM[reg].b[1] + src.b[1]); + MM[reg].b[2] = USATB(MM[reg].b[2] + src.b[2]); + MM[reg].b[3] = USATB(MM[reg].b[3] + src.b[3]); + MM[reg].b[4] = USATB(MM[reg].b[4] + src.b[4]); + MM[reg].b[5] = USATB(MM[reg].b[5] + src.b[5]); + MM[reg].b[6] = USATB(MM[reg].b[6] + src.b[6]); + MM[reg].b[7] = USATB(MM[reg].b[7] + src.b[7]); + + return 0; +} + +static int opPADDSW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].sw[0] = SSATW(MM[reg].sw[0] + src.sw[0]); + MM[reg].sw[1] = SSATW(MM[reg].sw[1] + src.sw[1]); + MM[reg].sw[2] = SSATW(MM[reg].sw[2] + src.sw[2]); + MM[reg].sw[3] = SSATW(MM[reg].sw[3] + src.sw[3]); + + return 0; +} +static int opPADDSW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].sw[0] = SSATW(MM[reg].sw[0] + src.sw[0]); + MM[reg].sw[1] = SSATW(MM[reg].sw[1] + src.sw[1]); + MM[reg].sw[2] = SSATW(MM[reg].sw[2] + src.sw[2]); + MM[reg].sw[3] = SSATW(MM[reg].sw[3] + src.sw[3]); + + return 0; +} + +static int opPADDUSW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] = USATW(MM[reg].w[0] + src.w[0]); + MM[reg].w[1] = USATW(MM[reg].w[1] + src.w[1]); + MM[reg].w[2] = USATW(MM[reg].w[2] + src.w[2]); + MM[reg].w[3] = USATW(MM[reg].w[3] + src.w[3]); + + return 0; +} +static int opPADDUSW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] = USATW(MM[reg].w[0] + src.w[0]); + MM[reg].w[1] = USATW(MM[reg].w[1] + src.w[1]); + MM[reg].w[2] = USATW(MM[reg].w[2] + src.w[2]); + MM[reg].w[3] = USATW(MM[reg].w[3] + src.w[3]); + + return 0; +} + +static int opPMADDWD_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + if (MM[reg].l[0] == 0x80008000 && src.l[0] == 0x80008000) + MM[reg].l[0] = 0x80000000; + else + MM[reg].sl[0] = ((int32_t)MM[reg].sw[0] * (int32_t)src.sw[0]) + ((int32_t)MM[reg].sw[1] * (int32_t)src.sw[1]); + + if (MM[reg].l[1] == 0x80008000 && src.l[1] == 0x80008000) + MM[reg].l[1] = 0x80000000; + else + MM[reg].sl[1] = ((int32_t)MM[reg].sw[2] * (int32_t)src.sw[2]) + ((int32_t)MM[reg].sw[3] * (int32_t)src.sw[3]); + + return 0; +} +static int opPMADDWD_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + if (MM[reg].l[0] == 0x80008000 && src.l[0] == 0x80008000) + MM[reg].l[0] = 0x80000000; + else + MM[reg].sl[0] = ((int32_t)MM[reg].sw[0] * (int32_t)src.sw[0]) + ((int32_t)MM[reg].sw[1] * (int32_t)src.sw[1]); + + if (MM[reg].l[1] == 0x80008000 && src.l[1] == 0x80008000) + MM[reg].l[1] = 0x80000000; + else + MM[reg].sl[1] = ((int32_t)MM[reg].sw[2] * (int32_t)src.sw[2]) + ((int32_t)MM[reg].sw[3] * (int32_t)src.sw[3]); + + return 0; +} + + +static int opPMULLW_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (mod == 3) + { + MM[reg].w[0] *= MM[rm].w[0]; + MM[reg].w[1] *= MM[rm].w[1]; + MM[reg].w[2] *= MM[rm].w[2]; + MM[reg].w[3] *= MM[rm].w[3]; + CLOCK_CYCLES(1); + } + else + { + MMX_REG src; + + src.l[0] = readmeml(easeg, eaaddr); + src.l[1] = readmeml(easeg, eaaddr + 4); if (abrt) return 0; + MM[reg].w[0] *= src.w[0]; + MM[reg].w[1] *= src.w[1]; + MM[reg].w[2] *= src.w[2]; + MM[reg].w[3] *= src.w[3]; + CLOCK_CYCLES(2); + } + return 0; +} +static int opPMULLW_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (mod == 3) + { + MM[reg].w[0] *= MM[rm].w[0]; + MM[reg].w[1] *= MM[rm].w[1]; + MM[reg].w[2] *= MM[rm].w[2]; + MM[reg].w[3] *= MM[rm].w[3]; + CLOCK_CYCLES(1); + } + else + { + MMX_REG src; + + src.l[0] = readmeml(easeg, eaaddr); + src.l[1] = readmeml(easeg, eaaddr + 4); if (abrt) return 0; + MM[reg].w[0] *= src.w[0]; + MM[reg].w[1] *= src.w[1]; + MM[reg].w[2] *= src.w[2]; + MM[reg].w[3] *= src.w[3]; + CLOCK_CYCLES(2); + } + return 0; +} + +static int opPMULHW_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (mod == 3) + { + MM[reg].w[0] = ((int32_t)MM[reg].sw[0] * (int32_t)MM[rm].sw[0]) >> 16; + MM[reg].w[1] = ((int32_t)MM[reg].sw[1] * (int32_t)MM[rm].sw[1]) >> 16; + MM[reg].w[2] = ((int32_t)MM[reg].sw[2] * (int32_t)MM[rm].sw[2]) >> 16; + MM[reg].w[3] = ((int32_t)MM[reg].sw[3] * (int32_t)MM[rm].sw[3]) >> 16; + CLOCK_CYCLES(1); + } + else + { + MMX_REG src; + + src.l[0] = readmeml(easeg, eaaddr); + src.l[1] = readmeml(easeg, eaaddr + 4); if (abrt) return 0; + MM[reg].w[0] = ((int32_t)MM[reg].sw[0] * (int32_t)src.sw[0]) >> 16; + MM[reg].w[1] = ((int32_t)MM[reg].sw[1] * (int32_t)src.sw[1]) >> 16; + MM[reg].w[2] = ((int32_t)MM[reg].sw[2] * (int32_t)src.sw[2]) >> 16; + MM[reg].w[3] = ((int32_t)MM[reg].sw[3] * (int32_t)src.sw[3]) >> 16; + CLOCK_CYCLES(2); + } + return 0; +} +static int opPMULHW_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (mod == 3) + { + MM[reg].w[0] = ((int32_t)MM[reg].sw[0] * (int32_t)MM[rm].sw[0]) >> 16; + MM[reg].w[1] = ((int32_t)MM[reg].sw[1] * (int32_t)MM[rm].sw[1]) >> 16; + MM[reg].w[2] = ((int32_t)MM[reg].sw[2] * (int32_t)MM[rm].sw[2]) >> 16; + MM[reg].w[3] = ((int32_t)MM[reg].sw[3] * (int32_t)MM[rm].sw[3]) >> 16; + CLOCK_CYCLES(1); + } + else + { + MMX_REG src; + + src.l[0] = readmeml(easeg, eaaddr); + src.l[1] = readmeml(easeg, eaaddr + 4); if (abrt) return 0; + MM[reg].w[0] = ((int32_t)MM[reg].sw[0] * (int32_t)src.sw[0]) >> 16; + MM[reg].w[1] = ((int32_t)MM[reg].sw[1] * (int32_t)src.sw[1]) >> 16; + MM[reg].w[2] = ((int32_t)MM[reg].sw[2] * (int32_t)src.sw[2]) >> 16; + MM[reg].w[3] = ((int32_t)MM[reg].sw[3] * (int32_t)src.sw[3]) >> 16; + CLOCK_CYCLES(2); + } + return 0; +} + +static int opPSUBB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] -= src.b[0]; + MM[reg].b[1] -= src.b[1]; + MM[reg].b[2] -= src.b[2]; + MM[reg].b[3] -= src.b[3]; + MM[reg].b[4] -= src.b[4]; + MM[reg].b[5] -= src.b[5]; + MM[reg].b[6] -= src.b[6]; + MM[reg].b[7] -= src.b[7]; + + return 0; +} +static int opPSUBB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] -= src.b[0]; + MM[reg].b[1] -= src.b[1]; + MM[reg].b[2] -= src.b[2]; + MM[reg].b[3] -= src.b[3]; + MM[reg].b[4] -= src.b[4]; + MM[reg].b[5] -= src.b[5]; + MM[reg].b[6] -= src.b[6]; + MM[reg].b[7] -= src.b[7]; + + return 0; +} + +static int opPSUBW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] -= src.w[0]; + MM[reg].w[1] -= src.w[1]; + MM[reg].w[2] -= src.w[2]; + MM[reg].w[3] -= src.w[3]; + + return 0; +} +static int opPSUBW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] -= src.w[0]; + MM[reg].w[1] -= src.w[1]; + MM[reg].w[2] -= src.w[2]; + MM[reg].w[3] -= src.w[3]; + + return 0; +} + +static int opPSUBD_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].l[0] -= src.l[0]; + MM[reg].l[1] -= src.l[1]; + + return 0; +} +static int opPSUBD_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].l[0] -= src.l[0]; + MM[reg].l[1] -= src.l[1]; + + return 0; +} + +static int opPSUBSB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].sb[0] = SSATB(MM[reg].sb[0] - src.sb[0]); + MM[reg].sb[1] = SSATB(MM[reg].sb[1] - src.sb[1]); + MM[reg].sb[2] = SSATB(MM[reg].sb[2] - src.sb[2]); + MM[reg].sb[3] = SSATB(MM[reg].sb[3] - src.sb[3]); + MM[reg].sb[4] = SSATB(MM[reg].sb[4] - src.sb[4]); + MM[reg].sb[5] = SSATB(MM[reg].sb[5] - src.sb[5]); + MM[reg].sb[6] = SSATB(MM[reg].sb[6] - src.sb[6]); + MM[reg].sb[7] = SSATB(MM[reg].sb[7] - src.sb[7]); + + return 0; +} +static int opPSUBSB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].sb[0] = SSATB(MM[reg].sb[0] - src.sb[0]); + MM[reg].sb[1] = SSATB(MM[reg].sb[1] - src.sb[1]); + MM[reg].sb[2] = SSATB(MM[reg].sb[2] - src.sb[2]); + MM[reg].sb[3] = SSATB(MM[reg].sb[3] - src.sb[3]); + MM[reg].sb[4] = SSATB(MM[reg].sb[4] - src.sb[4]); + MM[reg].sb[5] = SSATB(MM[reg].sb[5] - src.sb[5]); + MM[reg].sb[6] = SSATB(MM[reg].sb[6] - src.sb[6]); + MM[reg].sb[7] = SSATB(MM[reg].sb[7] - src.sb[7]); + + return 0; +} + +static int opPSUBUSB_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] = USATB(MM[reg].b[0] - src.b[0]); + MM[reg].b[1] = USATB(MM[reg].b[1] - src.b[1]); + MM[reg].b[2] = USATB(MM[reg].b[2] - src.b[2]); + MM[reg].b[3] = USATB(MM[reg].b[3] - src.b[3]); + MM[reg].b[4] = USATB(MM[reg].b[4] - src.b[4]); + MM[reg].b[5] = USATB(MM[reg].b[5] - src.b[5]); + MM[reg].b[6] = USATB(MM[reg].b[6] - src.b[6]); + MM[reg].b[7] = USATB(MM[reg].b[7] - src.b[7]); + + return 0; +} +static int opPSUBUSB_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] = USATB(MM[reg].b[0] - src.b[0]); + MM[reg].b[1] = USATB(MM[reg].b[1] - src.b[1]); + MM[reg].b[2] = USATB(MM[reg].b[2] - src.b[2]); + MM[reg].b[3] = USATB(MM[reg].b[3] - src.b[3]); + MM[reg].b[4] = USATB(MM[reg].b[4] - src.b[4]); + MM[reg].b[5] = USATB(MM[reg].b[5] - src.b[5]); + MM[reg].b[6] = USATB(MM[reg].b[6] - src.b[6]); + MM[reg].b[7] = USATB(MM[reg].b[7] - src.b[7]); + + return 0; +} + +static int opPSUBSW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].sw[0] = SSATW(MM[reg].sw[0] - src.sw[0]); + MM[reg].sw[1] = SSATW(MM[reg].sw[1] - src.sw[1]); + MM[reg].sw[2] = SSATW(MM[reg].sw[2] - src.sw[2]); + MM[reg].sw[3] = SSATW(MM[reg].sw[3] - src.sw[3]); + + return 0; +} +static int opPSUBSW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].sw[0] = SSATW(MM[reg].sw[0] - src.sw[0]); + MM[reg].sw[1] = SSATW(MM[reg].sw[1] - src.sw[1]); + MM[reg].sw[2] = SSATW(MM[reg].sw[2] - src.sw[2]); + MM[reg].sw[3] = SSATW(MM[reg].sw[3] - src.sw[3]); + + return 0; +} + +static int opPSUBUSW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] = USATW(MM[reg].w[0] - src.w[0]); + MM[reg].w[1] = USATW(MM[reg].w[1] - src.w[1]); + MM[reg].w[2] = USATW(MM[reg].w[2] - src.w[2]); + MM[reg].w[3] = USATW(MM[reg].w[3] - src.w[3]); + + return 0; +} +static int opPSUBUSW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] = USATW(MM[reg].w[0] - src.w[0]); + MM[reg].w[1] = USATW(MM[reg].w[1] - src.w[1]); + MM[reg].w[2] = USATW(MM[reg].w[2] - src.w[2]); + MM[reg].w[3] = USATW(MM[reg].w[3] - src.w[3]); + + return 0; +} diff --git a/src/x86_ops_mmx_cmp.h b/src/x86_ops_mmx_cmp.h new file mode 100644 index 000000000..5fe3fc5ab --- /dev/null +++ b/src/x86_ops_mmx_cmp.h @@ -0,0 +1,205 @@ +static int opPCMPEQB_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] = (MM[reg].b[0] == src.b[0]) ? 0xff : 0; + MM[reg].b[1] = (MM[reg].b[1] == src.b[1]) ? 0xff : 0; + MM[reg].b[2] = (MM[reg].b[2] == src.b[2]) ? 0xff : 0; + MM[reg].b[3] = (MM[reg].b[3] == src.b[3]) ? 0xff : 0; + MM[reg].b[4] = (MM[reg].b[4] == src.b[4]) ? 0xff : 0; + MM[reg].b[5] = (MM[reg].b[5] == src.b[5]) ? 0xff : 0; + MM[reg].b[6] = (MM[reg].b[6] == src.b[6]) ? 0xff : 0; + MM[reg].b[7] = (MM[reg].b[7] == src.b[7]) ? 0xff : 0; + + return 0; +} +static int opPCMPEQB_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] = (MM[reg].b[0] == src.b[0]) ? 0xff : 0; + MM[reg].b[1] = (MM[reg].b[1] == src.b[1]) ? 0xff : 0; + MM[reg].b[2] = (MM[reg].b[2] == src.b[2]) ? 0xff : 0; + MM[reg].b[3] = (MM[reg].b[3] == src.b[3]) ? 0xff : 0; + MM[reg].b[4] = (MM[reg].b[4] == src.b[4]) ? 0xff : 0; + MM[reg].b[5] = (MM[reg].b[5] == src.b[5]) ? 0xff : 0; + MM[reg].b[6] = (MM[reg].b[6] == src.b[6]) ? 0xff : 0; + MM[reg].b[7] = (MM[reg].b[7] == src.b[7]) ? 0xff : 0; + + return 0; +} + +static int opPCMPGTB_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] = (MM[reg].sb[0] > src.sb[0]) ? 0xff : 0; + MM[reg].b[1] = (MM[reg].sb[1] > src.sb[1]) ? 0xff : 0; + MM[reg].b[2] = (MM[reg].sb[2] > src.sb[2]) ? 0xff : 0; + MM[reg].b[3] = (MM[reg].sb[3] > src.sb[3]) ? 0xff : 0; + MM[reg].b[4] = (MM[reg].sb[4] > src.sb[4]) ? 0xff : 0; + MM[reg].b[5] = (MM[reg].sb[5] > src.sb[5]) ? 0xff : 0; + MM[reg].b[6] = (MM[reg].sb[6] > src.sb[6]) ? 0xff : 0; + MM[reg].b[7] = (MM[reg].sb[7] > src.sb[7]) ? 0xff : 0; + + return 0; +} +static int opPCMPGTB_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] = (MM[reg].sb[0] > src.sb[0]) ? 0xff : 0; + MM[reg].b[1] = (MM[reg].sb[1] > src.sb[1]) ? 0xff : 0; + MM[reg].b[2] = (MM[reg].sb[2] > src.sb[2]) ? 0xff : 0; + MM[reg].b[3] = (MM[reg].sb[3] > src.sb[3]) ? 0xff : 0; + MM[reg].b[4] = (MM[reg].sb[4] > src.sb[4]) ? 0xff : 0; + MM[reg].b[5] = (MM[reg].sb[5] > src.sb[5]) ? 0xff : 0; + MM[reg].b[6] = (MM[reg].sb[6] > src.sb[6]) ? 0xff : 0; + MM[reg].b[7] = (MM[reg].sb[7] > src.sb[7]) ? 0xff : 0; + + return 0; +} + +static int opPCMPEQW_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] = (MM[reg].w[0] == src.w[0]) ? 0xffff : 0; + MM[reg].w[1] = (MM[reg].w[1] == src.w[1]) ? 0xffff : 0; + MM[reg].w[2] = (MM[reg].w[2] == src.w[2]) ? 0xffff : 0; + MM[reg].w[3] = (MM[reg].w[3] == src.w[3]) ? 0xffff : 0; + + return 0; +} +static int opPCMPEQW_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] = (MM[reg].w[0] == src.w[0]) ? 0xffff : 0; + MM[reg].w[1] = (MM[reg].w[1] == src.w[1]) ? 0xffff : 0; + MM[reg].w[2] = (MM[reg].w[2] == src.w[2]) ? 0xffff : 0; + MM[reg].w[3] = (MM[reg].w[3] == src.w[3]) ? 0xffff : 0; + + return 0; +} + +static int opPCMPGTW_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] = (MM[reg].sw[0] > src.sw[0]) ? 0xffff : 0; + MM[reg].w[1] = (MM[reg].sw[1] > src.sw[1]) ? 0xffff : 0; + MM[reg].w[2] = (MM[reg].sw[2] > src.sw[2]) ? 0xffff : 0; + MM[reg].w[3] = (MM[reg].sw[3] > src.sw[3]) ? 0xffff : 0; + + return 0; +} +static int opPCMPGTW_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] = (MM[reg].sw[0] > src.sw[0]) ? 0xffff : 0; + MM[reg].w[1] = (MM[reg].sw[1] > src.sw[1]) ? 0xffff : 0; + MM[reg].w[2] = (MM[reg].sw[2] > src.sw[2]) ? 0xffff : 0; + MM[reg].w[3] = (MM[reg].sw[3] > src.sw[3]) ? 0xffff : 0; + + return 0; +} + +static int opPCMPEQD_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].l[0] = (MM[reg].l[0] == src.l[0]) ? 0xffffffff : 0; + MM[reg].l[1] = (MM[reg].l[1] == src.l[1]) ? 0xffffffff : 0; + + return 0; +} +static int opPCMPEQD_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].l[0] = (MM[reg].l[0] == src.l[0]) ? 0xffffffff : 0; + MM[reg].l[1] = (MM[reg].l[1] == src.l[1]) ? 0xffffffff : 0; + + return 0; +} + +static int opPCMPGTD_a16(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].l[0] = (MM[reg].sl[0] > src.sl[0]) ? 0xffffffff : 0; + MM[reg].l[1] = (MM[reg].sl[1] > src.sl[1]) ? 0xffffffff : 0; + + return 0; +} +static int opPCMPGTD_a32(uint32_t fetchdat) +{ + MMX_REG src; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].l[0] = (MM[reg].sl[0] > src.sl[0]) ? 0xffffffff : 0; + MM[reg].l[1] = (MM[reg].sl[1] > src.sl[1]) ? 0xffffffff : 0; + + return 0; +} diff --git a/src/x86_ops_mmx_logic.h b/src/x86_ops_mmx_logic.h new file mode 100644 index 000000000..f6bb880b7 --- /dev/null +++ b/src/x86_ops_mmx_logic.h @@ -0,0 +1,91 @@ +static int opPAND_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].q &= src.q; + return 0; +} +static int opPAND_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].q &= src.q; + return 0; +} + +static int opPANDN_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].q = ~MM[reg].q & src.q; + return 0; +} +static int opPANDN_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].q = ~MM[reg].q & src.q; + return 0; +} + +static int opPOR_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].q |= src.q; + return 0; +} +static int opPOR_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].q |= src.q; + return 0; +} + +static int opPXOR_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].q ^= src.q; + return 0; +} +static int opPXOR_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].q ^= src.q; + return 0; +} diff --git a/src/x86_ops_mmx_mov.h b/src/x86_ops_mmx_mov.h new file mode 100644 index 000000000..4779ff6a3 --- /dev/null +++ b/src/x86_ops_mmx_mov.h @@ -0,0 +1,161 @@ +static int opMOVD_l_mm_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (mod == 3) + { + MM[reg].l[0] = cpu_state.regs[rm].l; + MM[reg].l[1] = 0; + CLOCK_CYCLES(1); + } + else + { + uint32_t dst; + + dst = readmeml(easeg, eaaddr); if (abrt) return 1; + MM[reg].l[0] = dst; + MM[reg].l[1] = 0; + + CLOCK_CYCLES(2); + } + return 0; +} +static int opMOVD_l_mm_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (mod == 3) + { + MM[reg].l[0] = cpu_state.regs[rm].l; + MM[reg].l[1] = 0; + CLOCK_CYCLES(1); + } + else + { + uint32_t dst; + + dst = readmeml(easeg, eaaddr); if (abrt) return 1; + MM[reg].l[0] = dst; + MM[reg].l[1] = 0; + + CLOCK_CYCLES(2); + } + return 0; +} + +static int opMOVD_mm_l_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (mod == 3) + { + cpu_state.regs[rm].l = MM[reg].l[0]; + CLOCK_CYCLES(1); + } + else + { + CHECK_WRITE(ea_seg, eaaddr, eaaddr + 3); + writememl(easeg, eaaddr, MM[reg].l[0]); if (abrt) return 1; + CLOCK_CYCLES(2); + } + return 0; +} +static int opMOVD_mm_l_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (mod == 3) + { + cpu_state.regs[rm].l = MM[reg].l[0]; + CLOCK_CYCLES(1); + } + else + { + CHECK_WRITE(ea_seg, eaaddr, eaaddr + 3); + writememl(easeg, eaaddr, MM[reg].l[0]); if (abrt) return 1; + CLOCK_CYCLES(2); + } + return 0; +} + +static int opMOVQ_q_mm_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (mod == 3) + { + MM[reg].q = MM[rm].q; + CLOCK_CYCLES(1); + } + else + { + uint64_t dst; + + dst = readmemq(easeg, eaaddr); if (abrt) return 1; + MM[reg].q = dst; + CLOCK_CYCLES(2); + } + return 0; +} +static int opMOVQ_q_mm_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (mod == 3) + { + MM[reg].q = MM[rm].q; + CLOCK_CYCLES(1); + } + else + { + uint64_t dst; + + dst = readmemq(easeg, eaaddr); if (abrt) return 1; + MM[reg].q = dst; + CLOCK_CYCLES(2); + } + return 0; +} + +static int opMOVQ_mm_q_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (mod == 3) + { + MM[rm].q = MM[reg].q; + CLOCK_CYCLES(1); + } + else + { + CHECK_WRITE(ea_seg, eaaddr, eaaddr + 7); + writememq(easeg, eaaddr, MM[reg].l[0]); if (abrt) return 1; + CLOCK_CYCLES(2); + } + return 0; +} +static int opMOVQ_mm_q_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (mod == 3) + { + MM[rm].q = MM[reg].q; + CLOCK_CYCLES(1); + } + else + { + CHECK_WRITE(ea_seg, eaaddr, eaaddr + 7); + writememq(easeg, eaaddr, MM[reg].q); if (abrt) return 1; + CLOCK_CYCLES(2); + } + return 0; +} diff --git a/src/x86_ops_mmx_pack.h b/src/x86_ops_mmx_pack.h new file mode 100644 index 000000000..e9b84fbd3 --- /dev/null +++ b/src/x86_ops_mmx_pack.h @@ -0,0 +1,324 @@ +static int opPUNPCKLDQ_a16(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_16(fetchdat); + if (mod == 3) + { + MM[reg].l[1] = MM[rm].l[0]; + CLOCK_CYCLES(1); + } + else + { + uint32_t src; + + src = readmeml(easeg, eaaddr); if (abrt) return 0; + MM[reg].l[1] = src; + + CLOCK_CYCLES(2); + } + return 0; +} +static int opPUNPCKLDQ_a32(uint32_t fetchdat) +{ + MMX_ENTER(); + + fetch_ea_32(fetchdat); + if (mod == 3) + { + MM[reg].l[1] = MM[rm].l[0]; + CLOCK_CYCLES(1); + } + else + { + uint32_t src; + + src = readmeml(easeg, eaaddr); if (abrt) return 0; + MM[reg].l[1] = src; + + CLOCK_CYCLES(2); + } + return 0; +} + +static int opPUNPCKHDQ_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].l[0] = MM[reg].l[1]; + MM[reg].l[1] = src.l[1]; + + return 0; +} +static int opPUNPCKHDQ_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].l[0] = MM[reg].l[1]; + MM[reg].l[1] = src.l[1]; + + return 0; +} + +static int opPUNPCKLBW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].b[7] = src.b[3]; + MM[reg].b[6] = MM[reg].b[3]; + MM[reg].b[5] = src.b[2]; + MM[reg].b[4] = MM[reg].b[2]; + MM[reg].b[3] = src.b[1]; + MM[reg].b[2] = MM[reg].b[1]; + MM[reg].b[1] = src.b[0]; + MM[reg].b[0] = MM[reg].b[0]; + + return 0; +} +static int opPUNPCKLBW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].b[7] = src.b[3]; + MM[reg].b[6] = MM[reg].b[3]; + MM[reg].b[5] = src.b[2]; + MM[reg].b[4] = MM[reg].b[2]; + MM[reg].b[3] = src.b[1]; + MM[reg].b[2] = MM[reg].b[1]; + MM[reg].b[1] = src.b[0]; + MM[reg].b[0] = MM[reg].b[0]; + + return 0; +} + +static int opPUNPCKHBW_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] = MM[reg].b[4]; + MM[reg].b[1] = src.b[4]; + MM[reg].b[2] = MM[reg].b[5]; + MM[reg].b[3] = src.b[5]; + MM[reg].b[4] = MM[reg].b[6]; + MM[reg].b[5] = src.b[6]; + MM[reg].b[6] = MM[reg].b[7]; + MM[reg].b[7] = src.b[7]; + + return 0; +} +static int opPUNPCKHBW_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].b[0] = MM[reg].b[4]; + MM[reg].b[1] = src.b[4]; + MM[reg].b[2] = MM[reg].b[5]; + MM[reg].b[3] = src.b[5]; + MM[reg].b[4] = MM[reg].b[6]; + MM[reg].b[5] = src.b[6]; + MM[reg].b[6] = MM[reg].b[7]; + MM[reg].b[7] = src.b[7]; + + return 0; +} + +static int opPUNPCKLWD_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].w[3] = src.w[1]; + MM[reg].w[2] = MM[reg].w[1]; + MM[reg].w[1] = src.w[0]; + MM[reg].w[0] = MM[reg].w[0]; + + return 0; +} +static int opPUNPCKLWD_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].w[3] = src.w[1]; + MM[reg].w[2] = MM[reg].w[1]; + MM[reg].w[1] = src.w[0]; + MM[reg].w[0] = MM[reg].w[0]; + + return 0; +} + +static int opPUNPCKHWD_a16(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] = MM[reg].w[2]; + MM[reg].w[1] = src.w[2]; + MM[reg].w[2] = MM[reg].w[3]; + MM[reg].w[3] = src.w[3]; + + return 0; +} +static int opPUNPCKHWD_a32(uint32_t fetchdat) +{ + MMX_REG src; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + + MM[reg].w[0] = MM[reg].w[2]; + MM[reg].w[1] = src.w[2]; + MM[reg].w[2] = MM[reg].w[3]; + MM[reg].w[3] = src.w[3]; + + return 0; +} + +static int opPACKSSWB_a16(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + dst = MM[reg]; + + MM[reg].sb[0] = SSATB(dst.sw[0]); + MM[reg].sb[1] = SSATB(dst.sw[1]); + MM[reg].sb[2] = SSATB(dst.sw[2]); + MM[reg].sb[3] = SSATB(dst.sw[3]); + MM[reg].sb[4] = SSATB(src.sw[0]); + MM[reg].sb[5] = SSATB(src.sw[1]); + MM[reg].sb[6] = SSATB(src.sw[2]); + MM[reg].sb[7] = SSATB(src.sw[3]); + + return 0; +} +static int opPACKSSWB_a32(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + dst = MM[reg]; + + MM[reg].sb[0] = SSATB(dst.sw[0]); + MM[reg].sb[1] = SSATB(dst.sw[1]); + MM[reg].sb[2] = SSATB(dst.sw[2]); + MM[reg].sb[3] = SSATB(dst.sw[3]); + MM[reg].sb[4] = SSATB(src.sw[0]); + MM[reg].sb[5] = SSATB(src.sw[1]); + MM[reg].sb[6] = SSATB(src.sw[2]); + MM[reg].sb[7] = SSATB(src.sw[3]); + + return 0; +} + +static int opPACKUSWB_a16(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + dst = MM[reg]; + + MM[reg].b[0] = USATB(dst.sw[0]); + MM[reg].b[1] = USATB(dst.sw[1]); + MM[reg].b[2] = USATB(dst.sw[2]); + MM[reg].b[3] = USATB(dst.sw[3]); + MM[reg].b[4] = USATB(src.sw[0]); + MM[reg].b[5] = USATB(src.sw[1]); + MM[reg].b[6] = USATB(src.sw[2]); + MM[reg].b[7] = USATB(src.sw[3]); + + return 0; +} +static int opPACKUSWB_a32(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + dst = MM[reg]; + + MM[reg].b[0] = USATB(dst.sw[0]); + MM[reg].b[1] = USATB(dst.sw[1]); + MM[reg].b[2] = USATB(dst.sw[2]); + MM[reg].b[3] = USATB(dst.sw[3]); + MM[reg].b[4] = USATB(src.sw[0]); + MM[reg].b[5] = USATB(src.sw[1]); + MM[reg].b[6] = USATB(src.sw[2]); + MM[reg].b[7] = USATB(src.sw[3]); + + return 0; +} + +static int opPACKSSDW_a16(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSRC(); + dst = MM[reg]; + + MM[reg].sw[0] = SSATW(dst.sl[0]); + MM[reg].sw[1] = SSATW(dst.sl[1]); + MM[reg].sw[2] = SSATW(src.sl[0]); + MM[reg].sw[3] = SSATW(src.sl[1]); + + return 0; +} +static int opPACKSSDW_a32(uint32_t fetchdat) +{ + MMX_REG src, dst; + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSRC(); + dst = MM[reg]; + + MM[reg].sw[0] = SSATW(dst.sl[0]); + MM[reg].sw[1] = SSATW(dst.sl[1]); + MM[reg].sw[2] = SSATW(src.sl[0]); + MM[reg].sw[3] = SSATW(src.sl[1]); + + return 0; +} diff --git a/src/x86_ops_mmx_shift.h b/src/x86_ops_mmx_shift.h new file mode 100644 index 000000000..760998a7d --- /dev/null +++ b/src/x86_ops_mmx_shift.h @@ -0,0 +1,452 @@ +#define MMX_GETSHIFT() \ + if (mod == 3) \ + { \ + shift = MM[rm].b[0]; \ + CLOCK_CYCLES(1); \ + } \ + else \ + { \ + shift = readmemb(easeg, eaaddr); if (abrt) return 0; \ + CLOCK_CYCLES(2); \ + } + +static int opPSxxW_imm(uint32_t fetchdat) +{ + int reg = fetchdat & 7; + int op = fetchdat & 0x38; + int shift = (fetchdat >> 8) & 0xff; + + cpu_state.pc += 2; + MMX_ENTER(); + + switch (op) + { + case 0x10: /*PSRLW*/ + if (shift > 15) + MM[reg].q = 0; + else + { + MM[reg].w[0] >>= shift; + MM[reg].w[1] >>= shift; + MM[reg].w[2] >>= shift; + MM[reg].w[3] >>= shift; + } + break; + case 0x20: /*PSRAW*/ + if (shift > 15) + shift = 15; + MM[reg].sw[0] >>= shift; + MM[reg].sw[1] >>= shift; + MM[reg].sw[2] >>= shift; + MM[reg].sw[3] >>= shift; + break; + case 0x30: /*PSLLW*/ + if (shift > 15) + MM[reg].q = 0; + else + { + MM[reg].w[0] <<= shift; + MM[reg].w[1] <<= shift; + MM[reg].w[2] <<= shift; + MM[reg].w[3] <<= shift; + } + break; + default: + pclog("Bad PSxxW (0F 71) instruction %02X\n", op); + cpu_state.pc = oldpc; + x86illegal(); + return 0; + } + + CLOCK_CYCLES(1); + return 0; +} + +static int opPSLLW_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + MM[reg].q = 0; + else + { + MM[reg].w[0] <<= shift; + MM[reg].w[1] <<= shift; + MM[reg].w[2] <<= shift; + MM[reg].w[3] <<= shift; + } + + return 0; +} +static int opPSLLW_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + MM[reg].q = 0; + else + { + MM[reg].w[0] <<= shift; + MM[reg].w[1] <<= shift; + MM[reg].w[2] <<= shift; + MM[reg].w[3] <<= shift; + } + + return 0; +} + +static int opPSRLW_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + MM[reg].q = 0; + else + { + MM[reg].w[0] >>= shift; + MM[reg].w[1] >>= shift; + MM[reg].w[2] >>= shift; + MM[reg].w[3] >>= shift; + } + + return 0; +} +static int opPSRLW_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + MM[reg].q = 0; + else + { + MM[reg].w[0] >>= shift; + MM[reg].w[1] >>= shift; + MM[reg].w[2] >>= shift; + MM[reg].w[3] >>= shift; + } + + return 0; +} + +static int opPSRAW_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + shift = 15; + + MM[reg].sw[0] >>= shift; + MM[reg].sw[1] >>= shift; + MM[reg].sw[2] >>= shift; + MM[reg].sw[3] >>= shift; + + return 0; +} +static int opPSRAW_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 15) + shift = 15; + + MM[reg].sw[0] >>= shift; + MM[reg].sw[1] >>= shift; + MM[reg].sw[2] >>= shift; + MM[reg].sw[3] >>= shift; + + return 0; +} + +static int opPSxxD_imm(uint32_t fetchdat) +{ + int reg = fetchdat & 7; + int op = fetchdat & 0x38; + int shift = (fetchdat >> 8) & 0xff; + + cpu_state.pc += 2; + MMX_ENTER(); + + switch (op) + { + case 0x10: /*PSRLD*/ + if (shift > 31) + MM[reg].q = 0; + else + { + MM[reg].l[0] >>= shift; + MM[reg].l[1] >>= shift; + } + break; + case 0x20: /*PSRAD*/ + if (shift > 31) + shift = 31; + MM[reg].sl[0] >>= shift; + MM[reg].sl[1] >>= shift; + break; + case 0x30: /*PSLLD*/ + if (shift > 31) + MM[reg].q = 0; + else + { + MM[reg].l[0] <<= shift; + MM[reg].l[1] <<= shift; + } + break; + default: + pclog("Bad PSxxD (0F 72) instruction %02X\n", op); + cpu_state.pc = oldpc; + x86illegal(); + return 0; + } + + CLOCK_CYCLES(1); + return 0; +} + +static int opPSLLD_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + MM[reg].q = 0; + else + { + MM[reg].l[0] <<= shift; + MM[reg].l[1] <<= shift; + } + + return 0; +} +static int opPSLLD_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + MM[reg].q = 0; + else + { + MM[reg].l[0] <<= shift; + MM[reg].l[1] <<= shift; + } + + return 0; +} + +static int opPSRLD_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + MM[reg].q = 0; + else + { + MM[reg].l[0] >>= shift; + MM[reg].l[1] >>= shift; + } + + return 0; +} +static int opPSRLD_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + MM[reg].q = 0; + else + { + MM[reg].l[0] >>= shift; + MM[reg].l[1] >>= shift; + } + + return 0; +} + +static int opPSRAD_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + shift = 31; + + MM[reg].sl[0] >>= shift; + MM[reg].sl[1] >>= shift; + + return 0; +} +static int opPSRAD_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 31) + shift = 31; + + MM[reg].sl[0] >>= shift; + MM[reg].sl[1] >>= shift; + + return 0; +} + +static int opPSxxQ_imm(uint32_t fetchdat) +{ + int reg = fetchdat & 7; + int op = fetchdat & 0x38; + int shift = (fetchdat >> 8) & 0xff; + + cpu_state.pc += 2; + MMX_ENTER(); + + switch (op) + { + case 0x10: /*PSRLW*/ + if (shift > 63) + MM[reg].q = 0; + else + MM[reg].q >>= shift; + break; + case 0x20: /*PSRAW*/ + if (shift > 63) + shift = 63; + MM[reg].sq >>= shift; + break; + case 0x30: /*PSLLW*/ + if (shift > 63) + MM[reg].q = 0; + else + MM[reg].q <<= shift; + break; + default: + pclog("Bad PSxxQ (0F 73) instruction %02X\n", op); + cpu_state.pc = oldpc; + x86illegal(); + return 0; + } + + CLOCK_CYCLES(1); + return 0; +} + +static int opPSLLQ_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 63) + MM[reg].q = 0; + else + MM[reg].q <<= shift; + + return 0; +} +static int opPSLLQ_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 63) + MM[reg].q = 0; + else + MM[reg].q <<= shift; + + return 0; +} + +static int opPSRLQ_a16(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_16(fetchdat); + MMX_GETSHIFT(); + + if (shift > 63) + MM[reg].q = 0; + else + MM[reg].q >>= shift; + + return 0; +} +static int opPSRLQ_a32(uint32_t fetchdat) +{ + int shift; + + MMX_ENTER(); + + fetch_ea_32(fetchdat); + MMX_GETSHIFT(); + + if (shift > 63) + MM[reg].q = 0; + else + MM[reg].q >>= shift; + + return 0; +} diff --git a/src/x86_ops_mov.h b/src/x86_ops_mov.h new file mode 100644 index 000000000..d75f93861 --- /dev/null +++ b/src/x86_ops_mov.h @@ -0,0 +1,655 @@ +static int opMOV_AL_imm(uint32_t fetchdat) +{ + AL = getbytef(); + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_AH_imm(uint32_t fetchdat) +{ + AH = getbytef(); + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_BL_imm(uint32_t fetchdat) +{ + BL = getbytef(); + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_BH_imm(uint32_t fetchdat) +{ + BH = getbytef(); + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_CL_imm(uint32_t fetchdat) +{ + CL = getbytef(); + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_CH_imm(uint32_t fetchdat) +{ + CH = getbytef(); + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_DL_imm(uint32_t fetchdat) +{ + DL = getbytef(); + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_DH_imm(uint32_t fetchdat) +{ + DH = getbytef(); + CLOCK_CYCLES(timing_rr); + return 0; +} + +static int opMOV_AX_imm(uint32_t fetchdat) +{ + AX = getwordf(); + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_BX_imm(uint32_t fetchdat) +{ + BX = getwordf(); + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_CX_imm(uint32_t fetchdat) +{ + CX = getwordf(); + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_DX_imm(uint32_t fetchdat) +{ + DX = getwordf(); + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_SI_imm(uint32_t fetchdat) +{ + SI = getwordf(); + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_DI_imm(uint32_t fetchdat) +{ + DI = getwordf(); + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_BP_imm(uint32_t fetchdat) +{ + BP = getwordf(); + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_SP_imm(uint32_t fetchdat) +{ + SP = getwordf(); + CLOCK_CYCLES(timing_rr); + return 0; +} + +static int opMOV_EAX_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (abrt) return 1; + EAX = templ; + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_EBX_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (abrt) return 1; + EBX = templ; + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_ECX_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (abrt) return 1; + ECX = templ; + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_EDX_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (abrt) return 1; + EDX = templ; + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_ESI_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (abrt) return 1; + ESI = templ; + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_EDI_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (abrt) return 1; + EDI = templ; + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_EBP_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (abrt) return 1; + EBP = templ; + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opMOV_ESP_imm(uint32_t fetchdat) +{ + uint32_t templ = getlong(); if (abrt) return 1; + ESP = templ; + CLOCK_CYCLES(timing_rr); + return 0; +} + +static int opMOV_b_imm_a16(uint32_t fetchdat) +{ + uint8_t temp; + fetch_ea_16(fetchdat); + temp = readmemb(cs,cpu_state.pc); cpu_state.pc++; if (abrt) return 1; + CHECK_WRITE(ea_seg, eaaddr, eaaddr); + seteab(temp); + CLOCK_CYCLES(timing_rr); + return abrt; +} +static int opMOV_b_imm_a32(uint32_t fetchdat) +{ + uint8_t temp; + fetch_ea_32(fetchdat); + temp = getbyte(); if (abrt) return 1; + seteab(temp); + CLOCK_CYCLES(timing_rr); + return abrt; +} + +static int opMOV_w_imm_a16(uint32_t fetchdat) +{ + uint16_t temp; + fetch_ea_16(fetchdat); + temp = getword(); if (abrt) return 1; + seteaw(temp); + CLOCK_CYCLES(timing_rr); + return abrt; +} +static int opMOV_w_imm_a32(uint32_t fetchdat) +{ + uint16_t temp; + fetch_ea_32(fetchdat); + temp = getword(); if (abrt) return 1; + seteaw(temp); + CLOCK_CYCLES(timing_rr); + return abrt; +} +static int opMOV_l_imm_a16(uint32_t fetchdat) +{ + uint32_t temp; + fetch_ea_16(fetchdat); + temp = getlong(); if (abrt) return 1; + seteal(temp); + CLOCK_CYCLES(timing_rr); + return abrt; +} +static int opMOV_l_imm_a32(uint32_t fetchdat) +{ + uint32_t temp; + fetch_ea_32(fetchdat); + temp = getlong(); if (abrt) return 1; + seteal(temp); + CLOCK_CYCLES(timing_rr); + return abrt; +} + + +static int opMOV_AL_a16(uint32_t fetchdat) +{ + uint16_t addr = getwordf(); + uint8_t temp = readmemb(ea_seg->base, addr); if (abrt) return 1; + AL = temp; + CLOCK_CYCLES((is486) ? 1 : 4); + return 0; +} +static int opMOV_AL_a32(uint32_t fetchdat) +{ + uint32_t addr = getlong(); + uint8_t temp = readmemb(ea_seg->base, addr); if (abrt) return 1; + AL = temp; + CLOCK_CYCLES((is486) ? 1 : 4); + return 0; +} +static int opMOV_AX_a16(uint32_t fetchdat) +{ + uint16_t addr = getwordf(); + uint16_t temp = readmemw(ea_seg->base, addr); if (abrt) return 1; + AX = temp; + CLOCK_CYCLES((is486) ? 1 : 4); + return 0; +} +static int opMOV_AX_a32(uint32_t fetchdat) +{ + uint32_t addr = getlong(); + uint16_t temp = readmemw(ea_seg->base, addr); if (abrt) return 1; + AX = temp; + CLOCK_CYCLES((is486) ? 1 : 4); + return 0; +} +static int opMOV_EAX_a16(uint32_t fetchdat) +{ + uint16_t addr = getwordf(); + uint32_t temp = readmeml(ea_seg->base, addr); if (abrt) return 1; + EAX = temp; + CLOCK_CYCLES((is486) ? 1 : 4); + return 0; +} +static int opMOV_EAX_a32(uint32_t fetchdat) +{ + uint32_t addr = getlong(); + uint32_t temp = readmeml(ea_seg->base, addr); if (abrt) return 1; + EAX = temp; + CLOCK_CYCLES((is486) ? 1 : 4); + return 0; +} + +static int opMOV_a16_AL(uint32_t fetchdat) +{ + uint16_t addr = getwordf(); + writememb(ea_seg->base, addr, AL); + CLOCK_CYCLES((is486) ? 1 : 2); + return abrt; +} +static int opMOV_a32_AL(uint32_t fetchdat) +{ + uint32_t addr = getlong(); + writememb(ea_seg->base, addr, AL); + CLOCK_CYCLES((is486) ? 1 : 2); + return abrt; +} +static int opMOV_a16_AX(uint32_t fetchdat) +{ + uint16_t addr = getwordf(); + writememw(ea_seg->base, addr, AX); + CLOCK_CYCLES((is486) ? 1 : 2); + return abrt; +} +static int opMOV_a32_AX(uint32_t fetchdat) +{ + uint32_t addr = getlong(); if (abrt) return 1; + writememw(ea_seg->base, addr, AX); + CLOCK_CYCLES((is486) ? 1 : 2); + return abrt; +} +static int opMOV_a16_EAX(uint32_t fetchdat) +{ + uint16_t addr = getwordf(); + writememl(ea_seg->base, addr, EAX); + CLOCK_CYCLES((is486) ? 1 : 2); + return abrt; +} +static int opMOV_a32_EAX(uint32_t fetchdat) +{ + uint32_t addr = getlong(); if (abrt) return 1; + writememl(ea_seg->base, addr, EAX); + CLOCK_CYCLES((is486) ? 1 : 2); + return abrt; +} + + +static int opLEA_w_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + ILLEGAL_ON(mod == 3); + cpu_state.regs[reg].w = eaaddr; + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opLEA_w_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + ILLEGAL_ON(mod == 3); + cpu_state.regs[reg].w = eaaddr; + CLOCK_CYCLES(timing_rr); + return 0; +} + +static int opLEA_l_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + ILLEGAL_ON(mod == 3); + cpu_state.regs[reg].l = eaaddr & 0xffff; + CLOCK_CYCLES(timing_rr); + return 0; +} +static int opLEA_l_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + ILLEGAL_ON(mod == 3); + cpu_state.regs[reg].l = eaaddr; + CLOCK_CYCLES(timing_rr); + return 0; +} + + + +static int opXLAT_a16(uint32_t fetchdat) +{ + uint32_t addr = (BX + AL)&0xFFFF; + uint8_t temp = readmemb(ea_seg->base, addr); if (abrt) return 1; + AL = temp; + CLOCK_CYCLES(5); + return 0; +} +static int opXLAT_a32(uint32_t fetchdat) +{ + uint32_t addr = EBX + AL; + uint8_t temp = readmemb(ea_seg->base, addr); if (abrt) return 1; + AL = temp; + CLOCK_CYCLES(5); + return 0; +} + +static int opMOV_b_r_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + if (mod == 3) + { + setr8(rm, getr8(reg)); + CLOCK_CYCLES(timing_rr); + } + else + { + CHECK_WRITE(ea_seg, eaaddr, eaaddr); + seteab(getr8(reg)); + CLOCK_CYCLES(is486 ? 1 : 2); + } + return abrt; +} +static int opMOV_b_r_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + if (mod == 3) + { + setr8(rm, getr8(reg)); + CLOCK_CYCLES(timing_rr); + } + else + { + CHECK_WRITE(ea_seg, eaaddr, eaaddr); + seteab(getr8(reg)); + CLOCK_CYCLES(is486 ? 1 : 2); + } + return abrt; +} +static int opMOV_w_r_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + if (mod == 3) + { + cpu_state.regs[rm].w = cpu_state.regs[reg].w; + CLOCK_CYCLES(timing_rr); + } + else + { + CHECK_WRITE(ea_seg, eaaddr, eaaddr+1); + seteaw(cpu_state.regs[reg].w); + CLOCK_CYCLES(is486 ? 1 : 2); + } + return abrt; +} +static int opMOV_w_r_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + if (mod == 3) + { + cpu_state.regs[rm].w = cpu_state.regs[reg].w; + CLOCK_CYCLES(timing_rr); + } + else + { + CHECK_WRITE(ea_seg, eaaddr, eaaddr+1); + seteaw(cpu_state.regs[reg].w); + CLOCK_CYCLES(is486 ? 1 : 2); + } + return abrt; +} +static int opMOV_l_r_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + if (mod == 3) + { + cpu_state.regs[rm].l = cpu_state.regs[reg].l; + CLOCK_CYCLES(timing_rr); + } + else + { + CHECK_WRITE(ea_seg, eaaddr, eaaddr+3); + seteal(cpu_state.regs[reg].l); + CLOCK_CYCLES(is486 ? 1 : 2); + } + return abrt; +} +static int opMOV_l_r_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + if (mod == 3) + { + cpu_state.regs[rm].l = cpu_state.regs[reg].l; + CLOCK_CYCLES(timing_rr); + } + else + { + CHECK_WRITE(ea_seg, eaaddr, eaaddr+3); + seteal(cpu_state.regs[reg].l); + CLOCK_CYCLES(is486 ? 1 : 2); + } + return abrt; +} + +static int opMOV_r_b_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + if (mod == 3) + { + setr8(reg, getr8(rm)); + CLOCK_CYCLES(timing_rr); + } + else + { + uint8_t temp; + CHECK_READ(ea_seg, eaaddr, eaaddr); + temp = geteab(); if (abrt) return 1; + setr8(reg, temp); + CLOCK_CYCLES(is486 ? 1 : 4); + } + return 0; +} +static int opMOV_r_b_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + if (mod == 3) + { + setr8(reg, getr8(rm)); + CLOCK_CYCLES(timing_rr); + } + else + { + uint8_t temp; + CHECK_READ(ea_seg, eaaddr, eaaddr); + temp = geteab(); if (abrt) return 1; + setr8(reg, temp); + CLOCK_CYCLES(is486 ? 1 : 4); + } + return 0; +} +static int opMOV_r_w_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + if (mod == 3) + { + cpu_state.regs[reg].w = cpu_state.regs[rm].w; + CLOCK_CYCLES(timing_rr); + } + else + { + uint16_t temp; + CHECK_READ(ea_seg, eaaddr, eaaddr+1); + temp = geteaw(); if (abrt) return 1; + cpu_state.regs[reg].w = temp; + CLOCK_CYCLES((is486) ? 1 : 4); + } + return 0; +} +static int opMOV_r_w_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + if (mod == 3) + { + cpu_state.regs[reg].w = cpu_state.regs[rm].w; + CLOCK_CYCLES(timing_rr); + } + else + { + uint16_t temp; + CHECK_READ(ea_seg, eaaddr, eaaddr+1); + temp = geteaw(); if (abrt) return 1; + cpu_state.regs[reg].w = temp; + CLOCK_CYCLES((is486) ? 1 : 4); + } + return 0; +} +static int opMOV_r_l_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + if (mod == 3) + { + cpu_state.regs[reg].l = cpu_state.regs[rm].l; + CLOCK_CYCLES(timing_rr); + } + else + { + uint32_t temp; + CHECK_READ(ea_seg, eaaddr, eaaddr+3); + temp = geteal(); if (abrt) return 1; + cpu_state.regs[reg].l = temp; + CLOCK_CYCLES(is486 ? 1 : 4); + } + return 0; +} +static int opMOV_r_l_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + if (mod == 3) + { + cpu_state.regs[reg].l = cpu_state.regs[rm].l; + CLOCK_CYCLES(timing_rr); + } + else + { + uint32_t temp; + CHECK_READ(ea_seg, eaaddr, eaaddr+3); + temp = geteal(); if (abrt) return 1; + cpu_state.regs[reg].l = temp; + CLOCK_CYCLES(is486 ? 1 : 4); + } + return 0; +} + +#define opCMOV(condition) \ + static int opCMOV ## condition ## _w_a16(uint32_t fetchdat) \ + { \ + fetch_ea_16(fetchdat); \ + if (cond_ ## condition) \ + { \ + if (mod == 3) \ + cpu_state.regs[reg].w = cpu_state.regs[rm].w; \ + else \ + { \ + uint16_t temp; \ + CHECK_READ(ea_seg, eaaddr, eaaddr+1); \ + temp = geteaw(); if (abrt) return 1; \ + cpu_state.regs[reg].w = temp; \ + } \ + } \ + CLOCK_CYCLES(1); \ + return 0; \ + } \ + static int opCMOV ## condition ## _w_a32(uint32_t fetchdat) \ + { \ + fetch_ea_32(fetchdat); \ + if (cond_ ## condition) \ + { \ + if (mod == 3) \ + cpu_state.regs[reg].w = cpu_state.regs[rm].w; \ + else \ + { \ + uint16_t temp; \ + CHECK_READ(ea_seg, eaaddr, eaaddr+1); \ + temp = geteaw(); if (abrt) return 1; \ + cpu_state.regs[reg].w = temp; \ + } \ + } \ + CLOCK_CYCLES(1); \ + return 0; \ + } \ + static int opCMOV ## condition ## _l_a16(uint32_t fetchdat) \ + { \ + fetch_ea_16(fetchdat); \ + if (cond_ ## condition) \ + { \ + if (mod == 3) \ + cpu_state.regs[reg].l = cpu_state.regs[rm].l; \ + else \ + { \ + uint32_t temp; \ + CHECK_READ(ea_seg, eaaddr, eaaddr+3); \ + temp = geteal(); if (abrt) return 1; \ + cpu_state.regs[reg].l = temp; \ + } \ + } \ + CLOCK_CYCLES(1); \ + return 0; \ + } \ + static int opCMOV ## condition ## _l_a32(uint32_t fetchdat) \ + { \ + fetch_ea_32(fetchdat); \ + if (cond_ ## condition) \ + { \ + if (mod == 3) \ + cpu_state.regs[reg].l = cpu_state.regs[rm].l; \ + else \ + { \ + uint32_t temp; \ + CHECK_READ(ea_seg, eaaddr, eaaddr+3); \ + temp = geteal(); if (abrt) return 1; \ + cpu_state.regs[reg].l = temp; \ + } \ + } \ + CLOCK_CYCLES(1); \ + return 0; \ + } + +opCMOV(O) +opCMOV(NO) +opCMOV(B) +opCMOV(NB) +opCMOV(E) +opCMOV(NE) +opCMOV(BE) +opCMOV(NBE) +opCMOV(S) +opCMOV(NS) +opCMOV(P) +opCMOV(NP) +opCMOV(L) +opCMOV(NL) +opCMOV(LE) +opCMOV(NLE) diff --git a/src/x86_ops_mov_ctrl.h b/src/x86_ops_mov_ctrl.h new file mode 100644 index 000000000..633173417 --- /dev/null +++ b/src/x86_ops_mov_ctrl.h @@ -0,0 +1,268 @@ +static int opMOV_r_CRx_a16(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load from CRx\n"); + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + switch (reg) + { + case 0: + cpu_state.regs[rm].l = cr0; + if (is486) + cpu_state.regs[rm].l |= 0x10; /*ET hardwired on 486*/ + break; + case 2: + cpu_state.regs[rm].l = cr2; + break; + case 3: + cpu_state.regs[rm].l = cr3; + break; + case 4: + if (cpu_hasCR4) + { + cpu_state.regs[rm].l = cr4; + break; + } + default: + pclog("Bad read of CR%i %i\n",rmdat&7,reg); + cpu_state.pc = oldpc; + x86illegal(); + break; + } + CLOCK_CYCLES(6); + return 0; +} +static int opMOV_r_CRx_a32(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load from CRx\n"); + x86gpf(NULL, 0); + return 1; + } + fetch_ea_32(fetchdat); + switch (reg) + { + case 0: + cpu_state.regs[rm].l = cr0; + if (is486) + cpu_state.regs[rm].l |= 0x10; /*ET hardwired on 486*/ + break; + case 2: + cpu_state.regs[rm].l = cr2; + break; + case 3: + cpu_state.regs[rm].l = cr3; + break; + case 4: + if (cpu_hasCR4) + { + cpu_state.regs[rm].l = cr4; + break; + } + default: + pclog("Bad read of CR%i %i\n",rmdat&7,reg); + cpu_state.pc = oldpc; + x86illegal(); + break; + } + CLOCK_CYCLES(6); + return 0; +} + +static int opMOV_r_DRx_a16(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load from DRx\n"); + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + cpu_state.regs[rm].l = dr[reg]; + CLOCK_CYCLES(6); + return 0; +} +static int opMOV_r_DRx_a32(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load from DRx\n"); + x86gpf(NULL, 0); + return 1; + } + fetch_ea_32(fetchdat); + cpu_state.regs[rm].l = dr[reg]; + CLOCK_CYCLES(6); + return 0; +} + +static int opMOV_CRx_r_a16(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load CRx\n"); + x86gpf(NULL,0); + return 1; + } + fetch_ea_16(fetchdat); + switch (reg) + { + case 0: + if ((cpu_state.regs[rm].l ^ cr0) & 0x80000001) + flushmmucache(); + cr0 = cpu_state.regs[rm].l; + if (cpu_16bitbus) + cr0 |= 0x10; + if (!(cr0 & 0x80000000)) + mmu_perm=4; + break; + case 2: + cr2 = cpu_state.regs[rm].l; + break; + case 3: + cr3 = cpu_state.regs[rm].l; + flushmmucache(); + break; + case 4: + if (cpu_hasCR4) + { + cr4 = cpu_state.regs[rm].l & cpu_CR4_mask; + break; + } + + default: + pclog("Bad load CR%i\n", reg); + cpu_state.pc = oldpc; + x86illegal(); + break; + } + CLOCK_CYCLES(10); + return 0; +} +static int opMOV_CRx_r_a32(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load CRx\n"); + x86gpf(NULL,0); + return 1; + } + fetch_ea_32(fetchdat); + switch (reg) + { + case 0: + if ((cpu_state.regs[rm].l ^ cr0) & 0x80000001) + flushmmucache(); + cr0 = cpu_state.regs[rm].l; + if (cpu_16bitbus) + cr0 |= 0x10; + if (!(cr0 & 0x80000000)) + mmu_perm=4; + break; + case 2: + cr2 = cpu_state.regs[rm].l; + break; + case 3: + cr3 = cpu_state.regs[rm].l; + flushmmucache(); + break; + case 4: + if (cpu_hasCR4) + { + cr4 = cpu_state.regs[rm].l & cpu_CR4_mask; + break; + } + + default: + pclog("Bad load CR%i\n", reg); + cpu_state.pc = oldpc; + x86illegal(); + break; + } + CLOCK_CYCLES(10); + return 0; +} + +static int opMOV_DRx_r_a16(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load DRx\n"); + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + dr[reg] = cpu_state.regs[rm].l; + CLOCK_CYCLES(6); + return 0; +} +static int opMOV_DRx_r_a32(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load DRx\n"); + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + dr[reg] = cpu_state.regs[rm].l; + CLOCK_CYCLES(6); + return 0; +} + +static int opMOV_r_TRx_a16(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load from TRx\n"); + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + cpu_state.regs[rm].l = 0; + CLOCK_CYCLES(6); + return 0; +} +static int opMOV_r_TRx_a32(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load from TRx\n"); + x86gpf(NULL, 0); + return 1; + } + fetch_ea_32(fetchdat); + cpu_state.regs[rm].l = 0; + CLOCK_CYCLES(6); + return 0; +} + +static int opMOV_TRx_r_a16(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load TRx\n"); + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + CLOCK_CYCLES(6); + return 0; +} +static int opMOV_TRx_r_a32(uint32_t fetchdat) +{ + if ((CPL || (eflags&VM_FLAG)) && (cr0&1)) + { + pclog("Can't load TRx\n"); + x86gpf(NULL, 0); + return 1; + } + fetch_ea_16(fetchdat); + CLOCK_CYCLES(6); + return 0; +} + diff --git a/src/x86_ops_mov_seg.h b/src/x86_ops_mov_seg.h new file mode 100644 index 000000000..d728423a6 --- /dev/null +++ b/src/x86_ops_mov_seg.h @@ -0,0 +1,394 @@ +static int opMOV_w_seg_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + seteaw(ES); + break; + case 0x08: /*CS*/ + seteaw(CS); + break; + case 0x18: /*DS*/ + seteaw(DS); + break; + case 0x10: /*SS*/ + seteaw(SS); + break; + case 0x20: /*FS*/ + seteaw(FS); + break; + case 0x28: /*GS*/ + seteaw(GS); + break; + } + + CLOCK_CYCLES((mod == 3) ? 2 : 3); + return abrt; +} +static int opMOV_w_seg_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + seteaw(ES); + break; + case 0x08: /*CS*/ + seteaw(CS); + break; + case 0x18: /*DS*/ + seteaw(DS); + break; + case 0x10: /*SS*/ + seteaw(SS); + break; + case 0x20: /*FS*/ + seteaw(FS); + break; + case 0x28: /*GS*/ + seteaw(GS); + break; + } + + CLOCK_CYCLES((mod == 3) ? 2 : 3); + return abrt; +} + +static int opMOV_l_seg_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + if (mod == 3) cpu_state.regs[rm].l = ES; + else seteaw(ES); + break; + case 0x08: /*CS*/ + if (mod == 3) cpu_state.regs[rm].l = CS; + else seteaw(CS); + break; + case 0x18: /*DS*/ + if (mod == 3) cpu_state.regs[rm].l = DS; + else seteaw(DS); + break; + case 0x10: /*SS*/ + if (mod == 3) cpu_state.regs[rm].l = SS; + else seteaw(SS); + break; + case 0x20: /*FS*/ + if (mod == 3) cpu_state.regs[rm].l = FS; + else seteaw(FS); + break; + case 0x28: /*GS*/ + if (mod == 3) cpu_state.regs[rm].l = GS; + else seteaw(GS); + break; + } + + CLOCK_CYCLES((mod == 3) ? 2 : 3); + return abrt; +} +static int opMOV_l_seg_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + if (mod == 3) cpu_state.regs[rm].l = ES; + else seteaw(ES); + break; + case 0x08: /*CS*/ + if (mod == 3) cpu_state.regs[rm].l = CS; + else seteaw(CS); + break; + case 0x18: /*DS*/ + if (mod == 3) cpu_state.regs[rm].l = DS; + else seteaw(DS); + break; + case 0x10: /*SS*/ + if (mod == 3) cpu_state.regs[rm].l = SS; + else seteaw(SS); + break; + case 0x20: /*FS*/ + if (mod == 3) cpu_state.regs[rm].l = FS; + else seteaw(FS); + break; + case 0x28: /*GS*/ + if (mod == 3) cpu_state.regs[rm].l = GS; + else seteaw(GS); + break; + } + + CLOCK_CYCLES((mod == 3) ? 2 : 3); + return abrt; +} + +static int opMOV_seg_w_a16(uint32_t fetchdat) +{ + uint16_t new_seg; + + fetch_ea_16(fetchdat); + + new_seg=geteaw(); if (abrt) return 1; + + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + loadseg(new_seg, &_es); + break; + case 0x18: /*DS*/ + loadseg(new_seg, &_ds); + break; + case 0x10: /*SS*/ + loadseg(new_seg, &_ss); + if (abrt) return 1; + oldpc = cpu_state.pc; + op32 = use32; + ssegs = 0; + ea_seg = &_ds; + fetchdat = fastreadl(cs + cpu_state.pc); + cpu_state.pc++; + if (abrt) return 1; + x86_opcodes[(fetchdat & 0xff) | op32](fetchdat >> 8); + return 1; + case 0x20: /*FS*/ + loadseg(new_seg, &_fs); + break; + case 0x28: /*GS*/ + loadseg(new_seg, &_gs); + break; + } + + CLOCK_CYCLES((mod == 3) ? 2 : 5); + return abrt; +} +static int opMOV_seg_w_a32(uint32_t fetchdat) +{ + uint16_t new_seg; + + fetch_ea_32(fetchdat); + + new_seg=geteaw(); if (abrt) return 1; + + switch (rmdat & 0x38) + { + case 0x00: /*ES*/ + loadseg(new_seg, &_es); + break; + case 0x18: /*DS*/ + loadseg(new_seg, &_ds); + break; + case 0x10: /*SS*/ + loadseg(new_seg, &_ss); + if (abrt) return 1; + oldpc = cpu_state.pc; + op32 = use32; + ssegs = 0; + ea_seg = &_ds; + fetchdat = fastreadl(cs + cpu_state.pc); + cpu_state.pc++; + if (abrt) return 1; + x86_opcodes[(fetchdat & 0xff) | op32](fetchdat >> 8); + return 1; + case 0x20: /*FS*/ + loadseg(new_seg, &_fs); + break; + case 0x28: /*GS*/ + loadseg(new_seg, &_gs); + break; + } + + CLOCK_CYCLES((mod == 3) ? 2 : 5); + return abrt; +} + + +static int opLDS_w_a16(uint32_t fetchdat) +{ + uint16_t addr, seg; + + fetch_ea_16(fetchdat); + ILLEGAL_ON(mod == 3); + addr = readmemw(easeg, eaaddr); + seg = readmemw(easeg, eaaddr + 2); if (abrt) return 1; + loadseg(seg, &_ds); if (abrt) return 1; + cpu_state.regs[reg].w = addr; + + CLOCK_CYCLES(7); + return 0; +} +static int opLDS_w_a32(uint32_t fetchdat) +{ + uint16_t addr, seg; + + fetch_ea_32(fetchdat); + ILLEGAL_ON(mod == 3); + addr = readmemw(easeg, eaaddr); + seg = readmemw(easeg, eaaddr + 2); if (abrt) return 1; + loadseg(seg, &_ds); if (abrt) return 1; + cpu_state.regs[reg].w = addr; + + CLOCK_CYCLES(7); + return 0; +} +static int opLDS_l_a16(uint32_t fetchdat) +{ + uint32_t addr; + uint16_t seg; + + fetch_ea_16(fetchdat); + ILLEGAL_ON(mod == 3); + addr = readmeml(easeg, eaaddr); + seg = readmemw(easeg, eaaddr + 4); if (abrt) return 1; + loadseg(seg, &_ds); if (abrt) return 1; + cpu_state.regs[reg].l = addr; + + CLOCK_CYCLES(7); + return 0; +} +static int opLDS_l_a32(uint32_t fetchdat) +{ + uint32_t addr; + uint16_t seg; + + fetch_ea_32(fetchdat); + ILLEGAL_ON(mod == 3); + addr = readmeml(easeg, eaaddr); + seg = readmemw(easeg, eaaddr + 4); if (abrt) return 1; + loadseg(seg, &_ds); if (abrt) return 1; + cpu_state.regs[reg].l = addr; + + CLOCK_CYCLES(7); + return 0; +} + +static int opLSS_w_a16(uint32_t fetchdat) +{ + uint16_t addr, seg; + + fetch_ea_16(fetchdat); + ILLEGAL_ON(mod == 3); + addr = readmemw(easeg, eaaddr); + seg = readmemw(easeg, eaaddr + 2); if (abrt) return 1; + loadseg(seg, &_ss); if (abrt) return 1; + cpu_state.regs[reg].w = addr; + + CLOCK_CYCLES(7); + return 1; +} +static int opLSS_w_a32(uint32_t fetchdat) +{ + uint16_t addr, seg; + + fetch_ea_32(fetchdat); + ILLEGAL_ON(mod == 3); + addr = readmemw(easeg, eaaddr); + seg = readmemw(easeg, eaaddr + 2); if (abrt) return 1; + loadseg(seg, &_ss); if (abrt) return 1; + cpu_state.regs[reg].w = addr; + + CLOCK_CYCLES(7); + return 1; +} +static int opLSS_l_a16(uint32_t fetchdat) +{ + uint32_t addr; + uint16_t seg; + + fetch_ea_16(fetchdat); + ILLEGAL_ON(mod == 3); + addr = readmeml(easeg, eaaddr); + seg = readmemw(easeg, eaaddr + 4); if (abrt) return 1; + loadseg(seg, &_ss); if (abrt) return 1; + cpu_state.regs[reg].l = addr; + + CLOCK_CYCLES(7); + return 1; +} +static int opLSS_l_a32(uint32_t fetchdat) +{ + uint32_t addr; + uint16_t seg; + + fetch_ea_32(fetchdat); + ILLEGAL_ON(mod == 3); + addr = readmeml(easeg, eaaddr); + seg = readmemw(easeg, eaaddr + 4); if (abrt) return 1; + loadseg(seg, &_ss); if (abrt) return 1; + cpu_state.regs[reg].l = addr; + + CLOCK_CYCLES(7); + return 1; +} + +#define opLsel(name, sel) \ + static int opL ## name ## _w_a16(uint32_t fetchdat) \ + { \ + uint16_t addr, seg; \ + \ + fetch_ea_16(fetchdat); \ + ILLEGAL_ON(mod == 3); \ + addr = readmemw(easeg, eaaddr); \ + seg = readmemw(easeg, eaaddr + 2); if (abrt) return 1; \ + loadseg(seg, &sel); if (abrt) return 1; \ + cpu_state.regs[reg].w = addr; \ + \ + CLOCK_CYCLES(7); \ + return 0; \ + } \ + \ + static int opL ## name ## _w_a32(uint32_t fetchdat) \ + { \ + uint16_t addr, seg; \ + \ + fetch_ea_32(fetchdat); \ + ILLEGAL_ON(mod == 3); \ + addr = readmemw(easeg, eaaddr); \ + seg = readmemw(easeg, eaaddr + 2); if (abrt) return 1; \ + loadseg(seg, &sel); if (abrt) return 1; \ + cpu_state.regs[reg].w = addr; \ + \ + CLOCK_CYCLES(7); \ + return 0; \ + } \ + \ + static int opL ## name ## _l_a16(uint32_t fetchdat) \ + { \ + uint32_t addr; \ + uint16_t seg; \ + \ + fetch_ea_16(fetchdat); \ + ILLEGAL_ON(mod == 3); \ + addr = readmeml(easeg, eaaddr); \ + seg = readmemw(easeg, eaaddr + 4); if (abrt) return 1; \ + loadseg(seg, &sel); if (abrt) return 1; \ + cpu_state.regs[reg].l = addr; \ + \ + CLOCK_CYCLES(7); \ + return 0; \ + } \ + \ + static int opL ## name ## _l_a32(uint32_t fetchdat) \ + { \ + uint32_t addr; \ + uint16_t seg; \ + \ + fetch_ea_32(fetchdat); \ + ILLEGAL_ON(mod == 3); \ + addr = readmeml(easeg, eaaddr); \ + seg = readmemw(easeg, eaaddr + 4); if (abrt) return 1; \ + loadseg(seg, &sel); if (abrt) return 1; \ + cpu_state.regs[reg].l = addr; \ + \ + CLOCK_CYCLES(7); \ + return 0; \ + } + +opLsel(ES, _es) +opLsel(FS, _fs) +opLsel(GS, _gs) diff --git a/src/x86_ops_movx.h b/src/x86_ops_movx.h new file mode 100644 index 000000000..ac5ff45e1 --- /dev/null +++ b/src/x86_ops_movx.h @@ -0,0 +1,167 @@ +static int opMOVZX_w_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_16(fetchdat); + temp = geteab(); if (abrt) return 1; + cpu_state.regs[reg].w = (uint16_t)temp; + + CLOCK_CYCLES(3); + return 0; +} +static int opMOVZX_w_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_32(fetchdat); + temp = geteab(); if (abrt) return 1; + cpu_state.regs[reg].w = (uint16_t)temp; + + CLOCK_CYCLES(3); + return 0; +} +static int opMOVZX_l_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_16(fetchdat); + temp = geteab(); if (abrt) return 1; + cpu_state.regs[reg].l = (uint32_t)temp; + + CLOCK_CYCLES(3); + return 0; +} +static int opMOVZX_l_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_32(fetchdat); + temp = geteab(); if (abrt) return 1; + cpu_state.regs[reg].l = (uint32_t)temp; + + CLOCK_CYCLES(3); + return 0; +} +static int opMOVZX_w_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_16(fetchdat); + temp = geteaw(); if (abrt) return 1; + cpu_state.regs[reg].w = temp; + + CLOCK_CYCLES(3); + return 0; +} +static int opMOVZX_w_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_32(fetchdat); + temp = geteaw(); if (abrt) return 1; + cpu_state.regs[reg].w = temp; + + CLOCK_CYCLES(3); + return 0; +} +static int opMOVZX_l_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_16(fetchdat); + temp = geteaw(); if (abrt) return 1; + cpu_state.regs[reg].l = (uint32_t)temp; + + CLOCK_CYCLES(3); + return 0; +} +static int opMOVZX_l_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_32(fetchdat); + temp = geteaw(); if (abrt) return 1; + cpu_state.regs[reg].l = (uint32_t)temp; + + CLOCK_CYCLES(3); + return 0; +} + +static int opMOVSX_w_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_16(fetchdat); + temp = geteab(); if (abrt) return 1; + cpu_state.regs[reg].w = (uint16_t)temp; + if (temp & 0x80) + cpu_state.regs[reg].w |= 0xff00; + + CLOCK_CYCLES(3); + return 0; +} +static int opMOVSX_w_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_32(fetchdat); + temp = geteab(); if (abrt) return 1; + cpu_state.regs[reg].w = (uint16_t)temp; + if (temp & 0x80) + cpu_state.regs[reg].w |= 0xff00; + + CLOCK_CYCLES(3); + return 0; +} +static int opMOVSX_l_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_16(fetchdat); + temp = geteab(); if (abrt) return 1; + cpu_state.regs[reg].l = (uint32_t)temp; + if (temp & 0x80) + cpu_state.regs[reg].l |= 0xffffff00; + + CLOCK_CYCLES(3); + return 0; +} +static int opMOVSX_l_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + + fetch_ea_32(fetchdat); + temp = geteab(); if (abrt) return 1; + cpu_state.regs[reg].l = (uint32_t)temp; + if (temp & 0x80) + cpu_state.regs[reg].l |= 0xffffff00; + + CLOCK_CYCLES(3); + return 0; +} +static int opMOVSX_l_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_16(fetchdat); + temp = geteaw(); if (abrt) return 1; + cpu_state.regs[reg].l = (uint32_t)temp; + if (temp & 0x8000) + cpu_state.regs[reg].l |= 0xffff0000; + + CLOCK_CYCLES(3); + return 0; +} +static int opMOVSX_l_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + + fetch_ea_32(fetchdat); + temp = geteaw(); if (abrt) return 1; + cpu_state.regs[reg].l = (uint32_t)temp; + if (temp & 0x8000) + cpu_state.regs[reg].l |= 0xffff0000; + + CLOCK_CYCLES(3); + return 0; +} diff --git a/src/x86_ops_msr.h b/src/x86_ops_msr.h new file mode 100644 index 000000000..3d8cc07f8 --- /dev/null +++ b/src/x86_ops_msr.h @@ -0,0 +1,30 @@ +static int opRDTSC(uint32_t fetchdat) +{ + if (!cpu_hasrdtsc) + { + cpu_state.pc = oldpc; + x86illegal(); + return 1; + } + if ((cr4 & CR4_TSD) && CPL) + { + x86gpf("RDTSC when TSD set and CPL != 0", 0); + return 1; + } + EAX = tsc & 0xffffffff; + EDX = tsc >> 32; + CLOCK_CYCLES(1); + return 0; +} + +static int opRDPMC(uint32_t fetchdat) +{ + if (ECX > 1 || (!(cr4 & CR4_PCE) && (cr0 & 1) && CPL)) + { + x86gpf("RDPMC not allowed", 0); + return 1; + } + EAX = EDX = 0; + CLOCK_CYCLES(1); + return 0; +} diff --git a/src/x86_ops_mul.h b/src/x86_ops_mul.h new file mode 100644 index 000000000..b64276789 --- /dev/null +++ b/src/x86_ops_mul.h @@ -0,0 +1,222 @@ +static int opIMUL_w_iw_a16(uint32_t fetchdat) +{ + int32_t templ; + int16_t tempw, tempw2; + + fetch_ea_16(fetchdat); + + tempw = geteaw(); if (abrt) return 1; + tempw2 = getword(); if (abrt) return 1; + + templ = ((int)tempw) * ((int)tempw2); + flags_rebuild(); + if ((templ >> 15) != 0 && (templ >> 15) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[reg].w = templ & 0xffff; + + CLOCK_CYCLES((mod == 3) ? 14 : 17); + return 0; +} +static int opIMUL_w_iw_a32(uint32_t fetchdat) +{ + int32_t templ; + int16_t tempw, tempw2; + + fetch_ea_32(fetchdat); + + tempw = geteaw(); if (abrt) return 1; + tempw2 = getword(); if (abrt) return 1; + + templ = ((int)tempw) * ((int)tempw2); + flags_rebuild(); + if ((templ >> 15) != 0 && (templ >> 15) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[reg].w = templ & 0xffff; + + CLOCK_CYCLES((mod == 3) ? 14 : 17); + return 0; +} + +static int opIMUL_l_il_a16(uint32_t fetchdat) +{ + int64_t temp64; + int32_t templ, templ2; + + fetch_ea_16(fetchdat); + + templ = geteal(); if (abrt) return 1; + templ2 = getlong(); if (abrt) return 1; + + temp64 = ((int64_t)templ) * ((int64_t)templ2); + flags_rebuild(); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[reg].l = temp64 & 0xffffffff; + + CLOCK_CYCLES(25); + return 0; +} +static int opIMUL_l_il_a32(uint32_t fetchdat) +{ + int64_t temp64; + int32_t templ, templ2; + + fetch_ea_32(fetchdat); + + templ = geteal(); if (abrt) return 1; + templ2 = getlong(); if (abrt) return 1; + + temp64 = ((int64_t)templ) * ((int64_t)templ2); + flags_rebuild(); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[reg].l = temp64 & 0xffffffff; + + CLOCK_CYCLES(25); + return 0; +} + +static int opIMUL_w_ib_a16(uint32_t fetchdat) +{ + int32_t templ; + int16_t tempw, tempw2; + + fetch_ea_16(fetchdat); + + tempw = geteaw(); if (abrt) return 1; + tempw2 = getbyte(); if (abrt) return 1; + if (tempw2 & 0x80) tempw2 |= 0xff00; + + templ = ((int)tempw) * ((int)tempw2); + flags_rebuild(); + if ((templ >> 15) != 0 && (templ >> 15) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[reg].w = templ & 0xffff; + + CLOCK_CYCLES((mod == 3) ? 14 : 17); + return 0; +} +static int opIMUL_w_ib_a32(uint32_t fetchdat) +{ + int32_t templ; + int16_t tempw, tempw2; + + fetch_ea_32(fetchdat); + + tempw = geteaw(); if (abrt) return 1; + tempw2 = getbyte(); if (abrt) return 1; + if (tempw2 & 0x80) tempw2 |= 0xff00; + + templ = ((int)tempw) * ((int)tempw2); + flags_rebuild(); + if ((templ >> 15) != 0 && (templ >> 15) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[reg].w = templ & 0xffff; + + CLOCK_CYCLES((mod == 3) ? 14 : 17); + return 0; +} + +static int opIMUL_l_ib_a16(uint32_t fetchdat) +{ + int64_t temp64; + int32_t templ, templ2; + + fetch_ea_16(fetchdat); + templ = geteal(); if (abrt) return 1; + templ2 = getbyte(); if (abrt) return 1; + if (templ2 & 0x80) templ2 |= 0xffffff00; + + temp64 = ((int64_t)templ)*((int64_t)templ2); + flags_rebuild(); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[reg].l = temp64 & 0xffffffff; + + CLOCK_CYCLES(20); + return 0; +} +static int opIMUL_l_ib_a32(uint32_t fetchdat) +{ + int64_t temp64; + int32_t templ, templ2; + + fetch_ea_32(fetchdat); + templ = geteal(); if (abrt) return 1; + templ2 = getbyte(); if (abrt) return 1; + if (templ2 & 0x80) templ2 |= 0xffffff00; + + temp64 = ((int64_t)templ)*((int64_t)templ2); + flags_rebuild(); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + cpu_state.regs[reg].l = temp64 & 0xffffffff; + + CLOCK_CYCLES(20); + return 0; +} + + + +static int opIMUL_w_w_a16(uint32_t fetchdat) +{ + int32_t templ; + + fetch_ea_16(fetchdat); + templ = (int32_t)(int16_t)cpu_state.regs[reg].w * (int32_t)(int16_t)geteaw(); + if (abrt) return 1; + cpu_state.regs[reg].w = templ & 0xFFFF; + flags_rebuild(); + if ((templ >> 15) != 0 && (templ >> 15) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + + CLOCK_CYCLES(18); + return 0; +} +static int opIMUL_w_w_a32(uint32_t fetchdat) +{ + int32_t templ; + + fetch_ea_32(fetchdat); + templ = (int32_t)(int16_t)cpu_state.regs[reg].w * (int32_t)(int16_t)geteaw(); + if (abrt) return 1; + cpu_state.regs[reg].w = templ & 0xFFFF; + flags_rebuild(); + if ((templ >> 15) != 0 && (templ >> 15) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + + CLOCK_CYCLES(18); + return 0; +} + +static int opIMUL_l_l_a16(uint32_t fetchdat) +{ + int64_t temp64; + + fetch_ea_16(fetchdat); + temp64 = (int64_t)(int32_t)cpu_state.regs[reg].l * (int64_t)(int32_t)geteal(); + if (abrt) return 1; + cpu_state.regs[reg].l = temp64 & 0xFFFFFFFF; + flags_rebuild(); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + + CLOCK_CYCLES(30); + return 0; +} +static int opIMUL_l_l_a32(uint32_t fetchdat) +{ + int64_t temp64; + + fetch_ea_32(fetchdat); + temp64 = (int64_t)(int32_t)cpu_state.regs[reg].l * (int64_t)(int32_t)geteal(); + if (abrt) return 1; + cpu_state.regs[reg].l = temp64 & 0xFFFFFFFF; + flags_rebuild(); + if ((temp64 >> 31) != 0 && (temp64 >> 31) != -1) flags |= C_FLAG | V_FLAG; + else flags &= ~(C_FLAG | V_FLAG); + + CLOCK_CYCLES(30); + return 0; +} + diff --git a/src/x86_ops_pmode.h b/src/x86_ops_pmode.h new file mode 100644 index 000000000..bdda2f3f0 --- /dev/null +++ b/src/x86_ops_pmode.h @@ -0,0 +1,408 @@ +static int opARPL_a16(uint32_t fetchdat) +{ + uint16_t temp_seg; + + NOTRM + fetch_ea_16(fetchdat); + pclog("ARPL_a16\n"); + temp_seg = geteaw(); if (abrt) return 1; + + flags_rebuild(); + if ((temp_seg & 3) < (cpu_state.regs[reg].w & 3)) + { + temp_seg = (temp_seg & 0xfffc) | (cpu_state.regs[reg].w & 3); + seteaw(temp_seg); if (abrt) return 1; + flags |= Z_FLAG; + } + else + flags &= ~Z_FLAG; + + CLOCK_CYCLES(is486 ? 9 : 20); + return 0; +} +static int opARPL_a32(uint32_t fetchdat) +{ + uint16_t temp_seg; + + NOTRM + fetch_ea_32(fetchdat); + pclog("ARPL_a32\n"); + temp_seg = geteaw(); if (abrt) return 1; + + flags_rebuild(); + if ((temp_seg & 3) < (cpu_state.regs[reg].w & 3)) + { + temp_seg = (temp_seg & 0xfffc) | (cpu_state.regs[reg].w & 3); + seteaw(temp_seg); if (abrt) return 1; + flags |= Z_FLAG; + } + else + flags &= ~Z_FLAG; + + CLOCK_CYCLES(is486 ? 9 : 20); + return 0; +} + +#define opLAR(name, fetch_ea, is32) \ + static int opLAR_ ## name(uint32_t fetchdat) \ + { \ + int valid; \ + uint16_t sel, desc; \ + \ + NOTRM \ + fetch_ea(fetchdat); \ + \ + sel = geteaw(); if (abrt) return 1; \ + \ + flags_rebuild(); \ + if (!(sel & 0xfffc)) { flags &= ~Z_FLAG; return 0; } /*Null selector*/ \ + valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); \ + if (valid) \ + { \ + cpl_override = 1; \ + desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4); \ + cpl_override = 0; if (abrt) return 1; \ + } \ + flags &= ~Z_FLAG; \ + if ((desc & 0x1f00) == 0x000) valid = 0; \ + if ((desc & 0x1f00) == 0x800) valid = 0; \ + if ((desc & 0x1f00) == 0xa00) valid = 0; \ + if ((desc & 0x1f00) == 0xd00) valid = 0; \ + if ((desc & 0x1c00) < 0x1c00) /*Exclude conforming code segments*/ \ + { \ + int dpl = (desc >> 13) & 3; \ + if (dpl < CPL || dpl < (sel & 3)) valid = 0; \ + } \ + if (valid) \ + { \ + flags |= Z_FLAG; \ + cpl_override = 1; \ + if (is32) \ + cpu_state.regs[reg].l = readmeml(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4) & 0xffff00; \ + else \ + cpu_state.regs[reg].w = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4) & 0xff00; \ + cpl_override = 0; \ + } \ + CLOCK_CYCLES(11); \ + return abrt; \ + } + +opLAR(w_a16, fetch_ea_16, 0) +opLAR(w_a32, fetch_ea_32, 0) +opLAR(l_a16, fetch_ea_16, 1) +opLAR(l_a32, fetch_ea_32, 1) + +#define opLSL(name, fetch_ea, is32) \ + static int opLSL_ ## name(uint32_t fetchdat) \ + { \ + int valid; \ + uint16_t sel, desc; \ + \ + NOTRM \ + fetch_ea(fetchdat); \ + \ + sel = geteaw(); if (abrt) return 1; \ + flags_rebuild(); \ + flags &= ~Z_FLAG; \ + if (!(sel & 0xfffc)) return 0; /*Null selector*/ \ + valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); \ + if (valid) \ + { \ + cpl_override = 1; \ + desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4); \ + cpl_override = 0; if (abrt) return 1; \ + } \ + if ((desc & 0x1400) == 0x400) valid = 0; /*Interrupt or trap or call gate*/ \ + if ((desc & 0x1f00) == 0x000) valid = 0; /*Invalid*/ \ + if ((desc & 0x1f00) == 0xa00) valid = 0; /*Invalid*/ \ + if ((desc & 0x1c00) != 0x1c00) /*Exclude conforming code segments*/ \ + { \ + int rpl = (desc >> 13) & 3; \ + if (rpl < CPL || rpl < (sel & 3)) valid = 0; \ + } \ + if (valid) \ + { \ + flags |= Z_FLAG; \ + cpl_override = 1; \ + if (is32) \ + { \ + cpu_state.regs[reg].l = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7)); \ + cpu_state.regs[reg].l |= (readmemb(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 6) & 0xF) << 16; \ + if (readmemb(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 6) & 0x80) \ + { \ + cpu_state.regs[reg].l <<= 12; \ + cpu_state.regs[reg].l |= 0xFFF; \ + } \ + } \ + else \ + cpu_state.regs[reg].w = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7)); \ + cpl_override = 0; \ + } \ + CLOCK_CYCLES(10); \ + return abrt; \ + } + +opLSL(w_a16, fetch_ea_16, 0) +opLSL(w_a32, fetch_ea_32, 0) +opLSL(l_a16, fetch_ea_16, 1) +opLSL(l_a32, fetch_ea_32, 1) + + +static int op0F00_common(uint32_t fetchdat) +{ + int dpl, valid, granularity; + uint32_t addr, base, limit; + uint16_t desc, sel; + uint8_t access; + +// pclog("op0F00 %02X %04X:%04X\n", rmdat & 0x38, CS, pc); + switch (rmdat & 0x38) + { + case 0x00: /*SLDT*/ + seteaw(ldt.seg); + CLOCK_CYCLES(4); + break; + case 0x08: /*STR*/ + seteaw(tr.seg); + CLOCK_CYCLES(4); + break; + case 0x10: /*LLDT*/ + if ((CPL || eflags&VM_FLAG) && (cr0&1)) + { + pclog("Invalid LLDT!\n"); + x86gpf(NULL,0); + return 1; + } + sel = geteaw(); if (abrt) return 1; + addr = (sel & ~7) + gdt.base; + limit = readmemw(0, addr) + ((readmemb(0, addr + 6) & 0xf) << 16); + base = (readmemw(0, addr + 2)) | (readmemb(0, addr + 4) << 16) | (readmemb(0, addr + 7) << 24); + access = readmemb(0, addr + 5); + granularity = readmemb(0, addr + 6) & 0x80; + if (abrt) return 1; + ldt.limit = limit; + ldt.access = access; + if (granularity) + { + ldt.limit <<= 12; + ldt.limit |= 0xfff; + } + ldt.base = base; + ldt.seg = sel; + CLOCK_CYCLES(20); + break; + case 0x18: /*LTR*/ + if ((CPL || eflags&VM_FLAG) && (cr0&1)) + { + pclog("Invalid LTR!\n"); + x86gpf(NULL,0); + break; + } + sel = geteaw(); if (abrt) return 1; + addr = (sel & ~7) + gdt.base; + limit = readmemw(0, addr) + ((readmemb(0, addr + 6) & 0xf) << 16); + base = (readmemw(0, addr + 2)) | (readmemb(0, addr + 4) << 16) | (readmemb(0, addr + 7) << 24); + access = readmemb(0, addr + 5); + granularity = readmemb(0, addr + 6) & 0x80; + if (abrt) return 1; + tr.seg = sel; + tr.limit = limit; + tr.access = access; + if (granularity) + { + tr.limit <<= 12; + tr.limit |= 0xFFF; + } + tr.base = base; + CLOCK_CYCLES(20); + break; + case 0x20: /*VERR*/ + sel = geteaw(); if (abrt) return 1; + flags_rebuild(); + flags &= ~Z_FLAG; + if (!(sel & 0xfffc)) return 0; /*Null selector*/ + cpl_override = 1; + valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); + desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4); + cpl_override = 0; if (abrt) return 1; + if (!(desc & 0x1000)) valid = 0; + if ((desc & 0xC00) != 0xC00) /*Exclude conforming code segments*/ + { + dpl = (desc >> 13) & 3; /*Check permissions*/ + if (dpl < CPL || dpl < (sel & 3)) valid = 0; + } + if ((desc & 0x0800) && !(desc & 0x0200)) valid = 0; /*Non-readable code*/ + if (valid) flags |= Z_FLAG; + CLOCK_CYCLES(20); + break; + case 0x28: /*VERW*/ + sel = geteaw(); if (abrt) return 1; + flags_rebuild(); + flags &= ~Z_FLAG; + if (!(sel & 0xfffc)) return 0; /*Null selector*/ + cpl_override = 1; + valid = (sel & ~7) < ((sel & 4) ? ldt.limit : gdt.limit); + desc = readmemw(0, ((sel & 4) ? ldt.base : gdt.base) + (sel & ~7) + 4); + cpl_override = 0; if (abrt) return 1; + if (!(desc & 0x1000)) valid = 0; + dpl = (desc >> 13) & 3; /*Check permissions*/ + if (dpl < CPL || dpl < (sel & 3)) valid = 0; + if (desc & 0x0800) valid = 0; /*Code*/ + if (!(desc & 0x0200)) valid = 0; /*Read-only data*/ + if (valid) flags |= Z_FLAG; + CLOCK_CYCLES(20); + break; + + default: + pclog("Bad 0F 00 opcode %02X\n", rmdat & 0x38); + cpu_state.pc -= 3; + x86illegal(); + break; + } + return abrt; +} + +static int op0F00_a16(uint32_t fetchdat) +{ + NOTRM + + fetch_ea_16(fetchdat); + + return op0F00_common(fetchdat); +} +static int op0F00_a32(uint32_t fetchdat) +{ + NOTRM + + fetch_ea_32(fetchdat); + + return op0F00_common(fetchdat); +} + +static int op0F01_common(uint32_t fetchdat, int is32, int is286) +{ + uint32_t base; + uint16_t limit, tempw; +// pclog("op0F01 %02X %04X:%04X\n", rmdat & 0x38, CS, pc); + switch (rmdat & 0x38) + { + case 0x00: /*SGDT*/ + seteaw(gdt.limit); + base = gdt.base; //is32 ? gdt.base : (gdt.base & 0xffffff); + if (is286) + base |= 0xff000000; + writememl(easeg, eaaddr + 2, base); + CLOCK_CYCLES(7); + break; + case 0x08: /*SIDT*/ + seteaw(idt.limit); + base = idt.base; + if (is286) + base |= 0xff000000; + writememl(easeg, eaaddr + 2, base); + CLOCK_CYCLES(7); + break; + case 0x10: /*LGDT*/ + if ((CPL || eflags&VM_FLAG) && (cr0&1)) + { + pclog("Invalid LGDT!\n"); + x86gpf(NULL,0); + break; + } +// pclog("LGDT %08X:%08X\n", easeg, eaaddr); + limit = geteaw(); + base = readmeml(0, easeg + eaaddr + 2); if (abrt) return 1; +// pclog(" %08X %04X\n", base, limit); + gdt.limit = limit; + gdt.base = base; + if (!is32) gdt.base &= 0xffffff; + CLOCK_CYCLES(11); + break; + case 0x18: /*LIDT*/ + if ((CPL || eflags&VM_FLAG) && (cr0&1)) + { + pclog("Invalid LIDT!\n"); + x86gpf(NULL,0); + break; + } +// pclog("LIDT %08X:%08X\n", easeg, eaaddr); + limit = geteaw(); + base = readmeml(0, easeg + eaaddr + 2); if (abrt) return 1; +// pclog(" %08X %04X\n", base, limit); + idt.limit = limit; + idt.base = base; + if (!is32) idt.base &= 0xffffff; + CLOCK_CYCLES(11); + break; + + case 0x20: /*SMSW*/ + if (is486) seteaw(msw); + else seteaw(msw | 0xFF00); + CLOCK_CYCLES(2); + break; + case 0x30: /*LMSW*/ + if ((CPL || eflags&VM_FLAG) && (msw&1)) + { + pclog("LMSW - ring not zero!\n"); + x86gpf(NULL, 0); + break; + } + tempw = geteaw(); if (abrt) return 1; + if (msw & 1) tempw |= 1; + msw = tempw; + break; + + case 0x38: /*INVLPG*/ + if (is486) + { + if ((CPL || eflags&VM_FLAG) && (cr0&1)) + { + pclog("Invalid INVLPG!\n"); + x86gpf(NULL, 0); + break; + } + mmu_invalidate(ds + eaaddr); + CLOCK_CYCLES(12); + break; + } + + default: + pclog("Bad 0F 01 opcode %02X\n", rmdat & 0x38); + cpu_state.pc -= 3; + x86illegal(); + break; + } + return abrt; +} + +static int op0F01_w_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + + return op0F01_common(fetchdat, 0, 0); +} +static int op0F01_w_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + + return op0F01_common(fetchdat, 0, 0); +} +static int op0F01_l_a16(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + + return op0F01_common(fetchdat, 1, 0); +} +static int op0F01_l_a32(uint32_t fetchdat) +{ + fetch_ea_32(fetchdat); + + return op0F01_common(fetchdat, 1, 0); +} + +static int op0F01_286(uint32_t fetchdat) +{ + fetch_ea_16(fetchdat); + + return op0F01_common(fetchdat, 0, 1); +} diff --git a/src/x86_ops_prefix.h b/src/x86_ops_prefix.h new file mode 100644 index 000000000..e9eb74caa --- /dev/null +++ b/src/x86_ops_prefix.h @@ -0,0 +1,80 @@ +#define op_seg(name, seg) \ +static int op ## name ## _w_a16(uint32_t fetchdat) \ +{ \ + fetchdat = fastreadl(cs + cpu_state.pc); \ + if (abrt) return 1; \ + cpu_state.pc++; \ + \ + ea_seg = &seg; \ + ssegs = 1; \ + CLOCK_CYCLES(4); \ + \ + return x86_opcodes[fetchdat & 0xff](fetchdat >> 8); \ +} \ + \ +static int op ## name ## _l_a16(uint32_t fetchdat) \ +{ \ + fetchdat = fastreadl(cs + cpu_state.pc); \ + if (abrt) return 1; \ + cpu_state.pc++; \ + \ + ea_seg = &seg; \ + ssegs = 1; \ + CLOCK_CYCLES(4); \ + \ + return x86_opcodes[(fetchdat & 0xff) | 0x100](fetchdat >> 8); \ +} \ + \ +static int op ## name ## _w_a32(uint32_t fetchdat) \ +{ \ + fetchdat = fastreadl(cs + cpu_state.pc); \ + if (abrt) return 1; \ + cpu_state.pc++; \ + \ + ea_seg = &seg; \ + ssegs = 1; \ + CLOCK_CYCLES(4); \ + \ + return x86_opcodes[(fetchdat & 0xff) | 0x200](fetchdat >> 8); \ +} \ + \ +static int op ## name ## _l_a32(uint32_t fetchdat) \ +{ \ + fetchdat = fastreadl(cs + cpu_state.pc); \ + if (abrt) return 1; \ + cpu_state.pc++; \ + \ + ea_seg = &seg; \ + ssegs = 1; \ + CLOCK_CYCLES(4); \ + \ + return x86_opcodes[(fetchdat & 0xff) | 0x300](fetchdat >> 8); \ +} + +op_seg(CS, _cs) +op_seg(DS, _ds) +op_seg(ES, _es) +op_seg(FS, _fs) +op_seg(GS, _gs) +op_seg(SS, _ss) + +static int op_66(uint32_t fetchdat) /*Data size select*/ +{ + fetchdat = fastreadl(cs + cpu_state.pc); + if (abrt) return 1; + cpu_state.pc++; + + op32 = ((use32 & 0x100) ^ 0x100) | (op32 & 0x200); + CLOCK_CYCLES(2); + return x86_opcodes[(fetchdat & 0xff) | op32](fetchdat >> 8); +} +static int op_67(uint32_t fetchdat) /*Address size select*/ +{ + fetchdat = fastreadl(cs + cpu_state.pc); + if (abrt) return 1; + cpu_state.pc++; + + op32 = ((use32 & 0x200) ^ 0x200) | (op32 & 0x100); + CLOCK_CYCLES(2); + return x86_opcodes[(fetchdat & 0xff) | op32](fetchdat >> 8); +} diff --git a/src/x86_ops_rep.h b/src/x86_ops_rep.h new file mode 100644 index 000000000..4c94cd428 --- /dev/null +++ b/src/x86_ops_rep.h @@ -0,0 +1,9 @@ +static int opREPNE(uint32_t fetchdat) +{ + return rep386(0); +} +static int opREPE(uint32_t fetchdat) +{ + return rep386(1); +} + diff --git a/src/x86_ops_ret.h b/src/x86_ops_ret.h new file mode 100644 index 000000000..384491fe2 --- /dev/null +++ b/src/x86_ops_ret.h @@ -0,0 +1,194 @@ +#define RETF_a16(stack_offset) \ + if ((msw&1) && !(eflags&VM_FLAG)) \ + { \ + pmoderetf(0, stack_offset); \ + return 1; \ + } \ + oxpc = cpu_state.pc; \ + if (stack32) \ + { \ + cpu_state.pc = readmemw(ss, ESP); \ + loadcs(readmemw(ss, ESP + 2)); \ + } \ + else \ + { \ + cpu_state.pc = readmemw(ss, SP); \ + loadcs(readmemw(ss, SP + 2)); \ + } \ + if (abrt) return 1; \ + if (stack32) ESP += 4 + stack_offset; \ + else SP += 4 + stack_offset; \ + cycles -= timing_retf_rm; + +#define RETF_a32(stack_offset) \ + if ((msw&1) && !(eflags&VM_FLAG)) \ + { \ + pmoderetf(1, stack_offset); \ + return 1; \ + } \ + oxpc = cpu_state.pc; \ + if (stack32) \ + { \ + cpu_state.pc = readmeml(ss, ESP); \ + loadcs(readmeml(ss, ESP + 4) & 0xffff); \ + } \ + else \ + { \ + cpu_state.pc = readmeml(ss, SP); \ + loadcs(readmeml(ss, SP + 4) & 0xffff); \ + } \ + if (abrt) return 1; \ + if (stack32) ESP += 8 + stack_offset; \ + else SP += 8 + stack_offset; \ + cycles -= timing_retf_rm; + +static int opRETF_a16(uint32_t fetchdat) +{ + CPU_BLOCK_END(); + RETF_a16(0); + return 0; +} +static int opRETF_a32(uint32_t fetchdat) +{ + CPU_BLOCK_END(); + RETF_a32(0); + return 0; +} + +static int opRETF_a16_imm(uint32_t fetchdat) +{ + uint16_t offset = getwordf(); + CPU_BLOCK_END(); + RETF_a16(offset); + return 0; +} +static int opRETF_a32_imm(uint32_t fetchdat) +{ + uint16_t offset = getwordf(); + CPU_BLOCK_END(); + RETF_a32(offset); + return 0; +} + +static int opIRET_286(uint32_t fetchdat) +{ + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + if (msw&1) + { + optype = IRET; + pmodeiret(0); + optype = 0; + } + else + { + uint16_t new_cs; + oxpc = cpu_state.pc; + if (stack32) + { + cpu_state.pc = readmemw(ss, ESP); + new_cs = readmemw(ss, ESP + 2); + flags = (flags & 0x7000) | (readmemw(ss, ESP + 4) & 0xffd5) | 2; + ESP += 6; + } + else + { + cpu_state.pc = readmemw(ss, SP); + new_cs = readmemw(ss, ((SP + 2) & 0xffff)); + flags = (flags & 0x7000) | (readmemw(ss, ((SP + 4) & 0xffff)) & 0x0fd5) | 2; + SP += 6; + } + loadcs(new_cs); + cycles -= timing_iret_rm; + } + flags_extract(); + nmi_enable = 1; + CPU_BLOCK_END(); + return abrt; +} + +static int opIRET(uint32_t fetchdat) +{ + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + if (msw&1) + { + optype = IRET; + pmodeiret(0); + optype = 0; + } + else + { + uint16_t new_cs; + oxpc = cpu_state.pc; + if (stack32) + { + cpu_state.pc = readmemw(ss, ESP); + new_cs = readmemw(ss, ESP + 2); + flags = (readmemw(ss, ESP + 4) & 0xffd5) | 2; + ESP += 6; + } + else + { + cpu_state.pc = readmemw(ss, SP); + new_cs = readmemw(ss, ((SP + 2) & 0xffff)); + flags = (readmemw(ss, ((SP + 4) & 0xffff)) & 0xffd5) | 2; + SP += 6; + } + loadcs(new_cs); + cycles -= timing_iret_rm; + } + flags_extract(); + nmi_enable = 1; + CPU_BLOCK_END(); + return abrt; +} + +static int opIRETD(uint32_t fetchdat) +{ + if ((cr0 & 1) && (eflags & VM_FLAG) && (IOPL != 3)) + { + x86gpf(NULL,0); + return 1; + } + if (msw & 1) + { + optype = IRET; + pmodeiret(1); + optype = 0; + } + else + { + uint16_t new_cs; + oxpc = cpu_state.pc; + if (stack32) + { + cpu_state.pc = readmeml(ss, ESP); + new_cs = readmemw(ss, ESP + 4); + flags = (readmemw(ss, ESP + 8) & 0xffd5) | 2; + eflags = readmemw(ss, ESP + 10); + ESP += 12; + } + else + { + cpu_state.pc = readmeml(ss, SP); + new_cs = readmemw(ss, ((SP + 4) & 0xffff)); + flags = (readmemw(ss,(SP + 8) & 0xffff) & 0xffd5) | 2; + eflags = readmemw(ss, (SP + 10) & 0xffff); + SP += 12; + } + loadcs(new_cs); + cycles -= timing_iret_rm; + } + flags_extract(); + nmi_enable = 1; + CPU_BLOCK_END(); + return abrt; +} + diff --git a/src/x86_ops_set.h b/src/x86_ops_set.h new file mode 100644 index 000000000..de39bdefc --- /dev/null +++ b/src/x86_ops_set.h @@ -0,0 +1,33 @@ +#define opSET(condition) \ + static int opSET ## condition ## _a16(uint32_t fetchdat) \ + { \ + fetch_ea_16(fetchdat); \ + seteab((cond_ ## condition) ? 1 : 0); \ + CLOCK_CYCLES(4); \ + return abrt; \ + } \ + \ + static int opSET ## condition ## _a32(uint32_t fetchdat) \ + { \ + fetch_ea_32(fetchdat); \ + seteab((cond_ ## condition) ? 1 : 0); \ + CLOCK_CYCLES(4); \ + return abrt; \ + } + +opSET(O) +opSET(NO) +opSET(B) +opSET(NB) +opSET(E) +opSET(NE) +opSET(BE) +opSET(NBE) +opSET(S) +opSET(NS) +opSET(P) +opSET(NP) +opSET(L) +opSET(NL) +opSET(LE) +opSET(NLE) diff --git a/src/x86_ops_shift.h b/src/x86_ops_shift.h new file mode 100644 index 000000000..955c0aa8b --- /dev/null +++ b/src/x86_ops_shift.h @@ -0,0 +1,571 @@ +#define OP_SHIFT_b(c) \ + { \ + uint8_t temp_orig = temp; \ + if (!c) return 0; \ + flags_rebuild(); \ + switch (rmdat & 0x38) \ + { \ + case 0x00: /*ROL b, c*/ \ + while (c > 0) \ + { \ + temp2 = (temp & 0x80) ? 1 : 0; \ + temp = (temp << 1) | temp2; \ + c--; \ + } \ + seteab(temp); if (abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((flags & C_FLAG) ^ (temp >> 7)) flags |= V_FLAG; \ + CLOCK_CYCLES((mod == 3) ? 3 : 7); \ + break; \ + case 0x08: /*ROR b,CL*/ \ + while (c > 0) \ + { \ + temp2 = temp & 1; \ + temp >>= 1; \ + if (temp2) temp |= 0x80; \ + c--; \ + } \ + seteab(temp); if (abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x40) flags |= V_FLAG; \ + CLOCK_CYCLES((mod == 3) ? 3 : 7); \ + break; \ + case 0x10: /*RCL b,CL*/ \ + temp2 = flags & C_FLAG; \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 1 : 0; \ + temp2 = temp & 0x80; \ + temp = (temp << 1) | tempc; \ + c--; \ + } \ + seteab(temp); if (abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((flags & C_FLAG) ^ (temp >> 7)) flags |= V_FLAG; \ + CLOCK_CYCLES((mod == 3) ? 9 : 10); \ + break; \ + case 0x18: /*RCR b,CL*/ \ + temp2 = flags & C_FLAG; \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 0x80 : 0; \ + temp2 = temp & 1; \ + temp = (temp >> 1) | tempc; \ + c--; \ + } \ + seteab(temp); if (abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x40) flags |= V_FLAG; \ + CLOCK_CYCLES((mod == 3) ? 9 : 10); \ + break; \ + case 0x20: case 0x30: /*SHL b,CL*/ \ + seteab(temp << c); if (abrt) return 1; \ + set_flags_shift(FLAGS_SHL8, temp_orig, c, (temp << c) & 0xff); \ + CLOCK_CYCLES((mod == 3) ? 3 : 7); \ + break; \ + case 0x28: /*SHR b,CL*/ \ + seteab(temp >> c); if (abrt) return 1; \ + set_flags_shift(FLAGS_SHR8, temp_orig, c, temp >> c); \ + CLOCK_CYCLES((mod == 3) ? 3 : 7); \ + break; \ + case 0x38: /*SAR b,CL*/ \ + temp = (int8_t)temp >> c; \ + seteab(temp); if (abrt) return 1; \ + set_flags_shift(FLAGS_SAR8, temp_orig, c, temp); \ + CLOCK_CYCLES((mod == 3) ? 3 : 7); \ + break; \ + } \ + } + +#define OP_SHIFT_w(c) \ + { \ + uint16_t temp_orig = temp; \ + if (!c) return 0; \ + flags_rebuild(); \ + switch (rmdat & 0x38) \ + { \ + case 0x00: /*ROL w, c*/ \ + while (c > 0) \ + { \ + temp2 = (temp & 0x8000) ? 1 : 0; \ + temp = (temp << 1) | temp2; \ + c--; \ + } \ + seteaw(temp); if (abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((flags & C_FLAG) ^ (temp >> 15)) flags |= V_FLAG; \ + CLOCK_CYCLES((mod == 3) ? 3 : 7); \ + break; \ + case 0x08: /*ROR w, c*/ \ + while (c > 0) \ + { \ + temp2 = temp & 1; \ + temp >>= 1; \ + if (temp2) temp |= 0x8000; \ + c--; \ + } \ + seteaw(temp); if (abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x4000) flags |= V_FLAG; \ + CLOCK_CYCLES((mod == 3) ? 3 : 7); \ + break; \ + case 0x10: /*RCL w, c*/ \ + temp2 = flags & C_FLAG; \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 1 : 0; \ + temp2 = temp & 0x8000; \ + temp = (temp << 1) | tempc; \ + c--; \ + } \ + seteaw(temp); if (abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((flags & C_FLAG) ^ (temp >> 15)) flags |= V_FLAG; \ + CLOCK_CYCLES((mod == 3) ? 9 : 10); \ + break; \ + case 0x18: /*RCR w, c*/ \ + temp2 = flags & C_FLAG; \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 0x8000 : 0; \ + temp2 = temp & 1; \ + temp = (temp >> 1) | tempc; \ + c--; \ + } \ + seteaw(temp); if (abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x4000) flags |= V_FLAG; \ + CLOCK_CYCLES((mod == 3) ? 9 : 10); \ + break; \ + case 0x20: case 0x30: /*SHL w, c*/ \ + seteaw(temp << c); if (abrt) return 1; \ + set_flags_shift(FLAGS_SHL16, temp_orig, c, (temp << c) & 0xffff); \ + CLOCK_CYCLES((mod == 3) ? 3 : 7); \ + break; \ + case 0x28: /*SHR w, c*/ \ + seteaw(temp >> c); if (abrt) return 1; \ + set_flags_shift(FLAGS_SHR16, temp_orig, c, temp >> c); \ + CLOCK_CYCLES((mod == 3) ? 3 : 7); \ + break; \ + case 0x38: /*SAR w, c*/ \ + temp = (int16_t)temp >> c; \ + seteaw(temp); if (abrt) return 1; \ + set_flags_shift(FLAGS_SAR16, temp_orig, c, temp); \ + CLOCK_CYCLES((mod == 3) ? 3 : 7); \ + break; \ + } \ + } + +#define OP_SHIFT_l(c) \ + { \ + uint32_t temp_orig = temp; \ + if (!c) return 0; \ + flags_rebuild(); \ + switch (rmdat & 0x38) \ + { \ + case 0x00: /*ROL l, c*/ \ + while (c > 0) \ + { \ + temp2 = (temp & 0x80000000) ? 1 : 0; \ + temp = (temp << 1) | temp2; \ + c--; \ + } \ + seteal(temp); if (abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((flags & C_FLAG) ^ (temp >> 31)) flags |= V_FLAG; \ + CLOCK_CYCLES((mod == 3) ? 3 : 7); \ + break; \ + case 0x08: /*ROR l, c*/ \ + while (c > 0) \ + { \ + temp2 = temp & 1; \ + temp >>= 1; \ + if (temp2) temp |= 0x80000000; \ + c--; \ + } \ + seteal(temp); if (abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x40000000) flags |= V_FLAG; \ + CLOCK_CYCLES((mod == 3) ? 3 : 7); \ + break; \ + case 0x10: /*RCL l, c*/ \ + temp2 = CF_SET(); \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 1 : 0; \ + temp2 = temp & 0x80000000; \ + temp = (temp << 1) | tempc; \ + c--; \ + } \ + seteal(temp); if (abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((flags & C_FLAG) ^ (temp >> 31)) flags |= V_FLAG; \ + CLOCK_CYCLES((mod == 3) ? 9 : 10); \ + break; \ + case 0x18: /*RCR l, c*/ \ + temp2 = flags & C_FLAG; \ + if (is486) CLOCK_CYCLES_ALWAYS(c); \ + while (c > 0) \ + { \ + tempc = temp2 ? 0x80000000 : 0; \ + temp2 = temp & 1; \ + temp = (temp >> 1) | tempc; \ + c--; \ + } \ + seteal(temp); if (abrt) return 1; \ + flags &= ~(C_FLAG | V_FLAG); \ + if (temp2) flags |= C_FLAG; \ + if ((temp ^ (temp >> 1)) & 0x40000000) flags |= V_FLAG; \ + CLOCK_CYCLES((mod == 3) ? 9 : 10); \ + break; \ + case 0x20: case 0x30: /*SHL l, c*/ \ + seteal(temp << c); if (abrt) return 1; \ + set_flags_shift(FLAGS_SHL32, temp_orig, c, temp << c); \ + CLOCK_CYCLES((mod == 3) ? 3 : 7); \ + break; \ + case 0x28: /*SHR l, c*/ \ + seteal(temp >> c); if (abrt) return 1; \ + set_flags_shift(FLAGS_SHR32, temp_orig, c, temp >> c); \ + CLOCK_CYCLES((mod == 3) ? 3 : 7); \ + break; \ + case 0x38: /*SAR l, c*/ \ + temp = (int32_t)temp >> c; \ + seteal(temp); if (abrt) return 1; \ + set_flags_shift(FLAGS_SAR32, temp_orig, c, temp); \ + CLOCK_CYCLES((mod == 3) ? 3 : 7); \ + break; \ + } \ + } + +static int opC0_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint8_t temp, temp2; + + fetch_ea_16(fetchdat); + c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; + temp = geteab(); if (abrt) return 1; + OP_SHIFT_b(c); + return 0; +} +static int opC0_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint8_t temp, temp2; + + fetch_ea_32(fetchdat); + c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; + temp = geteab(); if (abrt) return 1; + OP_SHIFT_b(c); + return 0; +} +static int opC1_w_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint16_t temp, temp2; + + fetch_ea_16(fetchdat); + c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; + temp = geteaw(); if (abrt) return 1; + OP_SHIFT_w(c); + return 0; +} +static int opC1_w_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint16_t temp, temp2; + + fetch_ea_32(fetchdat); + c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; + temp = geteaw(); if (abrt) return 1; + OP_SHIFT_w(c); + return 0; +} +static int opC1_l_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint32_t temp, temp2; + + fetch_ea_16(fetchdat); + c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; + temp = geteal(); if (abrt) return 1; + OP_SHIFT_l(c); + return 0; +} +static int opC1_l_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint32_t temp, temp2; + + fetch_ea_32(fetchdat); + c = readmemb(cs, cpu_state.pc) & 31; cpu_state.pc++; + temp = geteal(); if (abrt) return 1; + OP_SHIFT_l(c); + return 0; +} + +static int opD0_a16(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint8_t temp, temp2; + + fetch_ea_16(fetchdat); + temp = geteab(); if (abrt) return 1; + OP_SHIFT_b(c); + return 0; +} +static int opD0_a32(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint8_t temp, temp2; + + fetch_ea_32(fetchdat); + temp = geteab(); if (abrt) return 1; + OP_SHIFT_b(c); + return 0; +} +static int opD1_w_a16(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint16_t temp, temp2; + + fetch_ea_16(fetchdat); + temp = geteaw(); if (abrt) return 1; + OP_SHIFT_w(c); + return 0; +} +static int opD1_w_a32(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint16_t temp, temp2; + + fetch_ea_32(fetchdat); + temp = geteaw(); if (abrt) return 1; + OP_SHIFT_w(c); + return 0; +} +static int opD1_l_a16(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint32_t temp, temp2; + + fetch_ea_16(fetchdat); + temp = geteal(); if (abrt) return 1; + OP_SHIFT_l(c); + return 0; +} +static int opD1_l_a32(uint32_t fetchdat) +{ + int c = 1; + int tempc; + uint32_t temp, temp2; + + fetch_ea_32(fetchdat); + temp = geteal(); if (abrt) return 1; + OP_SHIFT_l(c); + return 0; +} + +static int opD2_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint8_t temp, temp2; + + fetch_ea_16(fetchdat); + c = CL & 31; + temp = geteab(); if (abrt) return 1; + OP_SHIFT_b(c); + return 0; +} +static int opD2_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint8_t temp, temp2; + + fetch_ea_32(fetchdat); + c = CL & 31; + temp = geteab(); if (abrt) return 1; + OP_SHIFT_b(c); + return 0; +} +static int opD3_w_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint16_t temp, temp2; + + fetch_ea_16(fetchdat); + c = CL & 31; + temp = geteaw(); if (abrt) return 1; + OP_SHIFT_w(c); + return 0; +} +static int opD3_w_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint16_t temp, temp2; + + fetch_ea_32(fetchdat); + c = CL & 31; + temp = geteaw(); if (abrt) return 1; + OP_SHIFT_w(c); + return 0; +} +static int opD3_l_a16(uint32_t fetchdat) +{ + int c; + int tempc; + uint32_t temp, temp2; + + fetch_ea_16(fetchdat); + c = CL & 31; + temp = geteal(); if (abrt) return 1; + OP_SHIFT_l(c); + return 0; +} +static int opD3_l_a32(uint32_t fetchdat) +{ + int c; + int tempc; + uint32_t temp, temp2; + + fetch_ea_32(fetchdat); + c = CL & 31; + temp = geteal(); if (abrt) return 1; + OP_SHIFT_l(c); + return 0; +} + + +#define SHLD_w() \ + if (count) \ + { \ + uint16_t tempw = geteaw(); if (abrt) return 1; \ + int tempc = ((tempw << (count - 1)) & (1 << 15)) ? 1 : 0; \ + uint32_t templ = (tempw << 16) | cpu_state.regs[reg].w; \ + if (count <= 16) tempw = templ >> (16 - count); \ + else tempw = (templ << count) >> 16; \ + seteaw(tempw); if (abrt) return 1; \ + setznp16(tempw); \ + flags_rebuild(); \ + if (tempc) flags |= C_FLAG; \ + } + +#define SHLD_l() \ + if (count) \ + { \ + uint32_t templ = geteal(); if (abrt) return 1; \ + int tempc = ((templ << (count - 1)) & (1 << 31)) ? 1 : 0; \ + templ = (templ << count) | (cpu_state.regs[reg].l >> (32 - count)); \ + seteal(templ); if (abrt) return 1; \ + setznp32(templ); \ + flags_rebuild(); \ + if (tempc) flags |= C_FLAG; \ + } + + +#define SHRD_w() \ + if (count) \ + { \ + uint16_t tempw = geteaw(); if (abrt) return 1; \ + int tempc = (tempw >> (count - 1)) & 1; \ + uint32_t templ = tempw | (cpu_state.regs[reg].w << 16); \ + tempw = templ >> count; \ + seteaw(tempw); if (abrt) return 1; \ + setznp16(tempw); \ + flags_rebuild(); \ + if (tempc) flags |= C_FLAG; \ + } + +#define SHRD_l() \ + if (count) \ + { \ + uint32_t templ = geteal(); if (abrt) return 1; \ + int tempc = (templ >> (count - 1)) & 1; \ + templ = (templ >> count) | (cpu_state.regs[reg].l << (32 - count)); \ + seteal(templ); if (abrt) return 1; \ + setznp32(templ); \ + flags_rebuild(); \ + if (tempc) flags |= C_FLAG; \ + } + +#define opSHxD(operation) \ + static int op ## operation ## _i_a16(uint32_t fetchdat) \ + { \ + int count; \ + \ + fetch_ea_16(fetchdat); \ + count = getbyte() & 31; \ + operation(); \ + \ + CLOCK_CYCLES(3); \ + return 0; \ + } \ + static int op ## operation ## _CL_a16(uint32_t fetchdat) \ + { \ + int count; \ + \ + fetch_ea_16(fetchdat); \ + count = CL & 31; \ + operation(); \ + \ + CLOCK_CYCLES(3); \ + return 0; \ + } \ + static int op ## operation ## _i_a32(uint32_t fetchdat) \ + { \ + int count; \ + \ + fetch_ea_32(fetchdat); \ + count = getbyte() & 31; \ + operation(); \ + \ + CLOCK_CYCLES(3); \ + return 0; \ + } \ + static int op ## operation ## _CL_a32(uint32_t fetchdat) \ + { \ + int count; \ + \ + fetch_ea_32(fetchdat); \ + count = CL & 31; \ + operation(); \ + \ + CLOCK_CYCLES(3); \ + return 0; \ + } + +opSHxD(SHLD_w) +opSHxD(SHLD_l) +opSHxD(SHRD_w) +opSHxD(SHRD_l) diff --git a/src/x86_ops_stack.h b/src/x86_ops_stack.h new file mode 100644 index 000000000..5b6565f47 --- /dev/null +++ b/src/x86_ops_stack.h @@ -0,0 +1,476 @@ +#define PUSH_W_OP(reg) \ + static int opPUSH_ ## reg (uint32_t fetchdat) \ + { \ + PUSH_W(reg); \ + CLOCK_CYCLES((is486) ? 1 : 2); \ + return abrt; \ + } + +#define PUSH_L_OP(reg) \ + static int opPUSH_ ## reg (uint32_t fetchdat) \ + { \ + PUSH_L(reg); \ + CLOCK_CYCLES((is486) ? 1 : 2); \ + return abrt; \ + } + +#define POP_W_OP(reg) \ + static int opPOP_ ## reg (uint32_t fetchdat) \ + { \ + reg = POP_W(); \ + CLOCK_CYCLES((is486) ? 1 : 4); \ + return abrt; \ + } + +#define POP_L_OP(reg) \ + static int opPOP_ ## reg (uint32_t fetchdat) \ + { \ + reg = POP_L(); \ + CLOCK_CYCLES((is486) ? 1 : 4); \ + return abrt; \ + } + +PUSH_W_OP(AX) +PUSH_W_OP(BX) +PUSH_W_OP(CX) +PUSH_W_OP(DX) +PUSH_W_OP(SI) +PUSH_W_OP(DI) +PUSH_W_OP(BP) +PUSH_W_OP(SP) + +PUSH_L_OP(EAX) +PUSH_L_OP(EBX) +PUSH_L_OP(ECX) +PUSH_L_OP(EDX) +PUSH_L_OP(ESI) +PUSH_L_OP(EDI) +PUSH_L_OP(EBP) +PUSH_L_OP(ESP) + +POP_W_OP(AX) +POP_W_OP(BX) +POP_W_OP(CX) +POP_W_OP(DX) +POP_W_OP(SI) +POP_W_OP(DI) +POP_W_OP(BP) +POP_W_OP(SP) + +POP_L_OP(EAX) +POP_L_OP(EBX) +POP_L_OP(ECX) +POP_L_OP(EDX) +POP_L_OP(ESI) +POP_L_OP(EDI) +POP_L_OP(EBP) +POP_L_OP(ESP) + + +static int opPUSHA_w(uint32_t fetchdat) +{ + if (stack32) + { + writememw(ss, ESP - 2, AX); + writememw(ss, ESP - 4, CX); + writememw(ss, ESP - 6, DX); + writememw(ss, ESP - 8, BX); + writememw(ss, ESP - 10, SP); + writememw(ss, ESP - 12, BP); + writememw(ss, ESP - 14, SI); + writememw(ss, ESP - 16, DI); + if (!abrt) ESP -= 16; + } + else + { + writememw(ss, ((SP - 2) & 0xFFFF), AX); + writememw(ss, ((SP - 4) & 0xFFFF), CX); + writememw(ss, ((SP - 6) & 0xFFFF), DX); + writememw(ss, ((SP - 8) & 0xFFFF), BX); + writememw(ss, ((SP - 10) & 0xFFFF), SP); + writememw(ss, ((SP - 12) & 0xFFFF), BP); + writememw(ss, ((SP - 14) & 0xFFFF), SI); + writememw(ss, ((SP - 16) & 0xFFFF), DI); + if (!abrt) SP -= 16; + } + CLOCK_CYCLES((is486) ? 11 : 18); + return abrt; +} +static int opPUSHA_l(uint32_t fetchdat) +{ + if (stack32) + { + writememl(ss, ESP - 4, EAX); + writememl(ss, ESP - 8, ECX); + writememl(ss, ESP - 12, EDX); + writememl(ss, ESP - 16, EBX); + writememl(ss, ESP - 20, ESP); + writememl(ss, ESP - 24, EBP); + writememl(ss, ESP - 28, ESI); + writememl(ss, ESP - 32, EDI); + if (!abrt) ESP -= 32; + } + else + { + writememl(ss, ((SP - 4) & 0xFFFF), EAX); + writememl(ss, ((SP - 8) & 0xFFFF), ECX); + writememl(ss, ((SP - 12) & 0xFFFF), EDX); + writememl(ss, ((SP - 16) & 0xFFFF), EBX); + writememl(ss, ((SP - 20) & 0xFFFF), ESP); + writememl(ss, ((SP - 24) & 0xFFFF), EBP); + writememl(ss, ((SP - 28) & 0xFFFF), ESI); + writememl(ss, ((SP - 32) & 0xFFFF), EDI); + if (!abrt) SP -= 32; + } + CLOCK_CYCLES((is486) ? 11 : 18); + return abrt; +} + +static int opPOPA_w(uint32_t fetchdat) +{ + if (stack32) + { + DI = readmemw(ss, ESP); if (abrt) return 1; + SI = readmemw(ss, ESP + 2); if (abrt) return 1; + BP = readmemw(ss, ESP + 4); if (abrt) return 1; + BX = readmemw(ss, ESP + 8); if (abrt) return 1; + DX = readmemw(ss, ESP + 10); if (abrt) return 1; + CX = readmemw(ss, ESP + 12); if (abrt) return 1; + AX = readmemw(ss, ESP + 14); if (abrt) return 1; + ESP += 16; + } + else + { + DI = readmemw(ss, ((SP) & 0xFFFF)); if (abrt) return 1; + SI = readmemw(ss, ((SP + 2) & 0xFFFF)); if (abrt) return 1; + BP = readmemw(ss, ((SP + 4) & 0xFFFF)); if (abrt) return 1; + BX = readmemw(ss, ((SP + 8) & 0xFFFF)); if (abrt) return 1; + DX = readmemw(ss, ((SP + 10) & 0xFFFF)); if (abrt) return 1; + CX = readmemw(ss, ((SP + 12) & 0xFFFF)); if (abrt) return 1; + AX = readmemw(ss, ((SP + 14) & 0xFFFF)); if (abrt) return 1; + SP += 16; + } + CLOCK_CYCLES((is486) ? 9 : 24); + return 0; +} +static int opPOPA_l(uint32_t fetchdat) +{ + if (stack32) + { + EDI = readmeml(ss, ESP); if (abrt) return 1; + ESI = readmeml(ss, ESP + 4); if (abrt) return 1; + EBP = readmeml(ss, ESP + 8); if (abrt) return 1; + EBX = readmeml(ss, ESP + 16); if (abrt) return 1; + EDX = readmeml(ss, ESP + 20); if (abrt) return 1; + ECX = readmeml(ss, ESP + 24); if (abrt) return 1; + EAX = readmeml(ss, ESP + 28); if (abrt) return 1; + ESP += 32; + } + else + { + EDI = readmeml(ss, ((SP) & 0xFFFF)); if (abrt) return 1; + ESI = readmeml(ss, ((SP + 4) & 0xFFFF)); if (abrt) return 1; + EBP = readmeml(ss, ((SP + 8) & 0xFFFF)); if (abrt) return 1; + EBX = readmeml(ss, ((SP + 16) & 0xFFFF)); if (abrt) return 1; + EDX = readmeml(ss, ((SP + 20) & 0xFFFF)); if (abrt) return 1; + ECX = readmeml(ss, ((SP + 24) & 0xFFFF)); if (abrt) return 1; + EAX = readmeml(ss, ((SP + 28) & 0xFFFF)); if (abrt) return 1; + SP += 32; + } + CLOCK_CYCLES((is486) ? 9 : 24); + return 0; +} + +static int opPUSH_imm_w(uint32_t fetchdat) +{ + uint16_t val = getwordf(); + PUSH_W(val); + CLOCK_CYCLES(2); + return abrt; +} +static int opPUSH_imm_l(uint32_t fetchdat) +{ + uint32_t val = getlong(); if (abrt) return 1; + PUSH_L(val); + CLOCK_CYCLES(2); + return abrt; +} + +static int opPUSH_imm_bw(uint32_t fetchdat) +{ + uint16_t tempw = getbytef(); + + if (tempw & 0x80) tempw |= 0xFF00; + PUSH_W(tempw); + + CLOCK_CYCLES(2); + return abrt; +} +static int opPUSH_imm_bl(uint32_t fetchdat) +{ + uint32_t templ = getbytef(); + + if (templ & 0x80) templ |= 0xFFFFFF00; + PUSH_L(templ); + + CLOCK_CYCLES(2); + return abrt; +} + +static int opPOPW_a16(uint32_t fetchdat) +{ + uint16_t temp; + + temp = POP_W(); if (abrt) return 1; + + fetch_ea_16(fetchdat); + seteaw(temp); + if (abrt) + { + if (stack32) ESP -= 2; + else SP -= 2; + } + + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 6); + else CLOCK_CYCLES((mod == 3) ? 4 : 5); + return abrt; +} +static int opPOPW_a32(uint32_t fetchdat) +{ + uint16_t temp; + + temp = POP_W(); if (abrt) return 1; + + fetch_ea_32(fetchdat); + seteaw(temp); + if (abrt) + { + if (stack32) ESP -= 2; + else SP -= 2; + } + + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 6); + else CLOCK_CYCLES((mod == 3) ? 4 : 5); + return abrt; +} + +static int opPOPL_a16(uint32_t fetchdat) +{ + uint32_t temp; + + temp = POP_L(); if (abrt) return 1; + + fetch_ea_16(fetchdat); + seteal(temp); + if (abrt) + { + if (stack32) ESP -= 4; + else SP -= 4; + } + + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 6); + else CLOCK_CYCLES((mod == 3) ? 4 : 5); + return abrt; +} +static int opPOPL_a32(uint32_t fetchdat) +{ + uint32_t temp; + + temp = POP_L(); if (abrt) return 1; + + fetch_ea_32(fetchdat); + seteal(temp); + if (abrt) + { + if (stack32) ESP -= 4; + else SP -= 4; + } + + if (is486) CLOCK_CYCLES((mod == 3) ? 1 : 6); + else CLOCK_CYCLES((mod == 3) ? 4 : 5); + return abrt; +} + + +static int opENTER_w(uint32_t fetchdat) +{ + uint16_t offset = getwordf(); + int count = (fetchdat >> 16) & 0xff; cpu_state.pc++; + uint32_t tempEBP = EBP, tempESP = ESP, frame_ptr; + + PUSH_W(BP); if (abrt) return 1; + frame_ptr = ESP; + + if (count > 0) + { + while (--count) + { + uint16_t tempw; + + BP -= 2; + tempw = readmemw(ss, BP); + if (abrt) { ESP = tempESP; EBP = tempEBP; return 1; } + PUSH_W(tempw); + if (abrt) { ESP = tempESP; EBP = tempEBP; return 1; } + CLOCK_CYCLES((is486) ? 3 : 4); + } + PUSH_W(frame_ptr); + if (abrt) { ESP = tempESP; EBP = tempEBP; return 1; } + CLOCK_CYCLES((is486) ? 3 : 5); + } + BP = frame_ptr; + + if (stack32) ESP -= offset; + else SP -= offset; + CLOCK_CYCLES((is486) ? 14 : 10); + return 0; +} +static int opENTER_l(uint32_t fetchdat) +{ + uint16_t offset = getwordf(); + int count = (fetchdat >> 16) & 0xff; cpu_state.pc++; + uint32_t tempEBP = EBP, tempESP = ESP, frame_ptr; + + PUSH_L(EBP); if (abrt) return 1; + frame_ptr = ESP; + + if (count > 0) + { + while (--count) + { + uint32_t templ; + + EBP -= 4; + templ = readmeml(ss, EBP); + if (abrt) { ESP = tempESP; EBP = tempEBP; return 1; } + PUSH_L(templ); + if (abrt) { ESP = tempESP; EBP = tempEBP; return 1; } + CLOCK_CYCLES((is486) ? 3 : 4); + } + PUSH_L(frame_ptr); + if (abrt) { ESP = tempESP; EBP = tempEBP; return 1; } + CLOCK_CYCLES((is486) ? 3 : 5); + } + EBP = frame_ptr; + + if (stack32) ESP -= offset; + else SP -= offset; + CLOCK_CYCLES((is486) ? 14 : 10); + return 0; +} + + +static int opLEAVE_w(uint32_t fetchdat) +{ + uint32_t tempESP = ESP; + uint16_t temp; + + SP = BP; + temp = POP_W(); + if (abrt) { ESP = tempESP; return 1; } + BP = temp; + + CLOCK_CYCLES(4); + return 0; +} +static int opLEAVE_l(uint32_t fetchdat) +{ + uint32_t tempESP = ESP; + uint32_t temp; + + ESP = EBP; + temp = POP_L(); + if (abrt) { ESP = tempESP; return 1; } + EBP = temp; + + CLOCK_CYCLES(4); + return 0; +} + + +#define PUSH_SEG_OPS(seg) \ + static int opPUSH_ ## seg ## _w(uint32_t fetchdat) \ + { \ + PUSH_W(seg); \ + CLOCK_CYCLES(2); \ + return abrt; \ + } \ + static int opPUSH_ ## seg ## _l(uint32_t fetchdat) \ + { \ + PUSH_L(seg); \ + CLOCK_CYCLES(2); \ + return abrt; \ + } + +#define POP_SEG_OPS(seg, realseg) \ + static int opPOP_ ## seg ## _w(uint32_t fetchdat) \ + { \ + uint16_t temp_seg; \ + uint32_t temp_esp = ESP; \ + temp_seg = POP_W(); if (abrt) return 1; \ + loadseg(temp_seg, realseg); if (abrt) ESP = temp_esp; \ + CLOCK_CYCLES(is486 ? 3 : 7); \ + return abrt; \ + } \ + static int opPOP_ ## seg ## _l(uint32_t fetchdat) \ + { \ + uint32_t temp_seg; \ + uint32_t temp_esp = ESP; \ + temp_seg = POP_L(); if (abrt) return 1; \ + loadseg(temp_seg & 0xffff, realseg); if (abrt) ESP = temp_esp; \ + CLOCK_CYCLES(is486 ? 3 : 7); \ + return abrt; \ + } + + +PUSH_SEG_OPS(CS); +PUSH_SEG_OPS(DS); +PUSH_SEG_OPS(ES); +PUSH_SEG_OPS(FS); +PUSH_SEG_OPS(GS); +PUSH_SEG_OPS(SS); + +POP_SEG_OPS(DS, &_ds); +POP_SEG_OPS(ES, &_es); +POP_SEG_OPS(FS, &_fs); +POP_SEG_OPS(GS, &_gs); + + +static int opPOP_SS_w(uint32_t fetchdat) +{ + uint16_t temp_seg; + uint32_t temp_esp = ESP; + temp_seg = POP_W(); if (abrt) return 1; + loadseg(temp_seg, &_ss); if (abrt) { ESP = temp_esp; return 1; } + CLOCK_CYCLES(is486 ? 3 : 7); + + oldpc = cpu_state.pc; + op32 = use32; + ssegs = 0; + ea_seg = &_ds; + fetchdat = fastreadl(cs + cpu_state.pc); + cpu_state.pc++; + if (abrt) return 1; + x86_opcodes[(fetchdat & 0xff) | op32](fetchdat >> 8); + + return 1; +} +static int opPOP_SS_l(uint32_t fetchdat) +{ + uint32_t temp_seg; + uint32_t temp_esp = ESP; + temp_seg = POP_L(); if (abrt) return 1; + loadseg(temp_seg & 0xffff, &_ss); if (abrt) { ESP = temp_esp; return 1; } + CLOCK_CYCLES(is486 ? 3 : 7); + + oldpc = cpu_state.pc; + op32 = use32; + ssegs = 0; + ea_seg = &_ds; + fetchdat = fastreadl(cs + cpu_state.pc); + cpu_state.pc++; + if (abrt) return 1; + x86_opcodes[(fetchdat & 0xff) | op32](fetchdat >> 8); + + return 1; +} diff --git a/src/x86_ops_string.h b/src/x86_ops_string.h new file mode 100644 index 000000000..010fd37b9 --- /dev/null +++ b/src/x86_ops_string.h @@ -0,0 +1,435 @@ +static int opMOVSB_a16(uint32_t fetchdat) +{ + uint8_t temp = readmemb(ea_seg->base, SI); if (abrt) return 1; + writememb(es, DI, temp); if (abrt) return 1; + if (flags & D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + CLOCK_CYCLES(7); + return 0; +} +static int opMOVSB_a32(uint32_t fetchdat) +{ + uint8_t temp = readmemb(ea_seg->base, ESI); if (abrt) return 1; + writememb(es, EDI, temp); if (abrt) return 1; + if (flags & D_FLAG) { EDI--; ESI--; } + else { EDI++; ESI++; } + CLOCK_CYCLES(7); + return 0; +} + +static int opMOVSW_a16(uint32_t fetchdat) +{ + uint16_t temp = readmemw(ea_seg->base, SI); if (abrt) return 1; + writememw(es, DI, temp); if (abrt) return 1; + if (flags & D_FLAG) { DI -= 2; SI -= 2; } + else { DI += 2; SI += 2; } + CLOCK_CYCLES(7); + return 0; +} +static int opMOVSW_a32(uint32_t fetchdat) +{ + uint16_t temp = readmemw(ea_seg->base, ESI); if (abrt) return 1; + writememw(es, EDI, temp); if (abrt) return 1; + if (flags & D_FLAG) { EDI -= 2; ESI -= 2; } + else { EDI += 2; ESI += 2; } + CLOCK_CYCLES(7); + return 0; +} + +static int opMOVSL_a16(uint32_t fetchdat) +{ + uint32_t temp = readmeml(ea_seg->base, SI); if (abrt) return 1; + writememl(es, DI, temp); if (abrt) return 1; + if (flags & D_FLAG) { DI -= 4; SI -= 4; } + else { DI += 4; SI += 4; } + CLOCK_CYCLES(7); + return 0; +} +static int opMOVSL_a32(uint32_t fetchdat) +{ + uint32_t temp = readmeml(ea_seg->base, ESI); if (abrt) return 1; + writememl(es, EDI, temp); if (abrt) return 1; + if (flags & D_FLAG) { EDI -= 4; ESI -= 4; } + else { EDI += 4; ESI += 4; } + CLOCK_CYCLES(7); + return 0; +} + + +static int opCMPSB_a16(uint32_t fetchdat) +{ + uint8_t src = readmemb(ea_seg->base, SI); + uint8_t dst = readmemb(es, DI); if (abrt) return 1; + setsub8(src, dst); + if (flags & D_FLAG) { DI--; SI--; } + else { DI++; SI++; } + CLOCK_CYCLES((is486) ? 8 : 10); + return 0; +} +static int opCMPSB_a32(uint32_t fetchdat) +{ + uint8_t src = readmemb(ea_seg->base, ESI); + uint8_t dst = readmemb(es, EDI); if (abrt) return 1; + setsub8(src, dst); + if (flags & D_FLAG) { EDI--; ESI--; } + else { EDI++; ESI++; } + CLOCK_CYCLES((is486) ? 8 : 10); + return 0; +} + +static int opCMPSW_a16(uint32_t fetchdat) +{ + uint16_t src = readmemw(ea_seg->base, SI); + uint16_t dst = readmemw(es, DI); if (abrt) return 1; + setsub16(src, dst); + if (flags & D_FLAG) { DI -= 2; SI -= 2; } + else { DI += 2; SI += 2; } + CLOCK_CYCLES((is486) ? 8 : 10); + return 0; +} +static int opCMPSW_a32(uint32_t fetchdat) +{ + uint16_t src = readmemw(ea_seg->base, ESI); + uint16_t dst = readmemw(es, EDI); if (abrt) return 1; + setsub16(src, dst); + if (flags & D_FLAG) { EDI -= 2; ESI -= 2; } + else { EDI += 2; ESI += 2; } + CLOCK_CYCLES((is486) ? 8 : 10); + return 0; +} + +static int opCMPSL_a16(uint32_t fetchdat) +{ + uint32_t src = readmeml(ea_seg->base, SI); + uint32_t dst = readmeml(es, DI); if (abrt) return 1; + setsub32(src, dst); + if (flags & D_FLAG) { DI -= 4; SI -= 4; } + else { DI += 4; SI += 4; } + CLOCK_CYCLES((is486) ? 8 : 10); + return 0; +} +static int opCMPSL_a32(uint32_t fetchdat) +{ + uint32_t src = readmeml(ea_seg->base, ESI); + uint32_t dst = readmeml(es, EDI); if (abrt) return 1; + setsub32(src, dst); + if (flags & D_FLAG) { EDI -= 4; ESI -= 4; } + else { EDI += 4; ESI += 4; } + CLOCK_CYCLES((is486) ? 8 : 10); + return 0; +} + +static int opSTOSB_a16(uint32_t fetchdat) +{ + writememb(es, DI, AL); if (abrt) return 1; + if (flags & D_FLAG) DI--; + else DI++; + CLOCK_CYCLES(4); + return 0; +} +static int opSTOSB_a32(uint32_t fetchdat) +{ + writememb(es, EDI, AL); if (abrt) return 1; + if (flags & D_FLAG) EDI--; + else EDI++; + CLOCK_CYCLES(4); + return 0; +} + +static int opSTOSW_a16(uint32_t fetchdat) +{ + writememw(es, DI, AX); if (abrt) return 1; + if (flags & D_FLAG) DI -= 2; + else DI += 2; + CLOCK_CYCLES(4); + return 0; +} +static int opSTOSW_a32(uint32_t fetchdat) +{ + writememw(es, EDI, AX); if (abrt) return 1; + if (flags & D_FLAG) EDI -= 2; + else EDI += 2; + CLOCK_CYCLES(4); + return 0; +} + +static int opSTOSL_a16(uint32_t fetchdat) +{ + writememl(es, DI, EAX); if (abrt) return 1; + if (flags & D_FLAG) DI -= 4; + else DI += 4; + CLOCK_CYCLES(4); + return 0; +} +static int opSTOSL_a32(uint32_t fetchdat) +{ + writememl(es, EDI, EAX); if (abrt) return 1; + if (flags & D_FLAG) EDI -= 4; + else EDI += 4; + CLOCK_CYCLES(4); + return 0; +} + + +static int opLODSB_a16(uint32_t fetchdat) +{ + uint8_t temp = readmemb(ea_seg->base, SI); if (abrt) return 1; + AL = temp; + if (flags & D_FLAG) SI--; + else SI++; + CLOCK_CYCLES(5); + return 0; +} +static int opLODSB_a32(uint32_t fetchdat) +{ + uint8_t temp = readmemb(ea_seg->base, ESI); if (abrt) return 1; + AL = temp; + if (flags & D_FLAG) ESI--; + else ESI++; + CLOCK_CYCLES(5); + return 0; +} + +static int opLODSW_a16(uint32_t fetchdat) +{ + uint16_t temp = readmemw(ea_seg->base, SI); if (abrt) return 1; + AX = temp; + if (flags & D_FLAG) SI -= 2; + else SI += 2; + CLOCK_CYCLES(5); + return 0; +} +static int opLODSW_a32(uint32_t fetchdat) +{ + uint16_t temp = readmemw(ea_seg->base, ESI); if (abrt) return 1; + AX = temp; + if (flags & D_FLAG) ESI -= 2; + else ESI += 2; + CLOCK_CYCLES(5); + return 0; +} + +static int opLODSL_a16(uint32_t fetchdat) +{ + uint32_t temp = readmeml(ea_seg->base, SI); if (abrt) return 1; + EAX = temp; + if (flags & D_FLAG) SI -= 4; + else SI += 4; + CLOCK_CYCLES(5); + return 0; +} +static int opLODSL_a32(uint32_t fetchdat) +{ + uint32_t temp = readmeml(ea_seg->base, ESI); if (abrt) return 1; + EAX = temp; + if (flags & D_FLAG) ESI -= 4; + else ESI += 4; + CLOCK_CYCLES(5); + return 0; +} + + +static int opSCASB_a16(uint32_t fetchdat) +{ + uint8_t temp = readmemb(es, DI); if (abrt) return 1; + setsub8(AL, temp); + if (flags & D_FLAG) DI--; + else DI++; + CLOCK_CYCLES(7); + return 0; +} +static int opSCASB_a32(uint32_t fetchdat) +{ + uint8_t temp = readmemb(es, EDI); if (abrt) return 1; + setsub8(AL, temp); + if (flags & D_FLAG) EDI--; + else EDI++; + CLOCK_CYCLES(7); + return 0; +} + +static int opSCASW_a16(uint32_t fetchdat) +{ + uint16_t temp = readmemw(es, DI); if (abrt) return 1; + setsub16(AX, temp); + if (flags & D_FLAG) DI -= 2; + else DI += 2; + CLOCK_CYCLES(7); + return 0; +} +static int opSCASW_a32(uint32_t fetchdat) +{ + uint16_t temp = readmemw(es, EDI); if (abrt) return 1; + setsub16(AX, temp); + if (flags & D_FLAG) EDI -= 2; + else EDI += 2; + CLOCK_CYCLES(7); + return 0; +} + +static int opSCASL_a16(uint32_t fetchdat) +{ + uint32_t temp = readmeml(es, DI); if (abrt) return 1; + setsub32(EAX, temp); + if (flags & D_FLAG) DI -= 4; + else DI += 4; + CLOCK_CYCLES(7); + return 0; +} +static int opSCASL_a32(uint32_t fetchdat) +{ + uint32_t temp = readmeml(es, EDI); if (abrt) return 1; + setsub32(EAX, temp); + if (flags & D_FLAG) EDI -= 4; + else EDI += 4; + CLOCK_CYCLES(7); + return 0; +} + +static int opINSB_a16(uint32_t fetchdat) +{ + uint8_t temp; + check_io_perm(DX); + temp = inb(DX); + writememb(es, DI, temp); if (abrt) return 1; + if (flags & D_FLAG) DI--; + else DI++; + CLOCK_CYCLES(15); + return 0; +} +static int opINSB_a32(uint32_t fetchdat) +{ + uint8_t temp; + check_io_perm(DX); + temp = inb(DX); + writememb(es, EDI, temp); if (abrt) return 1; + if (flags & D_FLAG) EDI--; + else EDI++; + CLOCK_CYCLES(15); + return 0; +} + +static int opINSW_a16(uint32_t fetchdat) +{ + uint16_t temp; + check_io_perm(DX); + check_io_perm(DX + 1); + temp = inw(DX); + writememw(es, DI, temp); if (abrt) return 1; + if (flags & D_FLAG) DI -= 2; + else DI += 2; + CLOCK_CYCLES(15); + return 0; +} +static int opINSW_a32(uint32_t fetchdat) +{ + uint16_t temp; + check_io_perm(DX); + check_io_perm(DX + 1); + temp = inw(DX); + writememw(es, EDI, temp); if (abrt) return 1; + if (flags & D_FLAG) EDI -= 2; + else EDI += 2; + CLOCK_CYCLES(15); + return 0; +} + +static int opINSL_a16(uint32_t fetchdat) +{ + uint32_t temp; + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + temp = inl(DX); + writememl(es, DI, temp); if (abrt) return 1; + if (flags & D_FLAG) DI -= 4; + else DI += 4; + CLOCK_CYCLES(15); + return 0; +} +static int opINSL_a32(uint32_t fetchdat) +{ + uint32_t temp; + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + temp = inl(DX); + writememl(es, EDI, temp); if (abrt) return 1; + if (flags & D_FLAG) EDI -= 4; + else EDI += 4; + CLOCK_CYCLES(15); + return 0; +} + +static int opOUTSB_a16(uint32_t fetchdat) +{ + uint8_t temp = readmemb(ea_seg->base, SI); if (abrt) return 1; + check_io_perm(DX); + if (flags & D_FLAG) SI--; + else SI++; + outb(DX, temp); + CLOCK_CYCLES(14); + return 0; +} +static int opOUTSB_a32(uint32_t fetchdat) +{ + uint8_t temp = readmemb(ea_seg->base, ESI); if (abrt) return 1; + check_io_perm(DX); + if (flags & D_FLAG) ESI--; + else ESI++; + outb(DX, temp); + CLOCK_CYCLES(14); + return 0; +} + +static int opOUTSW_a16(uint32_t fetchdat) +{ + uint16_t temp = readmemw(ea_seg->base, SI); if (abrt) return 1; + check_io_perm(DX); + check_io_perm(DX + 1); + if (flags & D_FLAG) SI -= 2; + else SI += 2; + outw(DX, temp); + CLOCK_CYCLES(14); + return 0; +} +static int opOUTSW_a32(uint32_t fetchdat) +{ + uint16_t temp = readmemw(ea_seg->base, ESI); if (abrt) return 1; + check_io_perm(DX); + check_io_perm(DX + 1); + if (flags & D_FLAG) ESI -= 2; + else ESI += 2; + outw(DX, temp); + CLOCK_CYCLES(14); + return 0; +} + +static int opOUTSL_a16(uint32_t fetchdat) +{ + uint32_t temp = readmeml(ea_seg->base, SI); if (abrt) return 1; + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + if (flags & D_FLAG) SI -= 4; + else SI += 4; + outl(EDX, temp); + CLOCK_CYCLES(14); + return 0; +} +static int opOUTSL_a32(uint32_t fetchdat) +{ + uint32_t temp = readmeml(ea_seg->base, ESI); if (abrt) return 1; + check_io_perm(DX); + check_io_perm(DX + 1); + check_io_perm(DX + 2); + check_io_perm(DX + 3); + if (flags & D_FLAG) ESI -= 4; + else ESI += 4; + outl(EDX, temp); + CLOCK_CYCLES(14); + return 0; +} diff --git a/src/x86_ops_xchg.h b/src/x86_ops_xchg.h new file mode 100644 index 000000000..55a3d4a58 --- /dev/null +++ b/src/x86_ops_xchg.h @@ -0,0 +1,195 @@ +static int opXCHG_b_a16(uint32_t fetchdat) +{ + uint8_t temp; + fetch_ea_16(fetchdat); + temp = geteab(); if (abrt) return 1; + seteab(getr8(reg)); if (abrt) return 1; + setr8(reg, temp); + CLOCK_CYCLES((mod == 3) ? 3 : 5); + return 0; +} +static int opXCHG_b_a32(uint32_t fetchdat) +{ + uint8_t temp; + fetch_ea_32(fetchdat); + temp = geteab(); if (abrt) return 1; + seteab(getr8(reg)); if (abrt) return 1; + setr8(reg, temp); + CLOCK_CYCLES((mod == 3) ? 3 : 5); + return 0; +} + +static int opXCHG_w_a16(uint32_t fetchdat) +{ + uint16_t temp; + fetch_ea_16(fetchdat); + temp = geteaw(); if (abrt) return 1; + seteaw(cpu_state.regs[reg].w); if (abrt) return 1; + cpu_state.regs[reg].w = temp; + CLOCK_CYCLES((mod == 3) ? 3 : 5); + return 0; +} +static int opXCHG_w_a32(uint32_t fetchdat) +{ + uint16_t temp; + fetch_ea_32(fetchdat); + temp = geteaw(); if (abrt) return 1; + seteaw(cpu_state.regs[reg].w); if (abrt) return 1; + cpu_state.regs[reg].w = temp; + CLOCK_CYCLES((mod == 3) ? 3 : 5); + return 0; +} + +static int opXCHG_l_a16(uint32_t fetchdat) +{ + uint32_t temp; + fetch_ea_16(fetchdat); + temp = geteal(); if (abrt) return 1; + seteal(cpu_state.regs[reg].l); if (abrt) return 1; + cpu_state.regs[reg].l = temp; + CLOCK_CYCLES((mod == 3) ? 3 : 5); + return 0; +} +static int opXCHG_l_a32(uint32_t fetchdat) +{ + uint32_t temp; + fetch_ea_32(fetchdat); + temp = geteal(); if (abrt) return 1; + seteal(cpu_state.regs[reg].l); if (abrt) return 1; + cpu_state.regs[reg].l = temp; + CLOCK_CYCLES((mod == 3) ? 3 : 5); + return 0; +} + + +static int opXCHG_AX_BX(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = BX; + BX = temp; + CLOCK_CYCLES(3); + return 0; +} +static int opXCHG_AX_CX(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = CX; + CX = temp; + CLOCK_CYCLES(3); + return 0; +} +static int opXCHG_AX_DX(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = DX; + DX = temp; + CLOCK_CYCLES(3); + return 0; +} +static int opXCHG_AX_SI(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = SI; + SI = temp; + CLOCK_CYCLES(3); + return 0; +} +static int opXCHG_AX_DI(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = DI; + DI = temp; + CLOCK_CYCLES(3); + return 0; +} +static int opXCHG_AX_BP(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = BP; + BP = temp; + CLOCK_CYCLES(3); + return 0; +} +static int opXCHG_AX_SP(uint32_t fetchdat) +{ + uint16_t temp = AX; + AX = SP; + SP = temp; + CLOCK_CYCLES(3); + return 0; +} + +static int opXCHG_EAX_EBX(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = EBX; + EBX = temp; + CLOCK_CYCLES(3); + return 0; +} +static int opXCHG_EAX_ECX(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = ECX; + ECX = temp; + CLOCK_CYCLES(3); + return 0; +} +static int opXCHG_EAX_EDX(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = EDX; + EDX = temp; + CLOCK_CYCLES(3); + return 0; +} +static int opXCHG_EAX_ESI(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = ESI; + ESI = temp; + CLOCK_CYCLES(3); + return 0; +} +static int opXCHG_EAX_EDI(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = EDI; + EDI = temp; + CLOCK_CYCLES(3); + return 0; +} +static int opXCHG_EAX_EBP(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = EBP; + EBP = temp; + CLOCK_CYCLES(3); + return 0; +} +static int opXCHG_EAX_ESP(uint32_t fetchdat) +{ + uint32_t temp = EAX; + EAX = ESP; + ESP = temp; + CLOCK_CYCLES(3); + return 0; +} + + +#define opBSWAP(reg) \ + static int opBSWAP_ ## reg(uint32_t fetchdat) \ + { \ + reg = (reg >> 24) | ((reg >> 8) & 0xff00) | ((reg << 8) & 0xff0000) | ((reg << 24) & 0xff000000); \ + CLOCK_CYCLES(1); \ + return 0; \ + } + +opBSWAP(EAX) +opBSWAP(EBX) +opBSWAP(ECX) +opBSWAP(EDX) +opBSWAP(ESI) +opBSWAP(EDI) +opBSWAP(EBP) +opBSWAP(ESP) diff --git a/src/x86seg.c b/src/x86seg.c new file mode 100644 index 000000000..c72d6c80f --- /dev/null +++ b/src/x86seg.c @@ -0,0 +1,2597 @@ +//#if 0 +#include +#include +#include +#include "ibm.h" +#include "mem.h" +#include "x86.h" +#include "386.h" +#include "cpu.h" + +/*Controls whether the accessed bit in a descriptor is set when CS is loaded.*/ +#define CS_ACCESSED + +/*Controls whether the accessed bit in a descriptor is set when a data or stack + selector is loaded.*/ +#define SEL_ACCESSED +int stimes = 0; +int dtimes = 0; +int btimes = 0; +int is486=1; + +uint32_t abrt_error; +int cgate16,cgate32; + +#define breaknullsegs 0 + +int intgatesize; + +void taskswitch286(uint16_t seg, uint16_t *segdat, int is32); +void taskswitch386(uint16_t seg, uint16_t *segdat); + +int output; +void pmodeint(int num, int soft); +/*NOT PRESENT is INT 0B + GPF is INT 0D*/ + +FILE *pclogf; +void x86abort(const char *format, ...) +{ + char buf[256]; +// return; + if (!pclogf) + pclogf=fopen("pclog.txt","wt"); +//return; + va_list ap; + va_start(ap, format); + vsprintf(buf, format, ap); + va_end(ap); + fputs(buf,pclogf); + fflush(pclogf); + dumpregs(); + exit(-1); +} + +uint8_t opcode2; + +static void seg_reset(x86seg *s) +{ + s->access = (0 << 5) | 2 | 0x80; + s->limit = 0xFFFF; + s->limit_low = 0; + s->limit_high = 0xffff; +} + +void x86seg_reset() +{ + seg_reset(&_cs); + seg_reset(&_ds); + seg_reset(&_es); + seg_reset(&_fs); + seg_reset(&_gs); + seg_reset(&_ss); +} + +void x86_doabrt(int x86_abrt) +{ +// ingpf = 1; + CS = oldcs; + cpu_state.pc = oldpc; + _cs.access = (oldcpl << 5) | 0x80; +// pclog("x86_doabrt - %02X %08X %04X:%08X %i\n", x86_abrt, abrt_error, CS, pc, ins); + +/* if (CS == 0x3433 && cpu_state.pc == 0x000006B0) + { + pclog("Quit it\n"); + dumpregs(); + exit(-1); + }*/ +// pclog("GPF! - error %04X %04X(%08X):%08X %02X %02X %i %04X %i %i\n",error,CS,cs,cpu_state.pc,opcode,opcode2,ins,flags&I_FLAG,IOPL, dtimes); + + if (msw & 1) + pmodeint(x86_abrt, 0); + else + { + uint32_t addr = (x86_abrt << 2) + idt.base; + if (stack32) + { + writememw(ss,ESP-2,flags); + writememw(ss,ESP-4,CS); + writememw(ss,ESP-6,cpu_state.pc); + ESP-=6; + } + else + { + writememw(ss,((SP-2)&0xFFFF),flags); + writememw(ss,((SP-4)&0xFFFF),CS); + writememw(ss,((SP-6)&0xFFFF),cpu_state.pc); + SP-=6; + } + + flags&=~I_FLAG; + flags&=~T_FLAG; + oxpc=cpu_state.pc; + cpu_state.pc=readmemw(0,addr); + loadcs(readmemw(0,addr+2)); + return; + } + + if (abrt) return; + + if (intgatesize == 16) + { + if (stack32) + { + writememw(ss, ESP-2, abrt_error); + ESP-=2; + } + else + { + writememw(ss, ((SP-2)&0xFFFF), abrt_error); + SP-=2; + } + } + else + { + if (stack32) + { + writememl(ss, ESP-4, abrt_error); + ESP-=4; + } + else + { + writememl(ss, ((SP-4)&0xFFFF), abrt_error); + SP-=4; + } + } +// ingpf = 0; +// abrt = gpf = 1; +} +void x86gpf(char *s, uint16_t error) +{ + // pclog("GPF %04X : %s\n", error, s); + abrt = ABRT_GPF; + abrt_error = error; +} +void x86ss(char *s, uint16_t error) +{ + // pclog("SS %04X\n", error); + abrt = ABRT_SS; + abrt_error = error; +} +void x86ts(char *s, uint16_t error) +{ + // pclog("TS %04X\n", error); + abrt = ABRT_TS; + abrt_error = error; +} +void x86np(char *s, uint16_t error) +{ + // pclog("NP %04X : %s\n", error, s); + abrt = ABRT_NP; + abrt_error = error; +} + + +void do_seg_load(x86seg *s, uint16_t *segdat) +{ + s->limit = segdat[0] | ((segdat[3] & 0xF) << 16); + if (segdat[3] & 0x80) + s->limit = (s->limit << 12) | 0xFFF; + s->base = segdat[1] | ((segdat[2] & 0xFF) << 16); + if (is386) + s->base |= ((segdat[3] >> 8) << 24); + s->access = segdat[2] >> 8; + + if ((segdat[2] & 0x1800) != 0x1000 || !(segdat[2] & (1 << 10))) /*expand-down*/ + { + s->limit_high = s->limit; + s->limit_low = 0; + } + else + { + s->limit_high = (segdat[3] & 0x40) ? 0xffffffff : 0xffff; + s->limit_low = s->limit + 1; + } +// if (output) pclog("SEG : base=%08x limit=%08x low=%08x high=%08x\n", s->base, s->limit, s->limit_low, s->limit_high); +} + +static void do_seg_v86_init(x86seg *s) +{ + s->access = (3 << 5) | 2 | 0x80; + s->limit = 0xffff; + s->limit_low = 0; + s->limit_high = 0xffff; +} + +static void check_seg_valid(x86seg *s) +{ + int dpl = (s->access >> 5) & 3; + int valid = 1; + + if (s->seg & 4) + { + if ((s->seg & ~7) >= ldt.limit) + { +// pclog("Bigger than LDT limit %04X %04X %02X %02X %02X\n", s->seg, ldt.limit, opcode, opcode2, rmdat); + valid = 0; + } + } + else + { + if ((s->seg & ~7) >= gdt.limit) + { +// pclog("Bigger than GDT limit %04X %04X\n", s->seg, gdt.limit); + valid = 0; + } + } + + switch (s->access & 0x1f) + { + case 0x10: case 0x11: case 0x12: case 0x13: /*Data segments*/ + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x1A: case 0x1B: /*Readable non-conforming code*/ + if ((s->seg & 3) > dpl || (CPL) > dpl) + { +// pclog("Data seg fail - %04X:%08X %04X %i\n", CS, cpu_state.pc, s->seg, dpl); + valid = 0; + break; + } + break; + + case 0x1E: case 0x1F: /*Readable conforming code*/ + break; + + default: + valid = 0; + break; + } + + if (!valid) + loadseg(0, s); +} + +void loadseg(uint16_t seg, x86seg *s) +{ + uint16_t segdat[4]; + uint32_t addr; + int dpl; + + if (msw&1 && !(eflags&VM_FLAG)) + { +// intcount++; + if (!(seg&~3)) + { + if (s==&_ss) + { + pclog("SS selector = NULL!\n"); + x86ss(NULL,0); + return; +// dumpregs(); +// exit(-1); + } +// if (s->base!=-1) pclog("NEW! "); + s->seg=0; + // s->access = 0; + s->access = 0x80; + s->base=-1; +// pclog("NULL selector %s%s%s%s %04X(%06X):%06X\n",(s==&_ds)?"DS":"",(s==&_es)?"ES":"",(s==&_fs)?"FS":"",(s==&_gs)?"GS":"",CS,cs,cpu_state.pc); + return; + } +// if (s==&_ss) pclog("Load SS %04X\n",seg); +// pclog("Protected mode seg load!\n"); + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X %02X %02X %02X\n",seg,ldt.limit, opcode, opcode2, rmdat); +// dumppic(); +// dumpregs(); +// exit(-1); + x86gpf("loadseg(): Bigger than LDT limit",seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X 1\n",seg,gdt.limit); +// dumpregs(); +// exit(-1); + x86gpf("loadseg(): Bigger than GDT limit",seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) return; + dpl=(segdat[2]>>13)&3; + if (s==&_ss) + { + if (!(seg&~3)) + { + pclog("Load SS null selector\n"); + x86gpf(NULL,seg&~3); + return; + } + if ((seg&3)!=CPL || dpl!=CPL) + { + pclog("Invalid SS permiss\n"); + x86gpf(NULL,seg&~3); +// x86abort("Invalid SS permiss for %04X!\n",seg&0xFFFC); + return; + } + switch ((segdat[2]>>8)&0x1F) + { + case 0x12: case 0x13: case 0x16: case 0x17: /*r/w*/ + break; + default: + pclog("Invalid SS type\n"); + x86gpf(NULL,seg&~3); +// x86abort("Invalid SS segment type for %04X!\n",seg&0xFFFC); + return; + } + if (!(segdat[2]&0x8000)) + { + pclog("Load SS not present!\n"); + x86ss(NULL,seg&~3); + return; + } + stack32 = (segdat[3] & 0x40) ? 1 : 0; +// pclog("Load SS %04x %04x %04x %04x\n", segdat[0], segdat[1], segdat[2], segdat[3]); + } + else if (s!=&_cs) + { + if (output) pclog("Seg data %04X %04X %04X %04X\n", segdat[0], segdat[1], segdat[2], segdat[3]); + if (output) pclog("Seg type %03X\n",segdat[2]&0x1F00); + switch ((segdat[2]>>8)&0x1F) + { + case 0x10: case 0x11: case 0x12: case 0x13: /*Data segments*/ + case 0x14: case 0x15: case 0x16: case 0x17: + case 0x1A: case 0x1B: /*Readable non-conforming code*/ +// pclog("Load seg %04X %i %i %04X:%08X\n",seg,dpl,CS&3,CS,cpu_state.pc); + if ((seg&3)>dpl || (CPL)>dpl) + { + pclog("Data seg fail - %04X:%08X %04X %i %04X\n",CS,cpu_state.pc,seg,dpl,segdat[2]); + x86gpf(NULL,seg&~3); +// x86abort("Data segment load - level too low!\n",seg&0xFFFC); + return; + } + break; + case 0x1E: case 0x1F: /*Readable conforming code*/ + break; + default: + pclog("Invalid segment type for %04X! %04X\n",seg&0xFFFC,segdat[2]); + x86gpf(NULL,seg&~3); + return; + } + } + + if (!(segdat[2] & 0x8000)) + { + x86np("Load data seg not present", seg & 0xfffc); + return; + } + s->seg = seg; + do_seg_load(s, segdat); + +#ifndef CS_ACCESSED + if (s != &_cs) + { +#endif +#ifdef SEL_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif +#ifndef CS_ACCESSED + } +#endif + s->checked = 0; + } + else + { + s->access = (3 << 5) | 2 | 0x80; + s->base = seg << 4; + s->seg = seg; + if (s == &_ss) + stack32 = 0; + s->checked = 1; + } +} + +#define DPL ((segdat[2]>>13)&3) +#define DPL2 ((segdat2[2]>>13)&3) +#define DPL3 ((segdat3[2]>>13)&3) + +void loadcs(uint16_t seg) +{ + uint16_t segdat[4]; + uint32_t addr; + if (output) pclog("Load CS %04X\n",seg); + if (msw&1 && !(eflags&VM_FLAG)) + { +// intcount++; +// flushmmucache(); +// pclog("Load CS %04X\n",seg); + if (!(seg&~3)) + { + pclog("Trying to load CS with NULL selector! lcs\n"); +// dumpregs(); +// exit(-1); + x86gpf(NULL,0); + return; + } +// pclog("Protected mode CS load! %04X\n",seg); + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X CS\n",seg,ldt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X CS\n",seg,gdt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) return; + if (optype==JMP) pclog("Code seg - %04X - %04X %04X %04X %04X\n",seg,segdat[0],segdat[1],segdat[2],segdat[3]); +// if (!(segdat[2]&0x8000)) x86abort("Code segment not present!\n"); +// if (output) pclog("Segdat2 %04X\n",segdat[2]); + if (segdat[2]&0x1000) /*Normal code segment*/ + { + if (!(segdat[2]&0x400)) /*Not conforming*/ + { + if ((seg&3)>CPL) + { + x86gpf(NULL,seg&~3); + pclog("loadcs RPL > CPL %04X %04X %i %02X\n",segdat[2],seg,CPL,opcode); + return; + } + if (CPL != DPL) + { + x86gpf("loadcs(): CPL != DPL",seg&~3); + return; + } + } + if (CPL < DPL) + { + x86gpf("loadcs(): CPL < DPL",seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86np("Load CS not present", seg & 0xfffc); + return; + } + if (segdat[3]&0x40) use32=0x300; + else use32=0; + CS=(seg&~3)|CPL; + do_seg_load(&_cs, segdat); + use32=(segdat[3]&0x40)?0x300:0; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif +// if (output) pclog("Load CS %08X\n",_cs.base); +// CS=(CS&0xFFFC)|((_cs.access>>5)&3); + } + else /*System segment*/ + { + if (!(segdat[2]&0x8000)) + { + x86np("Load CS system seg not present\n", seg & 0xfffc); + return; + } + switch (segdat[2]&0xF00) + { + default: + pclog("Bad CS %02X %02X %i special descriptor %03X %04X\n",opcode,rmdat,optype,segdat[2]&0xF00,seg); + x86gpf(NULL,seg&~3); + return; + } + } +// pclog("CS = %04X base=%06X limit=%04X access=%02X %04X\n",CS,cs,_cs.limit,_cs.access,addr); +// dumpregs(); +// exit(-1); + } + else + { + _cs.base=seg<<4; + _cs.limit=0xFFFF; + _cs.limit_low = 0; + _cs.limit_high = 0xffff; + CS=seg; + if (eflags&VM_FLAG) _cs.access=(3<<5) | 2 | 0x80; + else _cs.access=(0<<5) | 2 | 0x80; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + } +} + +void loadcsjmp(uint16_t seg, uint32_t oxpc) +{ + uint16_t segdat[4]; + uint32_t addr; + int count; + uint16_t type,seg2; + uint32_t newpc; +// pclog("Load CS JMP %04X\n",seg); + if (msw&1 && !(eflags&VM_FLAG)) + { + if (!(seg&~3)) + { + pclog("Trying to load CS with NULL selector! lcsjmp\n"); + x86gpf(NULL,0); + return; +// dumpregs(); +// exit(-1); + } + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X CS\n",seg,ldt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X CS\n",seg,gdt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) return; + if (output) pclog("%04X %04X %04X %04X\n",segdat[0],segdat[1],segdat[2],segdat[3]); + if (segdat[2]&0x1000) /*Normal code segment*/ + { +// pclog("Normal CS\n"); + if (!(segdat[2]&0x400)) /*Not conforming*/ + { + if ((seg&3)>CPL) + { + x86gpf("loadcsjmp(): segment PL > CPL",seg&~3); + return; + } + if (CPL != DPL) + { + x86gpf("loadcsjmp(): CPL != DPL",seg&~3); + return; + } + } + if (CPL < DPL) + { + x86gpf("loadcsjmp(): CPL < DPL",seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86np("Load CS JMP not present\n", seg & 0xfffc); + return; + } + if (segdat[3]&0x40) use32=0x300; + else use32=0; + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + CS = (seg & ~3) | CPL; + segdat[2] = (segdat[2] & ~(3 << (5+8))) | (CPL << (5+8)); + + do_seg_load(&_cs, segdat); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + use32=(segdat[3]&0x40)?0x300:0; + cycles -= timing_jmp_pm; + } + else /*System segment*/ + { +// pclog("System CS\n"); + if (!(segdat[2]&0x8000)) + { + x86np("Load CS JMP system selector not present\n", seg & 0xfffc); + return; + } + type=segdat[2]&0xF00; + if (type==0x400) newpc=segdat[0]; + else newpc=segdat[0]|(segdat[3]<<16); + switch (type) + { + case 0x400: /*Call gate*/ + case 0xC00: +// pclog("Call gate\n"); + cgate32=(type&0x800); + cgate16=!cgate32; + oldcs=CS; + oldpc=cpu_state.pc; + count=segdat[2]&31; +#if 0 + if ((DPL < CPL) || (DPL < (seg&3))) + { + x86gpf(NULL,seg&~3); + return; + } +#endif + if (DPL < CPL) + { + x86gpf("loadcsjmp(): ex DPL < CPL",seg&~3); + return; + } + if ((DPL < (seg&3))) + { + x86gpf("loadcsjmp(): ex (DPL < (seg&3))",seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86np("Load CS JMP call gate not present\n", seg & 0xfffc); + return; + } + seg2=segdat[1]; + + if (!(seg2&~3)) + { + pclog("Trying to load CS with NULL selector! lcsjmpcg\n"); + x86gpf(NULL,0); + return; +// dumpregs(); +// exit(-1); + } + addr=seg2&~7; + if (seg2&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X CSJ\n",seg2,gdt.limit); + x86gpf(NULL,seg2&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X CSJ\n",seg2,gdt.limit); + x86gpf(NULL,seg2&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) return; + + if (DPL > CPL) + { + x86gpf("loadcsjmp(): ex DPL > CPL",seg2&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + x86np("Load CS JMP from call gate not present\n", seg2 & 0xfffc); + return; + } + + + switch (segdat[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming code*/ + if (DPL > CPL) + { + pclog("Call gate DPL > CPL"); + x86gpf(NULL,seg2&~3); + return; + } + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + CS=seg2; + do_seg_load(&_cs, segdat); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + use32=(segdat[3]&0x40)?0x300:0; + cpu_state.pc=newpc; + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + break; + + default: + pclog("JMP Call gate bad segment type\n"); + x86gpf(NULL,seg2&~3); + return; + } + cycles -= timing_jmp_pm_gate; + break; + + + case 0x900: /*386 Task gate*/ +// pclog("Task gate\n"); + cpu_state.pc=oxpc; + cpl_override=1; + taskswitch286(seg,segdat,segdat[2]&0x800); + flags &= ~NT_FLAG; + cpl_override=0; +// case 0xB00: /*386 Busy task gate*/ +// if (optype==JMP) pclog("Task switch!\n"); +// taskswitch386(seg,segdat); + return; + + default: + pclog("Bad JMP CS %02X %02X %i special descriptor %03X %04X\n",opcode,rmdat,optype,segdat[2]&0xF00,seg); + x86gpf(NULL,0); + return; +// dumpregs(); +// exit(-1); + } + } +// pclog("CS = %04X base=%06X limit=%04X access=%02X %04X\n",CS,cs,_cs.limit,_cs.access,addr); +// dumpregs(); +// exit(-1); + } + else + { + _cs.base=seg<<4; + _cs.limit=0xFFFF; + _cs.limit_low = 0; + _cs.limit_high = 0xffff; + CS=seg; + if (eflags&VM_FLAG) _cs.access=(3<<5) | 2 | 0x80; + else _cs.access=(0<<5) | 2 | 0x80; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + cycles -= timing_jmp_rm; + } +} + +void PUSHW(uint16_t v) +{ +// if (output==3) pclog("PUSHW %04X to %08X\n",v,ESP-4); + if (stack32) + { + writememw(ss,ESP-2,v); + if (abrt) return; + ESP-=2; + } + else + { +// pclog("Write %04X to %08X\n", v, ss+((SP-2)&0xFFFF)); + writememw(ss,((SP-2)&0xFFFF),v); + if (abrt) return; + SP-=2; + } +} +void PUSHL(uint32_t v) +{ +// if (output==3) pclog("PUSHL %08X to %08X\n",v,ESP-4); + if (stack32) + { + writememl(ss,ESP-4,v); + if (abrt) return; + ESP-=4; + } + else + { + writememl(ss,((SP-4)&0xFFFF),v); + if (abrt) return; + SP-=4; + } +} +uint16_t POPW() +{ + uint16_t tempw; + if (stack32) + { + tempw=readmemw(ss,ESP); + if (abrt) return 0; + ESP+=2; + } + else + { + tempw=readmemw(ss,SP); + if (abrt) return 0; + SP+=2; + } + return tempw; +} +uint32_t POPL() +{ + uint32_t templ; + if (stack32) + { + templ=readmeml(ss,ESP); + if (abrt) return 0; + ESP+=4; + } + else + { + templ=readmeml(ss,SP); + if (abrt) return 0; + SP+=4; + } + return templ; +} + +void loadcscall(uint16_t seg) +{ + uint16_t seg2; + uint16_t segdat[4],segdat2[4],newss; + uint32_t addr,oldssbase=ss, oaddr; + uint32_t newpc; + int count; + uint16_t oldcs=CPL; + uint32_t oldss,oldsp,newsp,oldpc, oldsp2; + int type; + uint16_t tempw; + + int csout = output; + + if (msw&1 && !(eflags&VM_FLAG)) + { + //flushmmucache(); + if (csout) pclog("Protected mode CS load! %04X\n",seg); + if (!(seg&~3)) + { + pclog("Trying to load CS with NULL selector! lcscall\n"); + x86gpf(NULL,0); + return; +// dumpregs(); +// exit(-1); + } + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X CSC\n",seg,gdt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X CSC\n",seg,gdt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) return; + type=segdat[2]&0xF00; + if (type==0x400) newpc=segdat[0]; + else newpc=segdat[0]|(segdat[3]<<16); + + if (csout) pclog("Code seg call - %04X - %04X %04X %04X\n",seg,segdat[0],segdat[1],segdat[2]); + if (segdat[2]&0x1000) + { + if (!(segdat[2]&0x400)) /*Not conforming*/ + { + if ((seg&3)>CPL) + { + /* if (csout) */ pclog("Not conforming, RPL > CPL\n"); + x86gpf("loadcscall(): segment > CPL",seg&~3); + return; + } + if (CPL != DPL) + { + /* if (csout) */ pclog("Not conforming, CPL != DPL (%i %i)\n",CPL,DPL); + x86gpf(NULL,seg&~3); + return; + } + } + if (CPL < DPL) + { + /* if (csout) */ pclog("CPL < DPL\n"); + x86gpf(NULL,seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + /* if (csout) */ pclog("Not present\n"); + x86np("Load CS call not present", seg & 0xfffc); + return; + } + if (segdat[3]&0x40) use32=0x300; + else use32=0; + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + /*Conforming segments don't change CPL, so preserve existing CPL*/ + if (segdat[2]&0x400) + { + seg = (seg & ~3) | CPL; + segdat[2] = (segdat[2] & ~(3 << (5+8))) | (CPL << (5+8)); + } + else /*On non-conforming segments, set RPL = CPL*/ + seg = (seg & ~3) | CPL; + CS=seg; + do_seg_load(&_cs, segdat); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + use32=(segdat[3]&0x40)?0x300:0; + if (csout) pclog("Complete\n"); + cycles -= timing_call_pm; + } + else + { + type=segdat[2]&0xF00; + if (csout) pclog("Type %03X\n",type); + switch (type) + { + case 0x400: /*Call gate*/ + case 0xC00: /*386 Call gate*/ + if (output) pclog("Callgate %08X\n", cpu_state.pc); + cgate32=(type&0x800); + cgate16=!cgate32; + oldcs=CS; + oldpc=cpu_state.pc; + count=segdat[2]&31; +#if 0 + if ((DPL < CPL) || (DPL < (seg&3))) + { + x86gpf("",seg&~3); + return; + } +#endif + if ((DPL < CPL)) + { + x86gpf("loadcscall(): ex DPL < CPL",seg&~3); + return; + } + if ((DPL < (seg&3))) + { + x86gpf("loadcscall(): ex (DPL < (seg&3))",seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + if (output) pclog("Call gate not present %04X\n",seg); + x86np("Call gate not present\n", seg & 0xfffc); + return; + } + seg2=segdat[1]; + + if (output) pclog("New address : %04X:%08X\n", seg2, newpc); + + if (!(seg2&~3)) + { + pclog("Trying to load CS with NULL selector! lcscallcg\n"); + x86gpf(NULL,0); + return; +// dumpregs(); +// exit(-1); + } + addr=seg2&~7; + if (seg2&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X CSC\n",seg2,gdt.limit); + x86gpf(NULL,seg2&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X CSC\n",seg2,gdt.limit); + x86gpf(NULL,seg2&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) return; + + if (output) pclog("Code seg2 call - %04X - %04X %04X %04X\n",seg2,segdat[0],segdat[1],segdat[2]); + + if (DPL > CPL) + { + x86gpf("loadcscall(): ex DPL > CPL",seg2&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + if (output) pclog("Call gate CS not present %04X\n",seg2); + x86np("Call gate CS not present", seg2 & 0xfffc); + return; + } + + + switch (segdat[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming code*/ + if (DPL < CPL) + { + oaddr = addr; + /*Load new stack*/ + oldss=SS; + oldsp=oldsp2=ESP; + cpl_override=1; + if (tr.access&8) + { + addr = 4 + tr.base + (DPL * 8); + newss=readmemw(0,addr+4); + newsp=readmeml(0,addr); + } + else + { + addr = 2 + tr.base + (DPL * 4); + newss=readmemw(0,addr+2); + newsp=readmemw(0,addr); + } + cpl_override=0; + if (abrt) return; + if (output) pclog("New stack %04X:%08X\n",newss,newsp); + if (!(newss&~3)) + { + pclog("Call gate loading null SS\n"); + x86ts(NULL,newss&~3); + return; + } + addr=newss&~7; + if (newss&4) + { + if (addr>=ldt.limit) + { + x86abort("Bigger than LDT limit %04X %08X %04X CSC SS\n",newss,addr,ldt.limit); + x86ts(NULL,newss&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + x86abort("Bigger than GDT limit %04X %04X CSC\n",newss,gdt.limit); + x86ts(NULL,newss&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + if (output) pclog("Read stack seg\n"); + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) return; + if (output) pclog("Read stack seg done!\n"); + if (((newss & 3) != DPL) || (DPL2 != DPL)) + { + pclog("Call gate loading SS with wrong permissions %04X %04X %i %i %04X %04X\n", newss, seg2, DPL, DPL2, segdat[2], segdat2[2]); +// dumpregs(); +// exit(-1); + x86ts(NULL,newss&~3); + return; + } + if ((segdat2[2]&0x1A00)!=0x1200) + { + pclog("Call gate loading SS wrong type\n"); + x86ts(NULL,newss&~3); + return; + } + if (!(segdat2[2]&0x8000)) + { + pclog("Call gate loading SS not present\n"); + x86np("Call gate loading SS not present\n", newss & 0xfffc); + return; + } + if (!stack32) oldsp &= 0xFFFF; + SS=newss; + stack32 = (segdat2[3] & 0x40) ? 1 : 0; + if (stack32) ESP=newsp; + else SP=newsp; + + do_seg_load(&_ss, segdat2); + + if (output) pclog("Set access 1\n"); + +#ifdef SEL_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat2[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + CS=seg2; + do_seg_load(&_cs, segdat); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + use32=(segdat[3]&0x40)?0x300:0; + cpu_state.pc=newpc; + + if (output) pclog("Set access 2\n"); + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, oaddr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + if (output) pclog("Type %04X\n",type); + if (type==0xC00) + { + PUSHL(oldss); + PUSHL(oldsp2); + if (abrt) + { + pclog("ABRT PUSHL\n"); + SS = oldss; + ESP = oldsp2; + return; + } +// if (output) pclog("Stack now %04X:%08X\n",SS,ESP); + if (count) + { + while (count) + { + count--; + PUSHL(readmeml(oldssbase,oldsp+(count*4))); + if (abrt) + { + pclog("ABRT COPYL\n"); + SS = oldss; + ESP = oldsp2; + return; + } + } + } +// x86abort("Call gate with count %i\n",count); +// PUSHL(oldcs); +// PUSHL(oldpc); if (abrt) return; + } + else + { + if (output) pclog("Stack %04X\n",SP); + PUSHW(oldss); + if (output) pclog("Write SS to %04X:%04X\n",SS,SP); + PUSHW(oldsp2); + if (abrt) + { + pclog("ABRT PUSHW\n"); + SS = oldss; + ESP = oldsp2; + return; + } + if (output) pclog("Write SP to %04X:%04X\n",SS,SP); +// if (output) pclog("Stack %04X %i %04X:%04X\n",SP,count,oldssbase,oldsp); +// if (output) pclog("PUSH %04X %04X %i %i now %04X:%08X\n",oldss,oldsp,count,stack32,SS,ESP); + if (count) + { + while (count) + { + count--; + tempw=readmemw(oldssbase,(oldsp&0xFFFF)+(count*2)); + if (output) pclog("PUSH %04X\n",tempw); + PUSHW(tempw); + if (abrt) + { + pclog("ABRT COPYW\n"); + SS = oldss; + ESP = oldsp2; + return; + } + } + } +// if (output) pclog("Stack %04X\n",SP); +// if (count) x86abort("Call gate with count\n"); +// PUSHW(oldcs); +// PUSHW(oldpc); if (abrt) return; + } + cycles -= timing_call_pm_gate_inner; + break; + } + else if (DPL > CPL) + { + pclog("Call gate DPL > CPL"); + x86gpf(NULL,seg2&~3); + return; + } + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ +/* if (type==0xC00) + { + PUSHL(oldcs); + PUSHL(oldpc); if (abrt) return; + } + else + { + PUSHW(oldcs); + PUSHW(oldpc); if (abrt) return; + }*/ + CS=seg2; + do_seg_load(&_cs, segdat); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + use32=(segdat[3]&0x40)?0x300:0; + cpu_state.pc=newpc; + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + cycles -= timing_call_pm_gate; + break; + + default: + pclog("Call gate bad segment type\n"); + x86gpf(NULL,seg2&~3); + return; + } + break; + +// case 0x900: /*386 Task gate*/ +// case 0xB00: /*386 Busy task gate*/ +// if (optype==JMP) pclog("Task switch!\n"); +// taskswitch386(seg,segdat); +// return; + + + default: + pclog("Bad CALL special descriptor %03X\n",segdat[2]&0xF00); + x86gpf(NULL,seg&~3); + return; +// dumpregs(); +// exit(-1); + } + } +// pclog("CS = %04X base=%06X limit=%04X access=%02X %04X\n",CS,cs,_cs.limit,_cs.access,addr); +// dumpregs(); +// exit(-1); + } + else + { + _cs.base=seg<<4; + _cs.limit=0xFFFF; + _cs.limit_low = 0; + _cs.limit_high = 0xffff; + CS=seg; + if (eflags&VM_FLAG) _cs.access=(3<<5) | 2 | 0x80; + else _cs.access=(0<<5) | 2 | 0x80; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + } +} + +void pmoderetf(int is32, uint16_t off) +{ + uint32_t newpc; + uint32_t newsp; + uint32_t addr, oaddr; + uint16_t segdat[4],segdat2[4],seg,newss; + uint32_t oldsp=ESP; + if (output) pclog("RETF %i %04X:%04X %08X %04X\n",is32,CS,cpu_state.pc,cr0,eflags); + if (is32) + { + newpc=POPL(); + seg=POPL(); if (abrt) return; + } + else + { + if (output) pclog("PC read from %04X:%04X\n",SS,SP); + newpc=POPW(); + if (output) pclog("CS read from %04X:%04X\n",SS,SP); + seg=POPW(); if (abrt) return; + } + if (output) pclog("Return to %04X:%08X\n",seg,newpc); + if ((seg&3)=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X RETF\n",seg,ldt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X RETF\n",seg,gdt.limit); + x86gpf(NULL,seg&~3); +// dumpregs(); +// exit(-1); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) { ESP=oldsp; return; } + oaddr = addr; + + if (output) pclog("CPL %i RPL %i %i\n",CPL,seg&3,is32); + + if (stack32) ESP+=off; + else SP+=off; + + if (CPL==(seg&3)) + { + if (output) pclog("RETF CPL = RPL %04X\n", segdat[2]); + switch (segdat[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ + if (CPL != DPL) + { + pclog("RETF non-conforming CPL != DPL\n"); + ESP=oldsp; + x86gpf(NULL,seg&~3); + return; + } + break; + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + if (CPL < DPL) + { + pclog("RETF non-conforming CPL < DPL\n"); + ESP=oldsp; + x86gpf(NULL,seg&~3); + return; + } + break; + default: + pclog("RETF CS not code segment\n"); + x86gpf(NULL,seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + pclog("RETF CS not present %i %04X %04X %04X\n",ins, segdat[0], segdat[1], segdat[2]); + ESP=oldsp; + x86np("RETF CS not present\n", seg & 0xfffc); + return; + } + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + cpu_state.pc=newpc; + if (segdat[2] & 0x400) + segdat[2] = (segdat[2] & ~(3 << (5+8))) | ((seg & 3) << (5+8)); + CS = seg; + do_seg_load(&_cs, segdat); + _cs.access = (_cs.access & ~(3 << 5)) | ((CS & 3) << 5); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + use32=(segdat[3]&0x40)?0x300:0; + +// pclog("CPL=RPL return to %04X:%08X\n",CS,cpu_state.pc); + cycles -= timing_retf_pm; + } + else + { + switch (segdat[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ + if ((seg&3) != DPL) + { + pclog("RETF non-conforming RPL != DPL\n"); + ESP=oldsp; + x86gpf(NULL,seg&~3); + return; + } + if (output) pclog("RETF non-conforming, %i %i\n",seg&3, DPL); + break; + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + if ((seg&3) < DPL) + { + pclog("RETF non-conforming RPL < DPL\n"); + ESP=oldsp; + x86gpf(NULL,seg&~3); + return; + } + if (output) pclog("RETF conforming, %i %i\n",seg&3, DPL); + break; + default: + pclog("RETF CS not code segment\n"); + ESP=oldsp; + x86gpf(NULL,seg&~3); + return; + } + if (!(segdat[2]&0x8000)) + { + pclog("RETF CS not present! %i %04X %04X %04X\n",ins, segdat[0], segdat[1], segdat[2]); + + ESP=oldsp; + x86np("RETF CS not present\n", seg & 0xfffc); + return; + } + if (is32) + { + newsp=POPL(); + newss=POPL(); if (abrt) return; +// pclog("is32 new stack %04X:%04X\n",newss,newsp); + } + else + { + if (output) pclog("SP read from %04X:%04X\n",SS,SP); + newsp=POPW(); + if (output) pclog("SS read from %04X:%04X\n",SS,SP); + newss=POPW(); if (abrt) return; +// pclog("!is32 new stack %04X:%04X\n",newss,newsp); + } + if (output) pclog("Read new stack : %04X:%04X (%08X)\n", newss, newsp, ldt.base); + if (!(newss&~3)) + { + pclog("RETF loading null SS\n"); + ESP=oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr=newss&~7; + if (newss&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X RETF SS\n",newss,gdt.limit); + ESP=oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X RETF SS\n",newss,gdt.limit); + ESP=oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) { ESP=oldsp; return; } + if (output) pclog("Segment data %04X %04X %04X %04X\n", segdat2[0], segdat2[1], segdat2[2], segdat2[3]); +// if (((newss & 3) != DPL) || (DPL2 != DPL)) + if ((newss & 3) != (seg & 3)) + { + pclog("RETF loading SS with wrong permissions %i %i %04X %04X\n", newss & 3, seg & 3, newss, seg); + ESP=oldsp; +// output = 3; +// dumpregs(); +// exit(-1); + x86gpf(NULL,newss&~3); + return; + } + if ((segdat2[2]&0x1A00)!=0x1200) + { + pclog("RETF loading SS wrong type\n"); + ESP=oldsp; +// dumpregs(); +// exit(-1); + x86gpf(NULL,newss&~3); + return; + } + if (!(segdat2[2]&0x8000)) + { + pclog("RETF loading SS not present\n"); + ESP=oldsp; + x86np("RETF loading SS not present\n", newss & 0xfffc); + return; + } + if (DPL2 != (seg & 3)) + { + pclog("RETF loading SS with wrong permissions2 %i %i %04X %04X\n", DPL2, seg & 3, newss, seg); + ESP=oldsp; + x86gpf(NULL,newss&~3); + return; + } + SS=newss; + stack32 = (segdat2[3] & 0x40) ? 1 : 0; + if (stack32) ESP=newsp; + else SP=newsp; + do_seg_load(&_ss, segdat2); + +#ifdef SEL_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat2[2] | 0x100); /*Set accessed bit*/ + +#ifdef CS_ACCESSED + writememw(0, oaddr+4, segdat[2] | 0x100); /*Set accessed bit*/ +#endif + cpl_override = 0; +#endif + /*Conforming segments don't change CPL, so CPL = RPL*/ + if (segdat[2]&0x400) + segdat[2] = (segdat[2] & ~(3 << (5+8))) | ((seg & 3) << (5+8)); + + cpu_state.pc=newpc; + CS=seg; + do_seg_load(&_cs, segdat); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + use32=(segdat[3]&0x40)?0x300:0; + + if (stack32) ESP+=off; + else SP+=off; + + check_seg_valid(&_ds); + check_seg_valid(&_es); + check_seg_valid(&_fs); + check_seg_valid(&_gs); +// pclog("CPL=idt.limit) + { + if (num==8) + { + /*Triple fault - reset!*/ + pclog("Triple fault!\n"); +// output=1; + softresetx86(); + } + else if (num==0xD) + { + pclog("Double fault!\n"); + pmodeint(8,0); + } + else + { + pclog("INT out of range\n"); + x86gpf(NULL,(num*8)+2+(soft)?0:1); + } + if (output) pclog("addr >= IDT.limit\n"); + return; + } + addr+=idt.base; + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(2,addr); + segdat[2]=readmemw(4,addr); + segdat[3]=readmemw(6,addr); cpl_override=0; if (abrt) { pclog("Abrt reading from %08X\n",addr); return; } + oaddr = addr; + + if (output) pclog("Addr %08X seg %04X %04X %04X %04X\n",addr,segdat[0],segdat[1],segdat[2],segdat[3]); + if (!(segdat[2]&0x1F00)) + { + // pclog("No seg\n"); + x86gpf(NULL,(num*8)+2); + return; + } + if (DPL=0x800)?32:16; +// if (output) pclog("Int gate %04X %i oldpc %04X pc %04X\n",type,intgatesize,oldpc,cpu_state.pc); + if (!(segdat[2]&0x8000)) + { + pclog("Int gate not present\n"); + x86np("Int gate not present\n", (num << 3) | 2); + return; + } + seg=segdat[1]; + new_cpl = seg & 3; +// pclog("Interrupt gate : %04X:%04X%04X\n",seg,segdat[3],segdat[0]); + + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X INT\n",seg,gdt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X INT %i\n",seg,gdt.limit,ins); + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } +/* if ((seg&3) < CPL) + { + pclog("INT to higher level\n"); + x86gpf(NULL,seg&~3); + return; + }*/ + cpl_override=1; + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) return; + oaddr = addr; + + if (DPL2 > CPL) + { + pclog("INT to higher level 2\n"); + x86gpf(NULL,seg&~3); + return; + } + //pclog("Type %04X\n",segdat2[2]); + switch (segdat2[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ + if (DPL2=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X PMODEINT SS\n",newss,gdt.limit); + x86ss(NULL,newss&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X CSC\n",newss,gdt.limit); + x86ss(NULL,newss&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat3[0]=readmemw(0,addr); + segdat3[1]=readmemw(0,addr+2); + segdat3[2]=readmemw(0,addr+4); + segdat3[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) return; + if (((newss & 3) != DPL2) || (DPL3 != DPL2)) + { + pclog("Int gate loading SS with wrong permissions\n"); + x86ss(NULL,newss&~3); + return; + } + if ((segdat3[2]&0x1A00)!=0x1200) + { + pclog("Int gate loading SS wrong type\n"); + x86ss(NULL,newss&~3); + return; + } + if (!(segdat3[2]&0x8000)) + { + pclog("Int gate loading SS not present\n"); + x86np("Int gate loading SS not present\n", newss & 0xfffc); + return; + } + SS=newss; + stack32 = (segdat3[3] & 0x40) ? 1 : 0; + if (stack32) ESP=newsp; + else SP=newsp; + do_seg_load(&_ss, segdat3); + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat3[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + if (output) pclog("New stack %04X:%08X\n",SS,ESP); + cpl_override=1; + if (type>=0x800) + { +// if (output) pclog("Push 32 %i\n",eflags&VM_FLAG); + if (eflags & VM_FLAG) + { + PUSHL(GS); + PUSHL(FS); + PUSHL(DS); + PUSHL(ES); if (abrt) return; + loadseg(0,&_ds); + loadseg(0,&_es); + loadseg(0,&_fs); + loadseg(0,&_gs); + } + PUSHL(oldss); + PUSHL(oldsp); + PUSHL(flags|(eflags<<16)); +// if (soft) pclog("Pushl CS %08X\n", CS); + PUSHL(CS); +// if (soft) pclog("Pushl PC %08X\n", cpu_state.pc); + PUSHL(cpu_state.pc); if (abrt) return; +// if (output) pclog("32Stack %04X:%08X\n",SS,ESP); + } + else + { +// if (output) pclog("Push 16\n"); + PUSHW(oldss); + PUSHW(oldsp); + PUSHW(flags); +// if (soft) pclog("Pushw CS %04X\n", CS); + PUSHW(CS); +// if (soft) pclog("Pushw pc %04X\n", cpu_state.pc); + PUSHW(cpu_state.pc); if (abrt) return; +// if (output) pclog("16Stack %04X:%08X\n",SS,ESP); + } + cpl_override=0; + _cs.access=0 | 0x80; + cycles -= timing_int_pm_outer - timing_int_pm; +// pclog("Non-confirming int gate, CS = %04X\n"); + break; + } + else if (DPL2!=CPL) + { + pclog("Non-conforming int gate DPL != CPL\n"); + x86gpf(NULL,seg&~3); + return; + } + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + if (!(segdat2[2]&0x8000)) + { + pclog("Int gate CS not present\n"); + x86np("Int gate CS not present\n", segdat[1] & 0xfffc); + return; + } + if ((eflags & VM_FLAG) && DPL20x800) + { + PUSHL(flags|(eflags<<16)); +// if (soft) pclog("Pushlc CS %08X\n", CS); + PUSHL(CS); +// if (soft) pclog("Pushlc PC %08X\n", cpu_state.pc); + PUSHL(cpu_state.pc); if (abrt) return; + } + else + { + PUSHW(flags); +// if (soft) pclog("Pushwc CS %04X\n", CS); + PUSHW(CS); +// if (soft) pclog("Pushwc PC %04X\n", cpu_state.pc); + PUSHW(cpu_state.pc); if (abrt) return; + } + new_cpl = CS & 3; + break; + default: + pclog("Int gate CS not code segment - %04X %04X %04X %04X\n",segdat2[0],segdat2[1],segdat2[2],segdat2[3]); + x86gpf(NULL,seg&~3); + return; + } + do_seg_load(&_cs, segdat2); + CS = (seg & ~3) | new_cpl; + _cs.access = (_cs.access & ~(3 << 5)) | (new_cpl << 5); +// pclog("New CS = %04X\n",CS); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + if (type>0x800) cpu_state.pc=segdat[0]|(segdat[3]<<16); + else cpu_state.pc=segdat[0]; + use32=(segdat2[3]&0x40)?0x300:0; +// pclog("Int gate done!\n"); + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, oaddr+4, segdat2[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + + eflags&=~VM_FLAG; + if (!(type&0x100)) + { + flags&=~I_FLAG; +// pclog("INT %02X disabling interrupts %i\n",num,soft); + } + flags&=~(T_FLAG|NT_FLAG); +// if (output) pclog("Final Stack %04X:%08X\n",SS,ESP); + cycles -= timing_int_pm; + break; + + case 0x500: /*Task gate*/ +// pclog("Task gate\n"); + seg=segdat[1]; + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X INT\n",seg,gdt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X INT %i\n",seg,gdt.limit,ins); + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); + cpl_override=0; if (abrt) return; + if (!(segdat2[2]&0x8000)) + { + pclog("Int task gate not present\n"); + x86np("Int task gate not present\n", segdat[1] & 0xfffc); + return; + } + optype=OPTYPE_INT; + cpl_override=1; + taskswitch286(seg,segdat2,segdat2[2]&0x800); + cpl_override=0; + break; + + default: + pclog("Bad int gate type %04X %04X %04X %04X %04X\n",segdat[2]&0x1F00,segdat[0],segdat[1],segdat[2],segdat[3]); + x86gpf(NULL,seg&~3); + return; + } +} + +void pmodeiret(int is32) +{ + uint32_t newsp; + uint16_t newss; + uint32_t tempflags,flagmask; + uint32_t newpc; + uint16_t segdat[4],segdat2[4]; + uint16_t segs[4]; + uint16_t seg; + uint32_t addr, oaddr; + uint32_t oldsp=ESP; + if (is386 && (eflags&VM_FLAG)) + { +// if (output) pclog("V86 IRET\n"); + if (IOPL!=3) + { + pclog("V86 IRET! IOPL!=3\n"); + x86gpf(NULL,0); + return; + } + oxpc=cpu_state.pc; + if (is32) + { + newpc=POPL(); + seg=POPL(); + tempflags=POPL(); if (abrt) return; + } + else + { + newpc=POPW(); + seg=POPW(); + tempflags=POPW(); if (abrt) return; + } + cpu_state.pc=newpc; + _cs.base=seg<<4; + _cs.limit=0xFFFF; + _cs.limit_low = 0; + _cs.limit_high = 0xffff; + _cs.access |= 0x80; + CS=seg; + flags=(flags&0x3000)|(tempflags&0xCFD5)|2; + cycles -= timing_iret_rm; + return; + } + +// pclog("IRET %i\n",is32); + //flushmmucache(); +// if (output) pclog("Pmode IRET %04X:%04X ",CS,cpu_state.pc); + + if (flags&NT_FLAG) + { +// pclog("NT IRET\n"); + seg=readmemw(tr.base,0); + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + pclog("TS Bigger than LDT limit %04X %04X IRET\n",seg,gdt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("TS Bigger than GDT limit %04X %04X IRET\n",seg,gdt.limit); + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); + taskswitch286(seg,segdat,0); + cpl_override=0; + return; + } + oxpc=cpu_state.pc; + flagmask=0xFFFF; + if (CPL) flagmask&=~0x3000; + if (IOPL>16)&VM_FLAG)) + { +// pclog("IRETD to V86\n"); + + newsp=POPL(); + newss=POPL(); + segs[0]=POPL(); + segs[1]=POPL(); + segs[2]=POPL(); + segs[3]=POPL(); if (abrt) { ESP = oldsp; return; } +// pclog("Pop stack %04X:%04X\n",newss,newsp); + eflags=tempflags>>16; + loadseg(segs[0],&_es); + do_seg_v86_init(&_es); + loadseg(segs[1],&_ds); + do_seg_v86_init(&_ds); + loadseg(segs[2],&_fs); + do_seg_v86_init(&_fs); + loadseg(segs[3],&_gs); + do_seg_v86_init(&_gs); + +// pclog("V86 IRET %04X:%08X\n",SS,ESP); +// output=3; + + cpu_state.pc=newpc; + _cs.base=seg<<4; + _cs.limit=0xFFFF; + _cs.limit_low = 0; + _cs.limit_high = 0xffff; + CS=seg; + _cs.access=(3<<5) | 2 | 0x80; + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + + ESP=newsp; + loadseg(newss,&_ss); + do_seg_v86_init(&_ss); + use32=0; + flags=(tempflags&0xFFD5)|2; + cycles -= timing_iret_v86; +// pclog("V86 IRET to %04X:%04X %04X:%04X %04X %04X %04X %04X %i\n",CS,cpu_state.pc,SS,SP,DS,ES,FS,GS,abrt); + // if (CS==0xFFFF && pc==0xFFFFFFFF) timetolive=12; +/* { + dumpregs(); + exit(-1); + }*/ + return; + } + } + else + { + newpc=POPW(); + seg=POPW(); + tempflags=POPW(); if (abrt) { ESP = oldsp; return; } + } +// if (!is386) tempflags&=0xFFF; +// pclog("Returned to %04X:%08X %04X %04X %i\n",seg,newpc,flags,tempflags, ins); + if (!(seg&~3)) + { + pclog("IRET CS=0\n"); + ESP = oldsp; +// dumpregs(); +// exit(-1); + x86gpf(NULL,0); + return; + } + +// if (output) pclog("IRET %04X:%08X\n",seg,newpc); + addr=seg&~7; + if (seg&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X IRET\n",seg,gdt.limit); + ESP = oldsp; + x86gpf(NULL,seg&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X IRET\n",seg,gdt.limit); + ESP = oldsp; + x86gpf(NULL,seg&~3); + return; + } + addr+=gdt.base; + } + if ((seg&3) < CPL) + { + pclog("IRET to lower level\n"); + ESP = oldsp; + x86gpf(NULL,seg&~3); + return; + } + cpl_override=1; + segdat[0]=readmemw(0,addr); + segdat[1]=readmemw(0,addr+2); + segdat[2]=readmemw(0,addr+4); + segdat[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) { ESP = oldsp; return; } +// pclog("Seg type %04X %04X\n",segdat[2]&0x1F00,segdat[2]); + + switch (segdat[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming code*/ + if ((seg&3) != DPL) + { + pclog("IRET NC DPL %04X %04X %04X %04X %04X\n", seg, segdat[0], segdat[1], segdat[2], segdat[3]); + ESP = oldsp; +// dumpregs(); +// exit(-1); + x86gpf(NULL,seg&~3); + return; + } + break; + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming code*/ + if ((seg&3) < DPL) + { + pclog("IRET C DPL\n"); + ESP = oldsp; + x86gpf(NULL,seg&~3); + return; + } + break; + default: + pclog("IRET CS != code seg\n"); + ESP = oldsp; + x86gpf(NULL,seg&~3); +// dumpregs(); +// exit(-1); + return; + } + if (!(segdat[2]&0x8000)) + { + pclog("IRET CS not present %i %04X %04X %04X\n",ins, segdat[0], segdat[1], segdat[2]); + ESP = oldsp; + x86np("IRET CS not present\n", seg & 0xfffc); + return; + } +// pclog("Seg %04X CPL %04X\n",seg,CPL); + if ((seg&3) == CPL) + { +// pclog("Same level\n"); + CS=seg; + do_seg_load(&_cs, segdat); + _cs.access = (_cs.access & ~(3 << 5)) | ((CS & 3) << 5); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + use32=(segdat[3]&0x40)?0x300:0; + +#ifdef CS_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat[2] | 0x100); /*Set accessed bit*/ + cpl_override = 0; +#endif + cycles -= timing_iret_pm; + } + else /*Return to outer level*/ + { + oaddr = addr; + if (output) pclog("Outer level\n"); + if (is32) + { + newsp=POPL(); + newss=POPL(); if (abrt) { ESP = oldsp; return; } + } + else + { + newsp=POPW(); + newss=POPW(); if (abrt) { ESP = oldsp; return; } + } + + if (output) pclog("IRET load stack %04X:%04X\n",newss,newsp); + + if (!(newss&~3)) + { + pclog("IRET loading null SS\n"); + ESP = oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr=newss&~7; + if (newss&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X PMODEIRET SS\n",newss,gdt.limit); + ESP = oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X PMODEIRET\n",newss,gdt.limit); + ESP = oldsp; + x86gpf(NULL,newss&~3); + return; + } + addr+=gdt.base; + } + cpl_override=1; + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); cpl_override=0; if (abrt) { ESP = oldsp; return; } +// pclog("IRET SS sd2 %04X\n",segdat2[2]); +// if (((newss & 3) != DPL) || (DPL2 != DPL)) + if ((newss & 3) != (seg & 3)) + { + pclog("IRET loading SS with wrong permissions %04X %04X\n", newss, seg); + ESP = oldsp; +// dumpregs(); +// exit(-1); + x86gpf(NULL,newss&~3); + return; + } + if ((segdat2[2]&0x1A00)!=0x1200) + { + pclog("IRET loading SS wrong type\n"); + ESP = oldsp; + x86gpf(NULL,newss&~3); + return; + } + if (DPL2 != (seg & 3)) + { + pclog("IRET loading SS with wrong permissions2 %i %i %04X %04X\n", DPL2, seg & 3, newss, seg); + ESP = oldsp; + x86gpf(NULL,newss&~3); + return; + } + if (!(segdat2[2]&0x8000)) + { + pclog("IRET loading SS not present\n"); + ESP = oldsp; + x86np("IRET loading SS not present\n", newss & 0xfffc); + return; + } + SS=newss; + stack32 = (segdat2[3] & 0x40) ? 1 : 0; + if (stack32) ESP=newsp; + else SP=newsp; + do_seg_load(&_ss, segdat2); + +#ifdef SEL_ACCESSED + cpl_override = 1; + writememw(0, addr+4, segdat2[2] | 0x100); /*Set accessed bit*/ + +#ifdef CS_ACCESSED + writememw(0, oaddr+4, segdat[2] | 0x100); /*Set accessed bit*/ +#endif + cpl_override = 0; +#endif + /*Conforming segments don't change CPL, so CPL = RPL*/ + if (segdat[2]&0x400) + segdat[2] = (segdat[2] & ~(3 << (5+8))) | ((seg & 3) << (5+8)); + + CS=seg; + do_seg_load(&_cs, segdat); + _cs.access = (_cs.access & ~(3 << 5)) | ((CS & 3) << 5); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + use32=(segdat[3]&0x40)?0x300:0; + + check_seg_valid(&_ds); + check_seg_valid(&_es); + check_seg_valid(&_fs); + check_seg_valid(&_gs); + cycles -= timing_iret_pm_outer; + } + cpu_state.pc=newpc; + flags=(flags&~flagmask)|(tempflags&flagmask&0xFFD5)|2; + if (is32) eflags=tempflags>>16; +// pclog("done\n"); +} + +void taskswitch286(uint16_t seg, uint16_t *segdat, int is32) +{ + uint32_t base; + uint32_t limit; + uint32_t templ; + uint16_t tempw; + + uint32_t new_cr3=0; + uint16_t new_es,new_cs,new_ss,new_ds,new_fs,new_gs; + uint16_t new_ldt; + + uint32_t new_eax,new_ebx,new_ecx,new_edx,new_esp,new_ebp,new_esi,new_edi,new_pc,new_flags; + + uint32_t addr; + + uint16_t segdat2[4]; + +//output=3; + base=segdat[1]|((segdat[2]&0xFF)<<16)|((segdat[3]>>8)<<24); + limit=segdat[0]|((segdat[3]&0xF)<<16); +// pclog("286 Task switch! %04X:%04X\n",CS,cpu_state.pc); +/// pclog("TSS %04X base %08X limit %04X old TSS %04X %08X %i\n",seg,base,limit,tr.seg,tr.base,ins); +// / pclog("%04X %04X %04X %04X\n",segdat[0],segdat[1],segdat[2],segdat[3]); + + if (is386) + { +// if (output) pclog("32-bit TSS\n"); + + new_cr3=readmeml(base,0x1C); + new_pc=readmeml(base,0x20); + new_flags=readmeml(base,0x24); + + new_eax=readmeml(base,0x28); + new_ecx=readmeml(base,0x2C); + new_edx=readmeml(base,0x30); + new_ebx=readmeml(base,0x34); + new_esp=readmeml(base,0x38); + new_ebp=readmeml(base,0x3C); + new_esi=readmeml(base,0x40); + new_edi=readmeml(base,0x44); + + new_es=readmemw(base,0x48); +// if (output) pclog("Read CS from %08X\n",base+0x4C); + new_cs=readmemw(base,0x4C); + new_ss=readmemw(base,0x50); + new_ds=readmemw(base,0x54); + new_fs=readmemw(base,0x58); + new_gs=readmemw(base,0x5C); + new_ldt=readmemw(base,0x60); + + if (abrt) return; + if (optype==JMP || optype==OPTYPE_INT) + { + if (tr.seg&4) tempw=readmemw(ldt.base,(tr.seg&~7)+4); + else tempw=readmemw(gdt.base,(tr.seg&~7)+4); + if (abrt) return; + tempw&=~0x200; + if (tr.seg&4) writememw(ldt.base,(tr.seg&~7)+4,tempw); + else writememw(gdt.base,(tr.seg&~7)+4,tempw); + } + + if (optype==IRET) flags&=~NT_FLAG; + +// if (output) pclog("Write PC %08X %08X\n",tr.base,cpu_state.pc); + cpu_386_flags_rebuild(); + writememl(tr.base,0x1C,cr3); + writememl(tr.base,0x20,cpu_state.pc); + writememl(tr.base,0x24,flags|(eflags<<16)); + + writememl(tr.base,0x28,EAX); + writememl(tr.base,0x2C,ECX); + writememl(tr.base,0x30,EDX); + writememl(tr.base,0x34,EBX); + writememl(tr.base,0x38,ESP); + writememl(tr.base,0x3C,EBP); + writememl(tr.base,0x40,ESI); + writememl(tr.base,0x44,EDI); + + writememl(tr.base,0x48,ES); +// if (output) pclog("Write CS %04X to %08X\n",CS,tr.base+0x4C); + writememl(tr.base,0x4C,CS); + writememl(tr.base,0x50,SS); + writememl(tr.base,0x54,DS); + writememl(tr.base,0x58,FS); + writememl(tr.base,0x5C,GS); + writememl(tr.base,0x60,ldt.seg); + + if (optype==OPTYPE_INT) + { + writememl(base,0,tr.seg); + new_flags|=NT_FLAG; + } + if (abrt) return; + if (optype==JMP || optype==OPTYPE_INT) + { + if (tr.seg&4) tempw=readmemw(ldt.base,(seg&~7)+4); + else tempw=readmemw(gdt.base,(seg&~7)+4); + if (abrt) return; + tempw|=0x200; + if (tr.seg&4) writememw(ldt.base,(seg&~7)+4,tempw); + else writememw(gdt.base,(seg&~7)+4,tempw); + } + + + + cr3=new_cr3; +// pclog("TS New CR3 %08X\n",cr3); + flushmmucache(); + + + + cpu_state.pc=new_pc; +// if (output) pclog("New pc %08X\n",new_pc); + flags=new_flags; + eflags=new_flags>>16; + cpu_386_flags_extract(); + +// if (output) pclog("Load LDT %04X\n",new_ldt); + ldt.seg=new_ldt; + templ=(ldt.seg&~7)+gdt.base; +// if (output) pclog("Load from %08X %08X\n",templ,gdt.base); + ldt.limit=readmemw(0,templ); + if (readmemb(templ+6)&0x80) + { + ldt.limit<<=12; + ldt.limit|=0xFFF; + } + ldt.base=(readmemw(0,templ+2))|(readmemb(templ+4)<<16)|(readmemb(templ+7)<<24); +// if (output) pclog("Limit %04X Base %08X\n",ldt.limit,ldt.base); + + + if (eflags&VM_FLAG) + { + pclog("Task switch V86!\n"); + x86gpf(NULL,0); + return; + } + + if (!(new_cs&~3)) + { + pclog("TS loading null CS\n"); + x86gpf(NULL,0); + return; + } + addr=new_cs&~7; + if (new_cs&4) + { + if (addr>=ldt.limit) + { + pclog("Bigger than LDT limit %04X %04X %04X TS\n",new_cs,ldt.limit,addr); + x86gpf(NULL,0); + return; + } + addr+=ldt.base; + } + else + { + if (addr>=gdt.limit) + { + pclog("Bigger than GDT limit %04X %04X TS\n",new_cs,gdt.limit); + x86gpf(NULL,0); + return; + } + addr+=gdt.base; + } + segdat2[0]=readmemw(0,addr); + segdat2[1]=readmemw(0,addr+2); + segdat2[2]=readmemw(0,addr+4); + segdat2[3]=readmemw(0,addr+6); + if (!(segdat2[2]&0x8000)) + { + pclog("TS loading CS not present\n"); + x86np("TS loading CS not present\n", new_cs & 0xfffc); + return; + } + switch (segdat2[2]&0x1F00) + { + case 0x1800: case 0x1900: case 0x1A00: case 0x1B00: /*Non-conforming*/ + if ((new_cs&3) != DPL2) + { + pclog("TS load CS non-conforming RPL != DPL"); + x86gpf(NULL,new_cs&~3); + return; + } + break; + case 0x1C00: case 0x1D00: case 0x1E00: case 0x1F00: /*Conforming*/ + if ((new_cs&3) < DPL2) + { + pclog("TS load CS non-conforming RPL < DPL"); + x86gpf(NULL,new_cs&~3); + return; + } + break; + default: + pclog("TS load CS not code segment\n"); + x86gpf(NULL,new_cs&~3); + return; + } + +// if (output) pclog("new_cs %04X\n",new_cs); + CS=new_cs; + do_seg_load(&_cs, segdat2); + if (CPL==3 && oldcpl!=3) flushmmucache_cr3(); + use32=(segdat2[3]&0x40)?0x300:0; + + EAX=new_eax; + ECX=new_ecx; + EDX=new_edx; + EBX=new_ebx; + ESP=new_esp; + EBP=new_ebp; + ESI=new_esi; + EDI=new_edi; + + if (output) pclog("Load ES %04X\n",new_es); + loadseg(new_es,&_es); + if (output) pclog("Load SS %04X\n",new_ss); + loadseg(new_ss,&_ss); + if (output) pclog("Load DS %04X\n",new_ds); + loadseg(new_ds,&_ds); + if (output) pclog("Load FS %04X\n",new_fs); + loadseg(new_fs,&_fs); + if (output) pclog("Load GS %04X\n",new_gs); + loadseg(new_gs,&_gs); + + if (output) pclog("Resuming at %04X:%08X\n",CS,cpu_state.pc); + } + else + { + pclog("16-bit TSS\n"); + resetx86(); + //exit(-1); + } + + + tr.seg=seg; + tr.base=base; + tr.limit=limit; + tr.access=segdat[2]>>8; +} + diff --git a/src/x86seg.h b/src/x86seg.h new file mode 100644 index 000000000..daf10a46e --- /dev/null +++ b/src/x86seg.h @@ -0,0 +1 @@ +void do_seg_load(x86seg *s, uint16_t *segdat); diff --git a/src/x87.c b/src/x87.c new file mode 100644 index 000000000..277320383 --- /dev/null +++ b/src/x87.c @@ -0,0 +1,90 @@ +//Quake timedemo demo1 - 8.1FPS + +//11A00 - D_SCAlloc +//11C1C - D_CacheSurface + +//36174 - SCR_CalcRefdef + +//SCR_CalcRefdef +//Calls R_SetVrect and R_ViewChanged + +#define fplog 0 + +#include +#include "ibm.h" +#include "pic.h" +#include "x86.h" +#include "x86_flags.h" +#include "x86_ops.h" +#include "x87.h" +#include "386_common.h" + +double ST[8]; +uint64_t ST_i64[8]; +MMX_REG MM[8]; +int ismmx; +uint16_t npxs,npxc; +uint8_t tag[8]; + +int TOP; + +uint16_t x87_gettag() +{ + uint16_t ret = 0; + int c; + + for (c = 0; c < 8; c++) + { + if (tag[c] & TAG_UINT64) + ret |= 2 << (c*2); + else + ret |= (tag[c] << (c*2)); + } + + return ret; +} + +void x87_settag(uint16_t new_tag) +{ + tag[0] = new_tag & 3; + tag[1] = (new_tag >> 2) & 3; + tag[2] = (new_tag >> 4) & 3; + tag[3] = (new_tag >> 6) & 3; + tag[4] = (new_tag >> 8) & 3; + tag[5] = (new_tag >> 10) & 3; + tag[6] = (new_tag >> 12) & 3; + tag[7] = (new_tag >> 14) & 3; +} + +void x87_dumpregs() +{ + if (ismmx) + { + pclog("MM0=%016llX\tMM1=%016llX\tMM2=%016llX\tMM3=%016llX\n", MM[0].q, MM[1].q, MM[2].q, MM[3].q); + pclog("MM4=%016llX\tMM5=%016llX\tMM6=%016llX\tMM7=%016llX\n", MM[4].q, MM[5].q, MM[6].q, MM[7].q); + } + else + { + pclog("ST(0)=%f\tST(1)=%f\tST(2)=%f\tST(3)=%f\t\n",ST[TOP],ST[(TOP+1)&7],ST[(TOP+2)&7],ST[(TOP+3)&7]); + pclog("ST(4)=%f\tST(5)=%f\tST(6)=%f\tST(7)=%f\t\n",ST[(TOP+4)&7],ST[(TOP+5)&7],ST[(TOP+6)&7],ST[(TOP+7)&7]); + } + pclog("Status = %04X Control = %04X Tag = %04X\n",npxs,npxc,x87_gettag()); +} + +void x87_print() +{ + if (ismmx) + { + pclog("\tMM0=%016llX\tMM1=%016llX\tMM2=%016llX\tMM3=%016llX\t", MM[0].q, MM[1].q, MM[2].q, MM[3].q); + pclog("MM4=%016llX\tMM5=%016llX\tMM6=%016llX\tMM7=%016llX\n", MM[4].q, MM[5].q, MM[6].q, MM[7].q); + } + else + { + pclog("\tST(0)=%.20f\tST(1)=%.20f\tST(2)=%f\tST(3)=%f\t",ST[TOP&7],ST[(TOP+1)&7],ST[(TOP+2)&7],ST[(TOP+3)&7]); + pclog("ST(4)=%f\tST(5)=%f\tST(6)=%f\tST(7)=%f\t TOP=%i CR=%04X SR=%04X TAG=%04X\n",ST[(TOP+4)&7],ST[(TOP+5)&7],ST[(TOP+6)&7],ST[(TOP+7)&7], TOP, npxc, npxs, x87_gettag()); + } +} + +void x87_reset() +{ +} diff --git a/src/x87.h b/src/x87.h new file mode 100644 index 000000000..1c58ba189 --- /dev/null +++ b/src/x87.h @@ -0,0 +1,32 @@ +uint32_t x87_pc_off,x87_op_off; +uint16_t x87_pc_seg,x87_op_seg; +extern uint32_t op32; +extern int TOP; +extern uint16_t npxs, npxc; +extern uint8_t tag[8]; +extern int ismmx; +extern double ST[8]; +extern uint64_t ST_i64[8]; + +typedef union MMX_REG +{ + uint64_t q; + int64_t sq; + uint32_t l[2]; + int32_t sl[2]; + uint16_t w[5]; + int16_t sw[4]; + uint8_t b[8]; + int8_t sb[8]; +} MMX_REG; + +extern MMX_REG MM[8]; + +static inline void x87_set_mmx(); +static inline void x87_emms(); + +uint16_t x87_gettag(); +void x87_settag(uint16_t new_tag); + +/*Hack for FPU copy. If set then ST_i64 contains the 64-bit integer loaded by FILD*/ +#define TAG_UINT64 (1 << 2) diff --git a/src/x87_ops.h b/src/x87_ops.h new file mode 100644 index 000000000..6a1fadca3 --- /dev/null +++ b/src/x87_ops.h @@ -0,0 +1,1127 @@ +#include +#include + +#define fplog 0 + +static int rounding_modes[4] = {FE_TONEAREST, FE_DOWNWARD, FE_UPWARD, FE_TOWARDZERO}; + +#define ST(x) ST[((TOP+(x))&7)] + +#define C0 (1<<8) +#define C1 (1<<9) +#define C2 (1<<10) +#define C3 (1<<14) + +#define STATUS_ZERODIVIDE 4 + +#define x87_div(dst, src1, src2) do \ + { \ + if (((double)src2) == 0.0) \ + { \ + npxs |= STATUS_ZERODIVIDE; \ + if (npxc & STATUS_ZERODIVIDE) \ + dst = src1 / (double)src2; \ + else \ + { \ + pclog("FPU : divide by zero\n"); \ + picint(1 << 13); \ + } \ + return 1; \ + } \ + else \ + dst = src1 / (double)src2; \ + } while (0) + +static inline void x87_set_mmx() +{ + TOP = 0; + *(uint64_t *)tag = 0; + ismmx = 1; +} + +static inline void x87_emms() +{ + *tag = 0x0303030303030303ll; + ismmx = 0; +} + +static inline void x87_checkexceptions() +{ +} + +static inline void x87_push(double i) +{ + TOP=(TOP-1)&7; + ST[TOP]=i; + tag[TOP&7] = (i == 0.0) ? 1 : 0; +} + +static inline double x87_pop() +{ + double t=ST[TOP]; + tag[TOP&7] = 3; + TOP=(TOP+1)&7; + return t; +} + +static inline int64_t x87_fround(double b) +{ + int64_t a, c; + + switch ((npxc>>10)&3) + { + case 0: /*Nearest*/ + a = (int64_t)floor(b); + c = (int64_t)floor(b + 1.0); + if ((b - a) < (c - b)) + return a; + else if ((b - a) > (c - b)) + return c; + else + return (a & 1) ? c : a; + case 1: /*Down*/ + return (int64_t)floor(b); + case 2: /*Up*/ + return (int64_t)ceil(b); + case 3: /*Chop*/ + return (int64_t)b; + } +} +#define BIAS80 16383 +#define BIAS64 1023 + +static inline double x87_ld80() +{ + struct { + int16_t begin; + union + { + double d; + uint64_t ll; + } eind; + } test; + test.eind.ll = readmeml(easeg,eaaddr); + test.eind.ll |= (uint64_t)readmeml(easeg,eaaddr+4)<<32; + test.begin = readmemw(easeg,eaaddr+8); + + int64_t exp64 = (((test.begin&0x7fff) - BIAS80)); + int64_t blah = ((exp64 >0)?exp64:-exp64)&0x3ff; + int64_t exp64final = ((exp64 >0)?blah:-blah) +BIAS64; + + int64_t mant64 = (test.eind.ll >> 11) & (0xfffffffffffff); + int64_t sign = (test.begin&0x8000)?1:0; + + if ((test.begin & 0x7fff) == 0x7fff) + exp64final = 0x7ff; + if ((test.begin & 0x7fff) == 0) + exp64final = 0; + if (test.eind.ll & 0x400) + mant64++; + + test.eind.ll = (sign <<63)|(exp64final << 52)| mant64; + + return test.eind.d; +} + +static inline void x87_st80(double d) +{ + struct { + int16_t begin; + union + { + double d; + uint64_t ll; + } eind; + } test; + + test.eind.d=d; + + int64_t sign80 = (test.eind.ll&(0x8000000000000000))?1:0; + int64_t exp80 = test.eind.ll&(0x7ff0000000000000); + int64_t exp80final = (exp80>>52); + int64_t mant80 = test.eind.ll&(0x000fffffffffffff); + int64_t mant80final = (mant80 << 11); + + if (exp80final == 0x7ff) /*Infinity / Nan*/ + { + exp80final = 0x7fff; + mant80final |= (0x8000000000000000); + } + else if (d != 0){ //Zero is a special case + // Elvira wants the 8 and tcalc doesn't + mant80final |= (0x8000000000000000); + //Ca-cyber doesn't like this when result is zero. + exp80final += (BIAS80 - BIAS64); + } + test.begin = (((int16_t)sign80)<<15)| (int16_t)exp80final; + test.eind.ll = mant80final; + + writememl(easeg,eaaddr,test.eind.ll); + writememl(easeg,eaaddr+4,test.eind.ll>>32); + writememw(easeg,eaaddr+8,test.begin); +} + +static inline void x87_st_fsave(int reg) +{ + reg = (TOP + reg) & 7; + + if (tag[reg] & TAG_UINT64) + { + writememl(easeg, eaaddr, ST_i64[reg] & 0xffffffff); + writememl(easeg, eaaddr + 4, ST_i64[reg] >> 32); + writememw(easeg, eaaddr + 8, 0x5555); + } + else + x87_st80(ST[reg]); +} + +static inline void x87_ld_frstor(int reg) +{ + uint16_t temp; + + reg = (TOP + reg) & 7; + + temp = readmemw(easeg, eaaddr + 8); + + if (temp == 0x5555 && tag[reg] == 2) + { + tag[reg] = TAG_UINT64; + ST_i64[reg] = readmeml(easeg, eaaddr); + ST_i64[reg] |= ((uint64_t)readmeml(easeg, eaaddr + 4) << 32); + ST[reg] = (double)ST_i64[reg]; + } + else + ST[reg] = x87_ld80(); +} + +static inline void x87_ldmmx(MMX_REG *r) +{ + r->l[0] = readmeml(easeg, eaaddr); + r->l[1] = readmeml(easeg, eaaddr + 4); + r->w[4] = readmemw(easeg, eaaddr + 8); +} + +static inline void x87_stmmx(MMX_REG r) +{ + writememl(easeg, eaaddr, r.l[0]); + writememl(easeg, eaaddr + 4, r.l[1]); + writememw(easeg, eaaddr + 8, 0xffff); +} + +static inline uint16_t x87_compare(double a, double b) +{ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 + uint32_t out; + + /* Memory barrier, to force GCC to write to the input parameters + * before the compare rather than after */ + asm volatile ("" : : : "memory"); + + asm( + "fldl %2\n" + "fldl %1\n" + "fclex\n" + "fcompp\n" + "fnstsw %0\n" + : "=m" (out) + : "m" (a), "m" (b) + ); + + return out & (C0|C2|C3); +#else + /* Generic C version is known to give incorrect results in some + * situations, eg comparison of infinity (Unreal) */ + uint32_t out = 0; + + if (a == b) + out |= C3; + else if (a < b) + out |= C0; + + return out; +#endif +} + +static inline uint16_t x87_ucompare(double a, double b) +{ +#if defined i386 || defined __i386 || defined __i386__ || defined _X86_ || defined WIN32 || defined _WIN32 || defined _WIN32 + uint32_t out; + + /* Memory barrier, to force GCC to write to the input parameters + * before the compare rather than after */ + asm volatile ("" : : : "memory"); + + asm( + "fldl %2\n" + "fldl %1\n" + "fclex\n" + "fucompp\n" + "fnstsw %0\n" + : "=m" (out) + : "m" (a), "m" (b) + ); + + return out & (C0|C2|C3); +#else + /* Generic C version is known to give incorrect results in some + * situations, eg comparison of infinity (Unreal) */ + uint32_t out = 0; + + if (a == b) + out |= C3; + else if (a < b) + out |= C0; + + return out; +#endif +} + +typedef union +{ + float s; + uint32_t i; +} x87_ts; + +typedef union +{ + double d; + uint64_t i; +} x87_td; + +#define FP_ENTER() do \ + { \ + flags_rebuild(); \ + if (cr0 & 0xc) \ + { \ + x86_int(7); \ + return 1; \ + } \ + fpucount++; \ + } while (0) + +#include "x87_ops_arith.h" +#include "x87_ops_misc.h" +#include "x87_ops_loadstore.h" + +static int op_nofpu_a16(uint32_t fetchdat) +{ + if (cr0 & 0xc) + { + x86_int(7); + return 1; + } + else + fetch_ea_16(fetchdat); +} +static int op_nofpu_a32(uint32_t fetchdat) +{ + if (cr0 & 0xc) + { + x86_int(7); + return 1; + } + else + fetch_ea_32(fetchdat); +} + +OpFn OP_TABLE(fpu_d8_a16)[32] = +{ + opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, + opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, + opFADDs_a16, opFMULs_a16, opFCOMs_a16, opFCOMPs_a16, opFSUBs_a16, opFSUBRs_a16, opFDIVs_a16, opFDIVRs_a16, + opFADD, opFMUL, opFCOM, opFCOMP, opFSUB, opFSUBR, opFDIV, opFDIVR +}; +OpFn OP_TABLE(fpu_d8_a32)[32] = +{ + opFADDs_a32, opFMULs_a32, opFCOMs_a32, opFCOMPs_a32, opFSUBs_a32, opFSUBRs_a32, opFDIVs_a32, opFDIVRs_a32, + opFADDs_a32, opFMULs_a32, opFCOMs_a32, opFCOMPs_a32, opFSUBs_a32, opFSUBRs_a32, opFDIVs_a32, opFDIVRs_a32, + opFADDs_a32, opFMULs_a32, opFCOMs_a32, opFCOMPs_a32, opFSUBs_a32, opFSUBRs_a32, opFDIVs_a32, opFDIVRs_a32, + opFADD, opFMUL, opFCOM, opFCOMP, opFSUB, opFSUBR, opFDIV, opFDIVR +}; + +OpFn OP_TABLE(fpu_d9_a16)[256] = +{ + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, opFLDs_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, opFSTs_a16, + opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, opFSTPs_a16, + opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, opFLDENV_a16, + opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, opFLDCW_a16, + opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, opFSTENV_a16, + opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, opFSTCW_a16, + + opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFNOP, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, /*Invalid*/ + opFCHS, opFABS, ILLEGAL, ILLEGAL, opFTST, opFXAM, ILLEGAL, ILLEGAL, + opFLD1, opFLDL2T, opFLDL2E, opFLDPI, opFLDEG2, opFLDLN2, opFLDZ, ILLEGAL, + opF2XM1, opFYL2X, opFPTAN, opFPATAN, ILLEGAL, opFPREM1, opFDECSTP, opFINCSTP, + opFPREM, opFYL2XP1,opFSQRT, opFSINCOS, opFRNDINT, opFSCALE, opFSIN, opFCOS +}; + +OpFn OP_TABLE(fpu_d9_a32)[256] = +{ + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, opFLDs_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, opFSTs_a32, + opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, opFSTPs_a32, + opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, opFLDENV_a32, + opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, opFLDCW_a32, + opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, opFSTENV_a32, + opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, opFSTCW_a32, + + opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, opFLD, + opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, opFXCH, + opFNOP, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, /*Invalid*/ + opFCHS, opFABS, ILLEGAL, ILLEGAL, opFTST, opFXAM, ILLEGAL, ILLEGAL, + opFLD1, opFLDL2T, opFLDL2E, opFLDPI, opFLDEG2, opFLDLN2, opFLDZ, ILLEGAL, + opF2XM1, opFYL2X, opFPTAN, opFPATAN, ILLEGAL, opFPREM1, opFDECSTP, opFINCSTP, + opFPREM, opFYL2XP1,opFSQRT, opFSINCOS, opFRNDINT, opFSCALE, opFSIN, opFCOS +}; + +OpFn OP_TABLE(fpu_da_a16)[256] = +{ + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, opFUCOMPP, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; +OpFn OP_TABLE(fpu_da_a32)[256] = +{ + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, opFUCOMPP, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +OpFn OP_TABLE(fpu_686_da_a16)[256] = +{ + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, opFADDil_a16, + opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, opFMULil_a16, + opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, opFCOMil_a16, + opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, opFCOMPil_a16, + opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, opFSUBil_a16, + opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, opFSUBRil_a16, + opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, opFDIVil_a16, + opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, opFDIVRil_a16, + + opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, + opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, + opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, + opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, opFUCOMPP, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; +OpFn OP_TABLE(fpu_686_da_a32)[256] = +{ + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, opFADDil_a32, + opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, opFMULil_a32, + opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, opFCOMil_a32, + opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, opFCOMPil_a32, + opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, opFSUBil_a32, + opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, opFSUBRil_a32, + opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, opFDIVil_a32, + opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, opFDIVRil_a32, + + opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, opFCMOVB, + opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, opFCMOVE, + opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, opFCMOVBE, + opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, opFCMOVU, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, opFUCOMPP, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +OpFn OP_TABLE(fpu_db_a16)[256] = +{ + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; +OpFn OP_TABLE(fpu_db_a32)[256] = +{ + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +OpFn OP_TABLE(fpu_686_db_a16)[256] = +{ + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, opFILDil_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, opFISTil_a16, + opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, opFISTPil_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, opFLDe_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, opFSTPe_a16, + + opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, + opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, + opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, + opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, + ILLEGAL, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL, ILLEGAL, + opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, + opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; +OpFn OP_TABLE(fpu_686_db_a32)[256] = +{ + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, opFILDil_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, opFISTil_a32, + opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, opFISTPil_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, opFLDe_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, opFSTPe_a32, + + opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, opFCMOVNB, + opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, opFCMOVNE, + opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, opFCMOVNBE, + opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, opFCMOVNU, + ILLEGAL, opFNOP, opFCLEX, opFINIT, opFNOP, opFNOP, ILLEGAL, ILLEGAL, + opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, opFUCOMI, + opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, opFCOMI, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +OpFn OP_TABLE(fpu_dc_a16)[32] = +{ + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDd_a16, opFMULd_a16, opFCOMd_a16, opFCOMPd_a16, opFSUBd_a16, opFSUBRd_a16, opFDIVd_a16, opFDIVRd_a16, + opFADDr, opFMULr, opFCOM, opFCOMP, opFSUBRr, opFSUBr, opFDIVRr, opFDIVr +}; +OpFn OP_TABLE(fpu_dc_a32)[32] = +{ + opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, + opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, + opFADDd_a32, opFMULd_a32, opFCOMd_a32, opFCOMPd_a32, opFSUBd_a32, opFSUBRd_a32, opFDIVd_a32, opFDIVRd_a32, + opFADDr, opFMULr, opFCOM, opFCOMP, opFSUBRr, opFSUBr, opFDIVRr, opFDIVr +}; + +OpFn OP_TABLE(fpu_dd_a16)[256] = +{ + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, opFLDd_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, opFSTd_a16, + opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, opFSTPd_a16, + opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, opFSTOR_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, opFSAVE_a16, + opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, opFSTSW_a16, + + opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFST, opFST, opFST, opFST, opFST, opFST, opFST, opFST, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, + opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; +OpFn OP_TABLE(fpu_dd_a32)[256] = +{ + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, opFLDd_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, opFSTd_a32, + opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, opFSTPd_a32, + opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, opFSTOR_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, opFSAVE_a32, + opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, opFSTSW_a32, + + opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, opFFREE, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFST, opFST, opFST, opFST, opFST, opFST, opFST, opFST, + opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, opFSTP, + opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, opFUCOM, + opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, opFUCOMP, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +OpFn OP_TABLE(fpu_de_a16)[256] = +{ + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, opFADDiw_a16, + opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, opFMULiw_a16, + opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, opFCOMiw_a16, + opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, opFCOMPiw_a16, + opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, opFSUBiw_a16, + opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, opFSUBRiw_a16, + opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, opFDIViw_a16, + opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, opFDIVRiw_a16, + + opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, + opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, opFCOMPP, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, + opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, + opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, + opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, +}; + +OpFn OP_TABLE(fpu_de_a32)[256] = +{ + opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, + opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, + opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, + opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, + opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, + opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, + opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, + opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, + + opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, + opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, + opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, + opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, + opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, + opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, + opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, + opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, + + opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, opFADDiw_a32, + opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, opFMULiw_a32, + opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, opFCOMiw_a32, + opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, opFCOMPiw_a32, + opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, opFSUBiw_a32, + opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, opFSUBRiw_a32, + opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, opFDIViw_a32, + opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, opFDIVRiw_a32, + + opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, opFADDP, + opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, opFMULP, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, opFCOMPP, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, opFSUBRP, + opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, opFSUBP, + opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, opFDIVRP, + opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, opFDIVP, +}; + +OpFn OP_TABLE(fpu_df_a16)[256] = +{ + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTSW_AX, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; +OpFn OP_TABLE(fpu_df_a32)[256] = +{ + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTSW_AX, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +OpFn OP_TABLE(fpu_686_df_a16)[256] = +{ + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, opFILDiw_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, opFISTiw_a16, + opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, opFISTPiw_a16, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, opFILDiq_a16, + FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, FBSTP_a16, + FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, FISTPiq_a16, + + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTSW_AX, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, + opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; +OpFn OP_TABLE(fpu_686_df_a32)[256] = +{ + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, opFILDiw_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, opFISTiw_a32, + opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, opFISTPiw_a32, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, opFILDiq_a32, + FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, FBSTP_a32, + FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, FISTPiq_a32, + + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFSTSW_AX, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, + opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, opFUCOMIP, + opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, opFCOMIP, + ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, ILLEGAL, +}; + +OpFn OP_TABLE(nofpu_a16)[256] = +{ + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, + op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, op_nofpu_a16, +}; +OpFn OP_TABLE(nofpu_a32)[256] = +{ + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, + op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, op_nofpu_a32, +}; diff --git a/src/x87_ops_arith.h b/src/x87_ops_arith.h new file mode 100644 index 000000000..6e8fb4659 --- /dev/null +++ b/src/x87_ops_arith.h @@ -0,0 +1,428 @@ +#define opFPU(name, optype, a_size, load_var, get, use_var) \ +static int opFADD ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + load_var = get(); if (abrt) return 1; \ + if ((npxc >> 10) & 3) \ + fesetround(rounding_modes[(npxc >> 10) & 3]); \ + ST(0) += use_var; \ + if ((npxc >> 10) & 3) \ + fesetround(FE_TONEAREST); \ + tag[TOP] &= ~TAG_UINT64; \ + CLOCK_CYCLES(8); \ + return 0; \ +} \ +static int opFCOM ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + load_var = get(); if (abrt) return 1; \ + npxs &= ~(C0|C2|C3); \ + npxs |= x87_compare(ST(0), (double)use_var); \ + CLOCK_CYCLES(4); \ + return 0; \ +} \ +static int opFCOMP ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + load_var = get(); if (abrt) return 1; \ + npxs &= ~(C0|C2|C3); \ + npxs |= x87_compare(ST(0), (double)use_var); \ + x87_pop(); \ + CLOCK_CYCLES(4); \ + return 0; \ +} \ +static int opFDIV ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + load_var = get(); if (abrt) return 1; \ + x87_div(ST(0), ST(0), use_var); \ + tag[TOP] &= ~TAG_UINT64; \ + CLOCK_CYCLES(73); \ + return 0; \ +} \ +static int opFDIVR ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + load_var = get(); if (abrt) return 1; \ + x87_div(ST(0), use_var, ST(0)); \ + tag[TOP] &= ~TAG_UINT64; \ + CLOCK_CYCLES(73); \ + return 0; \ +} \ +static int opFMUL ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + load_var = get(); if (abrt) return 1; \ + ST(0) *= use_var; \ + tag[TOP] &= ~TAG_UINT64; \ + CLOCK_CYCLES(11); \ + return 0; \ +} \ +static int opFSUB ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + load_var = get(); if (abrt) return 1; \ + ST(0) -= use_var; \ + tag[TOP] &= ~TAG_UINT64; \ + CLOCK_CYCLES(8); \ + return 0; \ +} \ +static int opFSUBR ## name ## _a ## a_size(uint32_t fetchdat) \ +{ \ + optype t; \ + FP_ENTER(); \ + fetch_ea_ ## a_size(fetchdat); \ + load_var = get(); if (abrt) return 1; \ + ST(0) = use_var - ST(0); \ + tag[TOP] &= ~TAG_UINT64; \ + CLOCK_CYCLES(8); \ + return 0; \ +} + + +opFPU(s, x87_ts, 16, t.i, geteal, t.s) +opFPU(s, x87_ts, 32, t.i, geteal, t.s) +opFPU(d, x87_td, 16, t.i, geteaq, t.d) +opFPU(d, x87_td, 32, t.i, geteaq, t.d) + +opFPU(iw, uint16_t, 16, t, geteaw, (double)(int16_t)t) +opFPU(iw, uint16_t, 32, t, geteaw, (double)(int16_t)t) +opFPU(il, uint32_t, 16, t, geteal, (double)(int32_t)t) +opFPU(il, uint32_t, 32, t, geteal, (double)(int32_t)t) + + + + +static int opFADD(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FADD\n"); + ST(0) = ST(0) + ST(fetchdat & 7); + tag[TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(8); + return 0; +} +static int opFADDr(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FADD\n"); + ST(fetchdat & 7) = ST(fetchdat & 7) + ST(0); + tag[(TOP + fetchdat) & 7] &= ~TAG_UINT64; + CLOCK_CYCLES(8); + return 0; +} +static int opFADDP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FADDP\n"); + ST(fetchdat & 7) = ST(fetchdat & 7) + ST(0); + tag[(TOP + fetchdat) & 7] &= ~TAG_UINT64; + x87_pop(); + CLOCK_CYCLES(8); + return 0; +} + +static int opFCOM(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FCOM\n"); + npxs &= ~(C0|C2|C3); + if (ST(0) == ST(fetchdat & 7)) npxs |= C3; + else if (ST(0) < ST(fetchdat & 7)) npxs |= C0; + CLOCK_CYCLES(4); + return 0; +} + +static int opFCOMP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FCOMP\n"); + npxs &= ~(C0|C2|C3); + npxs |= x87_compare(ST(0), ST(fetchdat & 7)); + x87_pop(); + CLOCK_CYCLES(4); + return 0; +} + +static int opFCOMPP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FCOMPP\n"); + npxs &= ~(C0|C2|C3); + if (*(uint64_t *)&ST(0) == ((uint64_t)1 << 63) && *(uint64_t *)&ST(1) == 0) + npxs |= C0; /*Nasty hack to fix 80387 detection*/ + else + npxs |= x87_compare(ST(0), ST(1)); + + x87_pop(); + x87_pop(); + CLOCK_CYCLES(4); + return 0; +} +static int opFUCOMPP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FUCOMPP\n", easeg, eaaddr); + npxs &= ~(C0|C2|C3); + npxs |= x87_ucompare(ST(0), ST(1)); + x87_pop(); + x87_pop(); + CLOCK_CYCLES(5); + return 0; +} + +static int opFCOMI(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FICOM\n"); + flags_rebuild(); + flags &= ~(Z_FLAG | P_FLAG | C_FLAG); + if (ST(0) == ST(fetchdat & 7)) flags |= Z_FLAG; + else if (ST(0) < ST(fetchdat & 7)) flags |= C_FLAG; + CLOCK_CYCLES(4); + return 0; +} +static int opFCOMIP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FICOMP\n"); + flags_rebuild(); + flags &= ~(Z_FLAG | P_FLAG | C_FLAG); + if (ST(0) == ST(fetchdat & 7)) flags |= Z_FLAG; + else if (ST(0) < ST(fetchdat & 7)) flags |= C_FLAG; + x87_pop(); + CLOCK_CYCLES(4); + return 0; +} + +static int opFDIV(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FDIV\n"); + x87_div(ST(0), ST(0), ST(fetchdat & 7)); + tag[TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(73); + return 0; +} +static int opFDIVr(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FDIV\n"); + x87_div(ST(fetchdat & 7), ST(fetchdat & 7), ST(0)); + tag[(TOP + fetchdat) & 7] &= ~TAG_UINT64; + CLOCK_CYCLES(73); + return 0; +} +static int opFDIVP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FDIVP\n"); + x87_div(ST(fetchdat & 7), ST(fetchdat & 7), ST(0)); + tag[(TOP + fetchdat) & 7] &= ~TAG_UINT64; + x87_pop(); + CLOCK_CYCLES(73); + return 0; +} + +static int opFDIVR(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FDIVR\n"); + x87_div(ST(0), ST(fetchdat&7), ST(0)); + tag[TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(73); + return 0; +} +static int opFDIVRr(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FDIVR\n"); + x87_div(ST(fetchdat & 7), ST(0), ST(fetchdat & 7)); + tag[(TOP + fetchdat) & 7] &= ~TAG_UINT64; + CLOCK_CYCLES(73); + return 0; +} +static int opFDIVRP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FDIVR\n"); + x87_div(ST(fetchdat & 7), ST(0), ST(fetchdat & 7)); + tag[(TOP + fetchdat) & 7] &= ~TAG_UINT64; + x87_pop(); + CLOCK_CYCLES(73); + return 0; +} + +static int opFMUL(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FMUL\n"); + ST(0) = ST(0) * ST(fetchdat & 7); + tag[TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(16); + return 0; +} +static int opFMULr(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FMUL\n"); + ST(fetchdat & 7) = ST(0) * ST(fetchdat & 7); + tag[(TOP + fetchdat) & 7] &= ~TAG_UINT64; + CLOCK_CYCLES(16); + return 0; +} +static int opFMULP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FMULP\n"); + ST(fetchdat & 7) = ST(0) * ST(fetchdat & 7); + tag[(TOP + fetchdat) & 7] &= ~TAG_UINT64; + x87_pop(); + CLOCK_CYCLES(16); + return 0; +} + +static int opFSUB(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSUB\n"); + ST(0) = ST(0) - ST(fetchdat & 7); + tag[TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(8); + return 0; +} +static int opFSUBr(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSUB\n"); + ST(fetchdat & 7) = ST(fetchdat & 7) - ST(0); + tag[(TOP + fetchdat) & 7] &= ~TAG_UINT64; + CLOCK_CYCLES(8); + return 0; +} +static int opFSUBP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSUBP\n"); + ST(fetchdat & 7) = ST(fetchdat & 7) - ST(0); + tag[(TOP + fetchdat) & 7] &= ~TAG_UINT64; + x87_pop(); + CLOCK_CYCLES(8); + return 0; +} + +static int opFSUBR(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSUBR\n"); + ST(0) = ST(fetchdat & 7) - ST(0); + tag[TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(8); + return 0; +} +static int opFSUBRr(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSUBR\n"); + ST(fetchdat & 7) = ST(0) - ST(fetchdat & 7); + tag[(TOP + fetchdat) & 7] &= ~TAG_UINT64; + CLOCK_CYCLES(8); + return 0; +} +static int opFSUBRP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSUBRP\n"); + ST(fetchdat & 7) = ST(0) - ST(fetchdat & 7); + tag[(TOP + fetchdat) & 7] &= ~TAG_UINT64; + x87_pop(); + CLOCK_CYCLES(8); + return 0; +} + +static int opFUCOM(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FUCOM\n"); + npxs &= ~(C0|C2|C3); + npxs |= x87_ucompare(ST(0), ST(fetchdat & 7)); + CLOCK_CYCLES(4); + return 0; +} + +static int opFUCOMP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FUCOMP\n"); + npxs &= ~(C0|C2|C3); + npxs |= x87_ucompare(ST(0), ST(fetchdat & 7)); + x87_pop(); + CLOCK_CYCLES(4); + return 0; +} + +static int opFUCOMI(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FUCOMI\n"); + flags_rebuild(); + flags &= ~(Z_FLAG | P_FLAG | C_FLAG); + if (ST(0) == ST(fetchdat & 7)) flags |= Z_FLAG; + else if (ST(0) < ST(fetchdat & 7)) flags |= C_FLAG; + CLOCK_CYCLES(4); + return 0; +} +static int opFUCOMIP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FUCOMIP\n"); + flags_rebuild(); + flags &= ~(Z_FLAG | P_FLAG | C_FLAG); + if (ST(0) == ST(fetchdat & 7)) flags |= Z_FLAG; + else if (ST(0) < ST(fetchdat & 7)) flags |= C_FLAG; + x87_pop(); + CLOCK_CYCLES(4); + return 0; +} diff --git a/src/x87_ops_loadstore.h b/src/x87_ops_loadstore.h new file mode 100644 index 000000000..bede280b9 --- /dev/null +++ b/src/x87_ops_loadstore.h @@ -0,0 +1,470 @@ +static int opFILDiw_a16(uint32_t fetchdat) +{ + int16_t temp; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FILDw %08X:%08X\n", easeg, eaaddr); + temp = geteaw(); if (abrt) return 1; + if (fplog) pclog(" %f\n", (double)temp); + x87_push((double)temp); + CLOCK_CYCLES(13); + return 0; +} +static int opFILDiw_a32(uint32_t fetchdat) +{ + int16_t temp; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FILDw %08X:%08X\n", easeg, eaaddr); + temp = geteaw(); if (abrt) return 1; + if (fplog) pclog(" %f\n", (double)temp); + x87_push((double)temp); + CLOCK_CYCLES(13); + return 0; +} + +static int opFISTiw_a16(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FISTw %08X:%08X\n", easeg, eaaddr); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 32767 || temp64 < -32768) + fatal("FISTw overflow %i\n", temp64);*/ + seteaw((int16_t)temp64); + CLOCK_CYCLES(29); + return abrt; +} +static int opFISTiw_a32(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FISTw %08X:%08X\n", easeg, eaaddr); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 32767 || temp64 < -32768) + fatal("FISTw overflow %i\n", temp64);*/ + seteaw((int16_t)temp64); + CLOCK_CYCLES(29); + return abrt; +} + +static int opFISTPiw_a16(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FISTw %08X:%08X\n", easeg, eaaddr); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 32767 || temp64 < -32768) + fatal("FISTw overflow %i\n", temp64);*/ + seteaw((int16_t)temp64); if (abrt) return 1; + x87_pop(); + CLOCK_CYCLES(29); + return 0; +} +static int opFISTPiw_a32(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FISTw %08X:%08X\n", easeg, eaaddr); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 32767 || temp64 < -32768) + fatal("FISTw overflow %i\n", temp64);*/ + seteaw((int16_t)temp64); if (abrt) return 1; + x87_pop(); + CLOCK_CYCLES(29); + return 0; +} + +static int opFILDiq_a16(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FILDl %08X:%08X\n", easeg, eaaddr); + temp64 = geteaq(); if (abrt) return 1; + if (fplog) pclog(" %f %08X %08X\n", (double)temp64, readmeml(easeg,eaaddr), readmeml(easeg,eaaddr+4)); + x87_push((double)temp64); + ST_i64[TOP] = temp64; + tag[TOP] |= TAG_UINT64; + + CLOCK_CYCLES(10); + return 0; +} +static int opFILDiq_a32(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FILDl %08X:%08X\n", easeg, eaaddr); + temp64 = geteaq(); if (abrt) return 1; + if (fplog) pclog(" %f %08X %08X\n", (double)temp64, readmeml(easeg,eaaddr), readmeml(easeg,eaaddr+4)); + x87_push((double)temp64); + ST_i64[TOP] = temp64; + tag[TOP] |= TAG_UINT64; + + CLOCK_CYCLES(10); + return 0; +} + +static int FBSTP_a16(uint32_t fetchdat) +{ + double tempd; + int c; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FBSTP %08X:%08X\n", easeg, eaaddr); + tempd = ST(0); + if (tempd < 0.0) + tempd = -tempd; + for (c = 0; c < 9; c++) + { + uint8_t tempc = (uint8_t)floor(fmod(tempd, 10.0)); + tempd -= floor(fmod(tempd, 10.0)); + tempd /= 10.0; + tempc |= ((uint8_t)floor(fmod(tempd, 10.0))) << 4; + tempd -= floor(fmod(tempd, 10.0)); + tempd /= 10.0; + writememb(easeg, eaaddr + c, tempc); + } + tempc = (uint8_t)floor(fmod(tempd, 10.0)); + if (ST(0) < 0.0) tempc |= 0x80; + writememb(easeg, eaaddr + 9, tempc); if (abrt) return 1; + x87_pop(); + return 0; +} +static int FBSTP_a32(uint32_t fetchdat) +{ + double tempd; + int c; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FBSTP %08X:%08X\n", easeg, eaaddr); + tempd = ST(0); + if (tempd < 0.0) + tempd = -tempd; + for (c = 0; c < 9; c++) + { + uint8_t tempc = (uint8_t)floor(fmod(tempd, 10.0)); + tempd -= floor(fmod(tempd, 10.0)); + tempd /= 10.0; + tempc |= ((uint8_t)floor(fmod(tempd, 10.0))) << 4; + tempd -= floor(fmod(tempd, 10.0)); + tempd /= 10.0; + writememb(easeg, eaaddr + c, tempc); + } + tempc = (uint8_t)floor(fmod(tempd, 10.0)); + if (ST(0) < 0.0) tempc |= 0x80; + writememb(easeg, eaaddr + 9, tempc); if (abrt) return 1; + x87_pop(); + return 0; +} + +static int FISTPiq_a16(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FISTPl %08X:%08X\n", easeg, eaaddr); + if (tag[TOP] & TAG_UINT64) + temp64 = ST_i64[TOP]; + else + temp64 = x87_fround(ST(0)); + seteaq(temp64); if (abrt) return 1; + x87_pop(); + CLOCK_CYCLES(29); + return 0; +} +static int FISTPiq_a32(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FISTPl %08X:%08X\n", easeg, eaaddr); + if (tag[TOP] & TAG_UINT64) + temp64 = ST_i64[TOP]; + else + temp64 = x87_fround(ST(0)); + seteaq(temp64); if (abrt) return 1; + x87_pop(); + CLOCK_CYCLES(29); + return 0; +} + +static int opFILDil_a16(uint32_t fetchdat) +{ + int32_t templ; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FILDs %08X:%08X\n", easeg, eaaddr); + templ = geteal(); if (abrt) return 1; + if (fplog) pclog(" %f %08X %i\n", (double)templ, templ, templ); + x87_push((double)templ); + CLOCK_CYCLES(9); + return 0; +} +static int opFILDil_a32(uint32_t fetchdat) +{ + int32_t templ; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FILDs %08X:%08X\n", easeg, eaaddr); + templ = geteal(); if (abrt) return 1; + if (fplog) pclog(" %f %08X %i\n", (double)templ, templ, templ); + x87_push((double)templ); + CLOCK_CYCLES(9); + return 0; +} + +static int opFISTil_a16(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FISTs %08X:%08X\n", easeg, eaaddr); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 2147483647 || temp64 < -2147483647) + fatal("FISTl out of range! %i\n", temp64);*/ + seteal((int32_t)temp64); + CLOCK_CYCLES(28); + return abrt; +} +static int opFISTil_a32(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FISTs %08X:%08X\n", easeg, eaaddr); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 2147483647 || temp64 < -2147483647) + fatal("FISTl out of range! %i\n", temp64);*/ + seteal((int32_t)temp64); + CLOCK_CYCLES(28); + return abrt; +} + +static int opFISTPil_a16(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FISTs %08X:%08X\n", easeg, eaaddr); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 2147483647 || temp64 < -2147483647) + fatal("FISTl out of range! %i\n", temp64);*/ + seteal((int32_t)temp64); if (abrt) return 1; + x87_pop(); + CLOCK_CYCLES(28); + return 0; +} +static int opFISTPil_a32(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FISTs %08X:%08X\n", easeg, eaaddr); + temp64 = x87_fround(ST(0)); +/* if (temp64 > 2147483647 || temp64 < -2147483647) + fatal("FISTl out of range! %i\n", temp64);*/ + seteal((int32_t)temp64); if (abrt) return 1; + x87_pop(); + CLOCK_CYCLES(28); + return 0; +} + +static int opFLDe_a16(uint32_t fetchdat) +{ + double t; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FLDe %08X:%08X\n", easeg, eaaddr); + t=x87_ld80(); if (abrt) return 1; + if (fplog) pclog(" %f\n", t); + x87_push(t); + CLOCK_CYCLES(6); + return 0; +} +static int opFLDe_a32(uint32_t fetchdat) +{ + double t; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FLDe %08X:%08X\n", easeg, eaaddr); + t=x87_ld80(); if (abrt) return 1; + if (fplog) pclog(" %f\n", t); + x87_push(t); + CLOCK_CYCLES(6); + return 0; +} + +static int opFSTPe_a16(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FSTPe %08X:%08X\n", easeg, eaaddr); + x87_st80(ST(0)); if (abrt) return 1; + x87_pop(); + CLOCK_CYCLES(6); + return 0; +} +static int opFSTPe_a32(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FSTPe %08X:%08X\n", easeg, eaaddr); + x87_st80(ST(0)); if (abrt) return 1; + x87_pop(); + CLOCK_CYCLES(6); + return 0; +} + +static int opFLDd_a16(uint32_t fetchdat) +{ + x87_td t; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FLDd %08X:%08X\n", easeg, eaaddr); + t.i = geteaq(); if (abrt) return 1; + if (fplog) pclog(" %f\n", t.d); + x87_push(t.d); + CLOCK_CYCLES(3); + return 0; +} +static int opFLDd_a32(uint32_t fetchdat) +{ + x87_td t; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FLDd %08X:%08X\n", easeg, eaaddr); + t.i = geteaq(); if (abrt) return 1; + if (fplog) pclog(" %f\n", t.d); + x87_push(t.d); + CLOCK_CYCLES(3); + return 0; +} + +static int opFSTd_a16(uint32_t fetchdat) +{ + x87_td t; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FSTd %08X:%08X\n", easeg, eaaddr); + t.d = ST(0); + seteaq(t.i); + CLOCK_CYCLES(8); + return abrt; +} +static int opFSTd_a32(uint32_t fetchdat) +{ + x87_td t; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FSTd %08X:%08X\n", easeg, eaaddr); + t.d = ST(0); + seteaq(t.i); + CLOCK_CYCLES(8); + return abrt; +} + +static int opFSTPd_a16(uint32_t fetchdat) +{ + x87_td t; + FP_ENTER(); + fetch_ea_16(fetchdat); + CHECK_WRITE(ea_seg, eaaddr, eaaddr + 7); + if (fplog) pclog("FSTd %08X:%08X\n", easeg, eaaddr); + t.d = ST(0); + seteaq(t.i); if (abrt) return 1; + x87_pop(); + CLOCK_CYCLES(8); + return 0; +} +static int opFSTPd_a32(uint32_t fetchdat) +{ + x87_td t; + FP_ENTER(); + fetch_ea_32(fetchdat); + CHECK_WRITE(ea_seg, eaaddr, eaaddr + 7); + if (fplog) pclog("FSTd %08X:%08X\n", easeg, eaaddr); + t.d = ST(0); + seteaq(t.i); if (abrt) return 1; + x87_pop(); + CLOCK_CYCLES(8); + return 0; +} + +static int opFLDs_a16(uint32_t fetchdat) +{ + x87_ts ts; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FLDs %08X:%08X\n", easeg, eaaddr); + ts.i = geteal(); if (abrt) return 1; + if (fplog) pclog(" %f\n", ts.s); + x87_push((double)ts.s); + CLOCK_CYCLES(3); + return 0; +} +static int opFLDs_a32(uint32_t fetchdat) +{ + x87_ts ts; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FLDs %08X:%08X\n", easeg, eaaddr); + ts.i = geteal(); if (abrt) return 1; + if (fplog) pclog(" %f\n", ts.s); + x87_push((double)ts.s); + CLOCK_CYCLES(3); + return 0; +} + +static int opFSTs_a16(uint32_t fetchdat) +{ + x87_ts ts; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FSTs %08X:%08X\n", easeg, eaaddr); + ts.s = (float)ST(0); + seteal(ts.i); + CLOCK_CYCLES(7); + return abrt; +} +static int opFSTs_a32(uint32_t fetchdat) +{ + x87_ts ts; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FSTs %08X:%08X\n", easeg, eaaddr); + ts.s = (float)ST(0); + seteal(ts.i); + CLOCK_CYCLES(7); + return abrt; +} + +static int opFSTPs_a16(uint32_t fetchdat) +{ + x87_ts ts; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FSTs %08X:%08X\n", easeg, eaaddr); + ts.s = (float)ST(0); + seteal(ts.i); if (abrt) return 1; + x87_pop(); + CLOCK_CYCLES(7); + return 0; +} +static int opFSTPs_a32(uint32_t fetchdat) +{ + x87_ts ts; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FSTs %08X:%08X\n", easeg, eaaddr); + ts.s = (float)ST(0); + seteal(ts.i); if (abrt) return 1; + x87_pop(); + CLOCK_CYCLES(7); + return 0; +} diff --git a/src/x87_ops_misc.h b/src/x87_ops_misc.h new file mode 100644 index 000000000..401e84cc6 --- /dev/null +++ b/src/x87_ops_misc.h @@ -0,0 +1,828 @@ +static int opFSTSW_AX(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSTSW\n"); + AX = npxs; + CLOCK_CYCLES(3); + return 0; +} + + + +static int opFNOP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + CLOCK_CYCLES(4); + return 0; +} + +static int opFCLEX(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + npxs &= 0xff00; + CLOCK_CYCLES(4); + return 0; +} + +static int opFINIT(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + npxc = 0x37F; + npxs = 0; + *(uint64_t *)tag = 0x0303030303030303ll; + TOP = 0; + CLOCK_CYCLES(17); + return 0; +} + + +static int opFFREE(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FFREE\n"); + tag[(TOP + fetchdat) & 7] = 3; + CLOCK_CYCLES(3); + return 0; +} + +static int opFST(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FST\n"); + ST(fetchdat & 7) = ST(0); + tag[(TOP + fetchdat) & 7] = tag[TOP & 7]; + CLOCK_CYCLES(3); + return 0; +} + +static int opFSTP(uint32_t fetchdat) +{ + int temp; + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSTP\n"); + ST(fetchdat & 7) = ST(0); + tag[(TOP + fetchdat) & 7] = tag[TOP & 7]; + x87_pop(); + CLOCK_CYCLES(3); + return 0; +} + + + + +static int FSTOR() +{ + FP_ENTER(); + switch ((cr0 & 1) | (op32 & 0x100)) + { + case 0x000: /*16-bit real mode*/ + case 0x001: /*16-bit protected mode*/ + npxc = readmemw(easeg, eaaddr); + npxs = readmemw(easeg, eaaddr+2); + x87_settag(readmemw(easeg, eaaddr+4)); + TOP = (npxs >> 11) & 7; + eaaddr += 14; + break; + case 0x100: /*32-bit real mode*/ + case 0x101: /*32-bit protected mode*/ + npxc = readmemw(easeg, eaaddr); + npxs = readmemw(easeg, eaaddr+4); + x87_settag(readmemw(easeg, eaaddr+8)); + TOP = (npxs >> 11) & 7; + eaaddr += 28; + break; + } + x87_ldmmx(&MM[0]); x87_ld_frstor(0); eaaddr += 10; + x87_ldmmx(&MM[1]); x87_ld_frstor(1); eaaddr += 10; + x87_ldmmx(&MM[2]); x87_ld_frstor(2); eaaddr += 10; + x87_ldmmx(&MM[3]); x87_ld_frstor(3); eaaddr += 10; + x87_ldmmx(&MM[4]); x87_ld_frstor(4); eaaddr += 10; + x87_ldmmx(&MM[5]); x87_ld_frstor(5); eaaddr += 10; + x87_ldmmx(&MM[6]); x87_ld_frstor(6); eaaddr += 10; + x87_ldmmx(&MM[7]); x87_ld_frstor(7); + + ismmx = 0; + /*Horrible hack, but as PCem doesn't keep the FPU stack in 80-bit precision at all times + something like this is needed*/ + if (MM[0].w[4] == 0xffff && MM[1].w[4] == 0xffff && MM[2].w[4] == 0xffff && MM[3].w[4] == 0xffff && + MM[4].w[4] == 0xffff && MM[5].w[4] == 0xffff && MM[6].w[4] == 0xffff && MM[7].w[4] == 0xffff && + !TOP && !(*(uint64_t *)tag)) + ismmx = 1; + + CLOCK_CYCLES((cr0 & 1) ? 34 : 44); + if (fplog) pclog("FRSTOR %08X:%08X %i %i %04X\n", easeg, eaaddr, ismmx, TOP, x87_gettag()); + return abrt; +} +static int opFSTOR_a16(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_16(fetchdat); + FSTOR(); + return abrt; +} +static int opFSTOR_a32(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_32(fetchdat); + FSTOR(); + return abrt; +} + +static int FSAVE() +{ + FP_ENTER(); + if (fplog) pclog("FSAVE %08X:%08X %i\n", easeg, eaaddr, ismmx); + npxs = (npxs & ~(7 << 11)) | (TOP << 11); + + switch ((cr0&1)|(op32&0x100)) + { + case 0x000: /*16-bit real mode*/ + writememw(easeg,eaaddr,npxc); + writememw(easeg,eaaddr+2,npxs); + writememw(easeg,eaaddr+4,x87_gettag()); + writememw(easeg,eaaddr+6,x87_pc_off); + writememw(easeg,eaaddr+10,x87_op_off); + eaaddr+=14; + if (ismmx) + { + x87_stmmx(MM[0]); eaaddr+=10; + x87_stmmx(MM[1]); eaaddr+=10; + x87_stmmx(MM[2]); eaaddr+=10; + x87_stmmx(MM[3]); eaaddr+=10; + x87_stmmx(MM[4]); eaaddr+=10; + x87_stmmx(MM[5]); eaaddr+=10; + x87_stmmx(MM[6]); eaaddr+=10; + x87_stmmx(MM[7]); + } + else + { + x87_st_fsave(0); eaaddr+=10; + x87_st_fsave(1); eaaddr+=10; + x87_st_fsave(2); eaaddr+=10; + x87_st_fsave(3); eaaddr+=10; + x87_st_fsave(4); eaaddr+=10; + x87_st_fsave(5); eaaddr+=10; + x87_st_fsave(6); eaaddr+=10; + x87_st_fsave(7); + } + break; + case 0x001: /*16-bit protected mode*/ + writememw(easeg,eaaddr,npxc); + writememw(easeg,eaaddr+2,npxs); + writememw(easeg,eaaddr+4,x87_gettag()); + writememw(easeg,eaaddr+6,x87_pc_off); + writememw(easeg,eaaddr+8,x87_pc_seg); + writememw(easeg,eaaddr+10,x87_op_off); + writememw(easeg,eaaddr+12,x87_op_seg); + eaaddr+=14; + if (ismmx) + { + x87_stmmx(MM[0]); eaaddr+=10; + x87_stmmx(MM[1]); eaaddr+=10; + x87_stmmx(MM[2]); eaaddr+=10; + x87_stmmx(MM[3]); eaaddr+=10; + x87_stmmx(MM[4]); eaaddr+=10; + x87_stmmx(MM[5]); eaaddr+=10; + x87_stmmx(MM[6]); eaaddr+=10; + x87_stmmx(MM[7]); + } + else + { + x87_st_fsave(0); eaaddr+=10; + x87_st_fsave(1); eaaddr+=10; + x87_st_fsave(2); eaaddr+=10; + x87_st_fsave(3); eaaddr+=10; + x87_st_fsave(4); eaaddr+=10; + x87_st_fsave(5); eaaddr+=10; + x87_st_fsave(6); eaaddr+=10; + x87_st_fsave(7); + } + break; + case 0x100: /*32-bit real mode*/ + writememw(easeg,eaaddr,npxc); + writememw(easeg,eaaddr+4,npxs); + writememw(easeg,eaaddr+8,x87_gettag()); + writememw(easeg,eaaddr+12,x87_pc_off); + writememw(easeg,eaaddr+20,x87_op_off); + writememl(easeg,eaaddr+24,(x87_op_off>>16)<<12); + eaaddr+=28; + if (ismmx) + { + x87_stmmx(MM[0]); eaaddr+=10; + x87_stmmx(MM[1]); eaaddr+=10; + x87_stmmx(MM[2]); eaaddr+=10; + x87_stmmx(MM[3]); eaaddr+=10; + x87_stmmx(MM[4]); eaaddr+=10; + x87_stmmx(MM[5]); eaaddr+=10; + x87_stmmx(MM[6]); eaaddr+=10; + x87_stmmx(MM[7]); + } + else + { + x87_st_fsave(0); eaaddr+=10; + x87_st_fsave(1); eaaddr+=10; + x87_st_fsave(2); eaaddr+=10; + x87_st_fsave(3); eaaddr+=10; + x87_st_fsave(4); eaaddr+=10; + x87_st_fsave(5); eaaddr+=10; + x87_st_fsave(6); eaaddr+=10; + x87_st_fsave(7); + } + break; + case 0x101: /*32-bit protected mode*/ + writememw(easeg,eaaddr,npxc); + writememw(easeg,eaaddr+4,npxs); + writememw(easeg,eaaddr+8,x87_gettag()); + writememl(easeg,eaaddr+12,x87_pc_off); + writememl(easeg,eaaddr+16,x87_pc_seg); + writememl(easeg,eaaddr+20,x87_op_off); + writememl(easeg,eaaddr+24,x87_op_seg); + eaaddr+=28; + if (ismmx) + { + x87_stmmx(MM[0]); eaaddr+=10; + x87_stmmx(MM[1]); eaaddr+=10; + x87_stmmx(MM[2]); eaaddr+=10; + x87_stmmx(MM[3]); eaaddr+=10; + x87_stmmx(MM[4]); eaaddr+=10; + x87_stmmx(MM[5]); eaaddr+=10; + x87_stmmx(MM[6]); eaaddr+=10; + x87_stmmx(MM[7]); + } + else + { + x87_st_fsave(0); eaaddr+=10; + x87_st_fsave(1); eaaddr+=10; + x87_st_fsave(2); eaaddr+=10; + x87_st_fsave(3); eaaddr+=10; + x87_st_fsave(4); eaaddr+=10; + x87_st_fsave(5); eaaddr+=10; + x87_st_fsave(6); eaaddr+=10; + x87_st_fsave(7); + } + break; + } + CLOCK_CYCLES((cr0 & 1) ? 56 : 67); + return abrt; +} +static int opFSAVE_a16(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_16(fetchdat); + FSAVE(); + return abrt; +} +static int opFSAVE_a32(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_32(fetchdat); + FSAVE(); + return abrt; +} + +static int opFSTSW_a16(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FSTSW %08X:%08X\n", easeg, eaaddr); + seteaw((npxs & 0xC7FF) | (TOP << 11)); + CLOCK_CYCLES(3); + return abrt; +} +static int opFSTSW_a32(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FSTSW %08X:%08X\n", easeg, eaaddr); + seteaw((npxs & 0xC7FF) | (TOP << 11)); + CLOCK_CYCLES(3); + return abrt; +} + + +static int opFLD(uint32_t fetchdat) +{ + int old_tag; + uint64_t old_i64; + + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FLD %f\n", ST(fetchdat & 7)); + old_tag = tag[(TOP + fetchdat) & 7]; + old_i64 = ST_i64[(TOP + fetchdat) & 7]; + x87_push(ST(fetchdat&7)); + tag[TOP] = old_tag; + ST_i64[TOP] = old_i64; + CLOCK_CYCLES(4); + return 0; +} + +static int opFXCH(uint32_t fetchdat) +{ + double td; + uint8_t old_tag; + uint64_t old_i64; + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FXCH\n"); + td = ST(0); + ST(0) = ST(fetchdat&7); + ST(fetchdat&7) = td; + old_tag = tag[TOP]; + tag[TOP] = tag[(TOP + fetchdat) & 7]; + tag[(TOP + fetchdat) & 7] = old_tag; + old_i64 = ST_i64[TOP]; + ST_i64[TOP] = ST_i64[(TOP + fetchdat) & 7]; + ST_i64[(TOP + fetchdat) & 7] = old_i64; + + CLOCK_CYCLES(4); + return 0; +} + +static int opFCHS(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FCHS\n"); + ST(0) = -ST(0); + tag[TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(6); + return 0; +} + +static int opFABS(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FABS %f\n", ST(0)); + ST(0) = fabs(ST(0)); + tag[TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(3); + return 0; +} + +static int opFTST(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FTST\n"); + npxs &= ~(C0|C2|C3); + if (ST(0) == 0.0) npxs |= C3; + else if (ST(0) < 0.0) npxs |= C0; + CLOCK_CYCLES(4); + return 0; +} + +static int opFXAM(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FXAM %i %f\n", tag[TOP&7], ST(0)); + npxs &= ~(C0|C1|C2|C3); + if (tag[TOP&7] == 3) npxs |= (C0|C3); + else if (ST(0) == 0.0) npxs |= C3; + else npxs |= C2; + if (ST(0) < 0.0) npxs |= C1; + CLOCK_CYCLES(8); + return 0; +} + +static int opFLD1(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FLD1\n"); + x87_push(1.0); + CLOCK_CYCLES(4); + return 0; +} + +static int opFLDL2T(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FLDL2T\n"); + x87_push(3.3219280948873623); + CLOCK_CYCLES(8); + return 0; +} + +static int opFLDL2E(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FLDL2E\n"); + x87_push(1.4426950408889634); + CLOCK_CYCLES(8); + return 0; +} + +static int opFLDPI(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FLDPI\n"); + x87_push(3.141592653589793); + CLOCK_CYCLES(8); + return 0; +} + +static int opFLDEG2(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FLDEG2\n"); + x87_push(0.3010299956639812); + CLOCK_CYCLES(8); + return 0; +} + +static int opFLDLN2(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FLDLN2\n"); + x87_push(0.693147180559945); + CLOCK_CYCLES(8); + return 0; +} + +static int opFLDZ(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FLDZ\n"); + x87_push(0.0); + tag[TOP&7] = 1; + CLOCK_CYCLES(4); + return 0; +} + +static int opF2XM1(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("F2XM1\n"); + ST(0) = pow(2.0, ST(0)) - 1.0; + tag[TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(200); + return 0; +} + +static int opFYL2X(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FYL2X\n"); + ST(1) = ST(1) * (log(ST(0)) / log(2.0)); + tag[(TOP + 1) & 7] &= ~TAG_UINT64; + x87_pop(); + CLOCK_CYCLES(250); + return 0; +} + +static int opFYL2XP1(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FYL2XP1\n"); + ST(1) = ST(1) * (log(ST(0)+1.0) / log(2.0)); + tag[(TOP + 1) & 7] &= ~TAG_UINT64; + x87_pop(); + CLOCK_CYCLES(250); + return 0; +} + +static int opFPTAN(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FPTAN\n"); + ST(0) = tan(ST(0)); + tag[TOP] &= ~TAG_UINT64; + x87_push(1.0); + npxs &= ~C2; + CLOCK_CYCLES(235); + return 0; +} + +static int opFPATAN(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FPATAN\n"); + ST(1) = atan2(ST(1), ST(0)); + tag[(TOP + 1) & 7] &= ~TAG_UINT64; + x87_pop(); + CLOCK_CYCLES(250); + return 0; +} + +static int opFDECSTP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FDECSTP\n"); + TOP = (TOP - 1) & 7; + CLOCK_CYCLES(4); + return 0; +} + +static int opFINCSTP(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FDECSTP\n"); + TOP = (TOP + 1) & 7; + CLOCK_CYCLES(4); + return 0; +} + +static int opFPREM(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FPREM %f %f ", ST(0), ST(1)); + temp64 = (int64_t)(ST(0) / ST(1)); + ST(0) = ST(0) - (ST(1) * (double)temp64); + tag[TOP] &= ~TAG_UINT64; + if (fplog) pclog("%f\n", ST(0)); + npxs &= ~(C0|C1|C2|C3); + if (temp64 & 4) npxs|=C0; + if (temp64 & 2) npxs|=C3; + if (temp64 & 1) npxs|=C1; + CLOCK_CYCLES(100); + return 0; +} +static int opFPREM1(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FPREM1 %f %f ", ST(0), ST(1)); + temp64 = (int64_t)(ST(0) / ST(1)); + ST(0) = ST(0) - (ST(1) * (double)temp64); + tag[TOP] &= ~TAG_UINT64; + if (fplog) pclog("%f\n", ST(0)); + npxs &= ~(C0|C1|C2|C3); + if (temp64 & 4) npxs|=C0; + if (temp64 & 2) npxs|=C3; + if (temp64 & 1) npxs|=C1; + CLOCK_CYCLES(100); + return 0; +} + +static int opFSQRT(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSQRT\n"); + ST(0) = sqrt(ST(0)); + tag[TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(83); + return 0; +} + +static int opFSINCOS(uint32_t fetchdat) +{ + double td; + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSINCOS\n"); + td = ST(0); + ST(0) = sin(td); + tag[TOP] &= ~TAG_UINT64; + x87_push(cos(td)); + npxs &= ~C2; + CLOCK_CYCLES(330); + return 0; +} + +static int opFRNDINT(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FRNDINT %g ", ST(0)); + ST(0) = (double)x87_fround(ST(0)); + tag[TOP] &= ~TAG_UINT64; + if (fplog) pclog("%g\n", ST(0)); + CLOCK_CYCLES(21); + return 0; +} + +static int opFSCALE(uint32_t fetchdat) +{ + int64_t temp64; + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSCALE\n"); + temp64 = (int64_t)ST(1); + ST(0) = ST(0) * pow(2.0, (double)temp64); + tag[TOP] &= ~TAG_UINT64; + CLOCK_CYCLES(30); + return 0; +} + +static int opFSIN(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FSIN\n"); + ST(0) = sin(ST(0)); + tag[TOP] &= ~TAG_UINT64; + npxs &= ~C2; + CLOCK_CYCLES(300); + return 0; +} + +static int opFCOS(uint32_t fetchdat) +{ + FP_ENTER(); + cpu_state.pc++; + if (fplog) pclog("FCOS\n"); + ST(0) = cos(ST(0)); + tag[TOP] &= ~TAG_UINT64; + npxs &= ~C2; + CLOCK_CYCLES(300); + return 0; +} + + +static int FLDENV() +{ + FP_ENTER(); + if (fplog) pclog("FLDENV %08X:%08X\n", easeg, eaaddr); + switch ((cr0 & 1) | (op32 & 0x100)) + { + case 0x000: /*16-bit real mode*/ + case 0x001: /*16-bit protected mode*/ + npxc = readmemw(easeg, eaaddr); + npxs = readmemw(easeg, eaaddr+2); + x87_settag(readmemw(easeg, eaaddr+4)); + TOP = (npxs >> 11) & 7; + break; + case 0x100: /*32-bit real mode*/ + case 0x101: /*32-bit protected mode*/ + npxc = readmemw(easeg, eaaddr); + npxs = readmemw(easeg, eaaddr+4); + x87_settag(readmemw(easeg, eaaddr+8)); + TOP = (npxs >> 11) & 7; + break; + } + CLOCK_CYCLES((cr0 & 1) ? 34 : 44); + return abrt; +} + +static int opFLDENV_a16(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_16(fetchdat); + FLDENV(); + return abrt; +} +static int opFLDENV_a32(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_32(fetchdat); + FLDENV(); + return abrt; +} + +static int opFLDCW_a16(uint32_t fetchdat) +{ + uint16_t tempw; + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FLDCW %08X:%08X\n", easeg, eaaddr); + tempw = geteaw(); + if (abrt) return 1; + npxc = tempw; + CLOCK_CYCLES(4); + return 0; +} +static int opFLDCW_a32(uint32_t fetchdat) +{ + uint16_t tempw; + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FLDCW %08X:%08X\n", easeg, eaaddr); + tempw = geteaw(); + if (abrt) return 1; + npxc = tempw; + CLOCK_CYCLES(4); + return 0; +} + +static int FSTENV() +{ + FP_ENTER(); + if (fplog) pclog("FSTENV %08X:%08X\n", easeg, eaaddr); + switch ((cr0 & 1) | (op32 & 0x100)) + { + case 0x000: /*16-bit real mode*/ + writememw(easeg,eaaddr,npxc); + writememw(easeg,eaaddr+2,npxs); + writememw(easeg,eaaddr+4,x87_gettag()); + writememw(easeg,eaaddr+6,x87_pc_off); + writememw(easeg,eaaddr+10,x87_op_off); + break; + case 0x001: /*16-bit protected mode*/ + writememw(easeg,eaaddr,npxc); + writememw(easeg,eaaddr+2,npxs); + writememw(easeg,eaaddr+4,x87_gettag()); + writememw(easeg,eaaddr+6,x87_pc_off); + writememw(easeg,eaaddr+8,x87_pc_seg); + writememw(easeg,eaaddr+10,x87_op_off); + writememw(easeg,eaaddr+12,x87_op_seg); + break; + case 0x100: /*32-bit real mode*/ + writememw(easeg,eaaddr,npxc); + writememw(easeg,eaaddr+4,npxs); + writememw(easeg,eaaddr+8,x87_gettag()); + writememw(easeg,eaaddr+12,x87_pc_off); + writememw(easeg,eaaddr+20,x87_op_off); + writememl(easeg,eaaddr+24,(x87_op_off>>16)<<12); + break; + case 0x101: /*32-bit protected mode*/ + writememw(easeg,eaaddr,npxc); + writememw(easeg,eaaddr+4,npxs); + writememw(easeg,eaaddr+8,x87_gettag()); + writememl(easeg,eaaddr+12,x87_pc_off); + writememl(easeg,eaaddr+16,x87_pc_seg); + writememl(easeg,eaaddr+20,x87_op_off); + writememl(easeg,eaaddr+24,x87_op_seg); + break; + } + CLOCK_CYCLES((cr0 & 1) ? 56 : 67); + return abrt; +} + +static int opFSTENV_a16(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_16(fetchdat); + FSTENV(); + return abrt; +} +static int opFSTENV_a32(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_32(fetchdat); + FSTENV(); + return abrt; +} + +static int opFSTCW_a16(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_16(fetchdat); + if (fplog) pclog("FSTCW %08X:%08X\n", easeg, eaaddr); + seteaw(npxc); + CLOCK_CYCLES(3); + return abrt; +} +static int opFSTCW_a32(uint32_t fetchdat) +{ + FP_ENTER(); + fetch_ea_32(fetchdat); + if (fplog) pclog("FSTCW %08X:%08X\n", easeg, eaaddr); + seteaw(npxc); + CLOCK_CYCLES(3); + return abrt; +} + +#define opFCMOV(condition) \ + static int opFCMOV ## condition(uint32_t fetchdat) \ + { \ + FP_ENTER(); \ + cpu_state.pc++; \ + if (fplog) pclog("FCMOV %f\n", ST(fetchdat & 7)); \ + if (cond_ ## condition) \ + { \ + tag[TOP] = tag[(TOP + fetchdat) & 7]; \ + ST_i64[TOP] = ST_i64[(TOP + fetchdat) & 7]; \ + ST(0) = ST(fetchdat & 7); \ + } \ + CLOCK_CYCLES(4); \ + return 0; \ + } + +#define cond_U ( PF_SET()) +#define cond_NU (!PF_SET()) + +opFCMOV(B) +opFCMOV(E) +opFCMOV(BE) +opFCMOV(U) +opFCMOV(NB) +opFCMOV(NE) +opFCMOV(NBE) +opFCMOV(NU) diff --git a/src/xtide.c b/src/xtide.c new file mode 100644 index 000000000..5694cf78b --- /dev/null +++ b/src/xtide.c @@ -0,0 +1,58 @@ +#include "ibm.h" + +#include "io.h" +#include "ide.h" +#include "xtide.h" + +uint8_t xtide_high; + +void xtide_write(uint16_t port, uint8_t val, void *priv) +{ + switch (port & 0xf) + { + case 0x0: + writeidew(0, val | (xtide_high << 8)); + return; + + case 0x1: case 0x2: case 0x3: + case 0x4: case 0x5: case 0x6: case 0x7: + writeide(0, (port & 0xf) | 0x1f0, val); + return; + + case 0x8: + xtide_high = val; + return; + + case 0xe: + writeide(0, 0x3f6, val); + return; + } +} + +uint8_t xtide_read(uint16_t port, void *priv) +{ + uint16_t tempw; + switch (port & 0xf) + { + case 0x0: + tempw = readidew(0); + xtide_high = tempw >> 8; + return tempw & 0xff; + + case 0x1: case 0x2: case 0x3: + case 0x4: case 0x5: case 0x6: case 0x7: + return readide(0, (port & 0xf) | 0x1f0); + + case 0x8: + return xtide_high; + + case 0xe: + return readide(0, 0x3f6); + } +} + +void xtide_init() +{ + ide_init(); + io_sethandler(0x0300, 0x0010, xtide_read, NULL, NULL, xtide_write, NULL, NULL, NULL); +} diff --git a/src/xtide.h b/src/xtide.h new file mode 100644 index 000000000..36e01c0a4 --- /dev/null +++ b/src/xtide.h @@ -0,0 +1 @@ +void xtide_init();